昨天写了一篇关于导航栏的文章,由于时间太晚了没细弄,今天调整了一下主要有一下功能:
- 导航栏布局的自定义
- 使用ViewPager2默认样式
- 使用默认自定义样式(带角标的实现)
- 使用自定义样式
- TabLayout 导航栏在底部或者顶部
- 导航栏高度的调整
- 一些功能的延伸
效果图:
  
核心代码
其中的TableAndViewPage类是传入数据的bean,LogUtil类是记录日志的,替换成自己的即可。
主要方法说明:
- TabLayout + ViewPager2 + Fragment 实现
- 默认的加载方式是自定义的布局
- setData() 设置数据
- setLoadTypeToDefault() 设置加载方式为默认
- setTabCustomLayout() 设置自定义布局
- setTabHeight() 设置tab的高度
- isRoll() 导航条放置在顶部,默认在底部
- setJiaoBiaoNO() 设置角标
- setOffscreenPageLimit() 设置预加载fragment的数量,默认懒加载
SelfViewPageFragmentControl
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.pksh.tools.R;
import com.pksh.tools.style.moudle.TableAndViewPage;
import com.pksh.tools.utils.log.LogUtil;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Target;
import java.util.List;
public class SelfViewPageFragmentControl extends RelativeLayout{
private static final String TAG = "底部导航栏";
private final ViewPager2 viewPager2;
private final TabLayout tabLayout;
public static final int TAB_LOAD_TYPE_DEFAULT = 0;
public static final int TAB_LOAD_TYPE_DEFAULT_CUSTOM = 1;
public static final int TAB_LOAD_TYPE_CUSTOM = 2;
@IntDef(value = {TAB_LOAD_TYPE_DEFAULT, TAB_LOAD_TYPE_DEFAULT_CUSTOM, TAB_LOAD_TYPE_CUSTOM})
@Inherited
@Target({ElementType.PARAMETER,ElementType.FIELD})
public @interface LoadType { }
private @LoadType int loadType = TAB_LOAD_TYPE_DEFAULT_CUSTOM;
private List<TableAndViewPage> data;
private boolean isTop = false;
private boolean isRoll = false;
private int tabHeight = 0;
private int oldId;
private TabLayoutLoadCustomView tabLayoutLoadCustomView;
public SelfViewPageFragmentControl(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.slef_view_page_fragment, this);
viewPager2 = findViewById(R.id.view_pager);
tabLayout = findViewById(R.id.tab_layout);
}
public void build(){
if (isTop) {
RelativeLayout.LayoutParams layoutParams = (LayoutParams) viewPager2.getLayoutParams();
layoutParams.addRule(RelativeLayout.BELOW,R.id.tab_layout);
viewPager2.setLayoutParams(layoutParams);
if (tabHeight != 0) {
RelativeLayout.LayoutParams layoutParams1 = new LayoutParams(LayoutParams.MATCH_PARENT,tabHeight);
tabLayout.setLayoutParams(layoutParams1);
}
} else {
RelativeLayout.LayoutParams layoutParams = (LayoutParams) viewPager2.getLayoutParams();
layoutParams.addRule(RelativeLayout.ABOVE,R.id.tab_layout);
viewPager2.setLayoutParams(layoutParams);
RelativeLayout.LayoutParams layoutParams1;
if (tabHeight != 0) layoutParams1 = new LayoutParams(LayoutParams.MATCH_PARENT,tabHeight);
else layoutParams1 = (LayoutParams) tabLayout.getLayoutParams();
layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
tabLayout.setLayoutParams(layoutParams1);
}
if (isRoll) tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
if (loadType != TAB_LOAD_TYPE_DEFAULT) {
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
int selectId = tabLayout.getSelectedTabPosition();
oldId = selectId;
if (loadType == TAB_LOAD_TYPE_DEFAULT_CUSTOM &&
data.get(selectId).getIconSelected() != 0 &&
tab.getCustomView() != null) {
ImageView imageView = tab.getCustomView().findViewById(R.id.imageview);
imageView.setImageResource(data.get(selectId).getIconSelected());
return;
}
if (loadType == TAB_LOAD_TYPE_CUSTOM) {
View view = tabLayoutLoadCustomView.onTabSelected(tab, selectId);
if (view != null) tab.setCustomView(view);
return;
}
LogUtil.e(TAG,"未配置选择后的图片或者当前tab选项卡未配置自定义布局,当前加载方式:"+loadType);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
if (loadType == TAB_LOAD_TYPE_DEFAULT_CUSTOM &&
data.get(oldId).getIcon() != 0 &&
tab.getCustomView() != null) {
ImageView imageView = tab.getCustomView().findViewById(R.id.imageview);
imageView.setImageResource(data.get(oldId).getIcon());
return;
}
if (loadType == TAB_LOAD_TYPE_CUSTOM) {
View view = tabLayoutLoadCustomView.onTabUnselected(tab, oldId);
if (view != null) tab.setCustomView(view);
return;
}
LogUtil.e(TAG,"未配置未选中的图片或者当前tab选项卡未配置自定义布局,当前加载方式:"+loadType);
}
@Override
public void onTabReselected(TabLayout.Tab tab) {}
});
}
if (data != null) {
AdapterViewPage2 adapterViewPage = new AdapterViewPage2((FragmentActivity) getContext(),data);
viewPager2.setAdapter(adapterViewPage);
new TabLayoutMediator(tabLayout, viewPager2,true,false, (tab, position) -> {
switch (loadType){
case TAB_LOAD_TYPE_DEFAULT:
if (data.get(position).getIcon() != 0) tab.setIcon(data.get(position).getIcon());
tab.setText(data.get(position).getText());
break;
case TAB_LOAD_TYPE_DEFAULT_CUSTOM:
tab.setCustomView(makeTabView(position));
break;
case TAB_LOAD_TYPE_CUSTOM:
View view = tabLayoutLoadCustomView.loadTabLayoutView(tab, position);
if (view != null) tab.setCustomView(view);
break;
}
}).attach();
}
}
private View makeTabView(int position){
@SuppressLint("InflateParams") View tabView = LayoutInflater.from(getContext()).inflate(R.layout.tab_text_icon,null);
TextView textView = tabView.findViewById(R.id.textview);
ImageView imageView = tabView.findViewById(R.id.imageview);
textView.setText(data.get(position).getText());
if (data.get(position).getIcon() != 0) imageView.setImageResource(data.get(position).getIcon());
return tabView;
}
public interface TabLayoutLoadCustomView {
View loadTabLayoutView(TabLayout.Tab tab, int position);
View onTabSelected(TabLayout.Tab tab, int position);
View onTabUnselected(TabLayout.Tab tab, int position);
}
public SelfViewPageFragmentControl setLoadTypeToDefault(){
loadType = TAB_LOAD_TYPE_DEFAULT;
return this;
}
public void setJiaoBiaoNO(@IntRange(from = 0) int position, int number){
if (position > data.size()-1) {
LogUtil.e(TAG,"角标数字设置失败,TAB下标过大, 最大"+(data.size()-1));
return;
}
if (loadType == TAB_LOAD_TYPE_DEFAULT_CUSTOM) {
TabLayout.Tab tabAt = tabLayout.getTabAt(position);
if (tabAt != null && tabAt.getCustomView() != null) {
RelativeLayout relativeLayout = tabAt.getCustomView().findViewById(R.id.jiao_biao);
if (number < 1) {
relativeLayout.setVisibility(GONE);
return;
}
relativeLayout.setVisibility(VISIBLE);
TextView textView = tabAt.getCustomView().findViewById(R.id.jiao_biao_text);
textView.setText(String.valueOf(number));
return;
}
LogUtil.e(TAG,"角标数字设置失败,当前tab为空或默认布局为空");
}
LogUtil.e(TAG,"角标数字设置失败,当前加载方式不是默认布局");
}
public SelfViewPageFragmentControl setOffscreenPageLimit(@ViewPager2.OffscreenPageLimit int limit){
viewPager2.setOffscreenPageLimit(limit);
return this;
}
public SelfViewPageFragmentControl setData(@NonNull List<TableAndViewPage> data){
this.data = data;
return this;
}
public SelfViewPageFragmentControl isTop(boolean isTop){
this.isTop = isTop;
return this;
}
public SelfViewPageFragmentControl isRoll(boolean isRoll){
this.isRoll = isRoll;
return this;
}
public SelfViewPageFragmentControl setTabHeight(@IntRange(from = 20, to = 100) int height){
this.tabHeight = height;
return this;
}
public SelfViewPageFragmentControl setTabCustomLayout(TabLayoutLoadCustomView tabLayoutLoadCustomView){
this.tabLayoutLoadCustomView = tabLayoutLoadCustomView;
if (tabLayoutLoadCustomView != null) {
this.loadType = TAB_LOAD_TYPE_CUSTOM;
}
return this;
}
}
布局
TestTablayoutActivity 的布局
布局很简单就一个ViewPager2 和一个TabLayout这两个怎么放都可以,在上面代码里调整其布局 slef_view_page_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
app:tabTextColor="#B8B8B8"
app:tabPaddingStart="1dp"
app:tabPaddingEnd="1dp"
app:tabPaddingBottom="1dp"
app:tabPaddingTop="1dp"
app:tabIndicatorHeight="0dp"
app:tabSelectedTextColor="#000000"
app:tabMinWidth="10dp"
app:tabMaxWidth="200dp"
app:tabPadding="0dp"
/>
</RelativeLayout>
默认自定义布局
角标的图片见文章最后附录 tab_text_icon.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/text_view_def"
android:gravity="center">
<RelativeLayout
android:id="@+id/icon"
android:layout_width="30dp"
android:layout_height="30dp">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:padding="2dp"
/>
<RelativeLayout
android:id="@+id/jiao_biao"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_alignParentEnd="true"
android:visibility="gone"
>
<ImageView
android:id="@+id/jiao_biao_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/def_img_jiao_biao"
/>
<TextView
android:id="@+id/jiao_biao_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/text_white_color"
android:ellipsize="end"
android:lines="1"
android:maxLength="2"
android:textSize="@dimen/def_text_small_small_size" />
</RelativeLayout>
</RelativeLayout>
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center"
android:layout_gravity="center"
android:textSize="@dimen/def_text_small_small_size"
android:ellipsize="end"
android:lines="1"
android:text="1258"
/>
</LinearLayout>
Adapter
viewpage2的Adapter
AdapterViewPage2.class
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
import com.pksh.tools.style.moudle.TableAndViewPage;
public class AdapterViewPage2 extends FragmentStateAdapter{
private final List<TableAndViewPage> data;
public AdapterViewPage2(@NonNull FragmentActivity fragmentActivity, List<TableAndViewPage> data) {
super(fragmentActivity);
this.data = data;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return data.get(position).getFragment();
}
@Override
public int getItemCount() {
return data.size();
}
}
数据bean
TableAndViewPage.class
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
public class TableAndViewPage {
private int icon;
private int iconSelected;
private @NonNull String text;
private Fragment fragment;
public TableAndViewPage(@NonNull String text,int icon,int iconSelected,Fragment fragment){
this.fragment = fragment;
this.icon = icon;
this.iconSelected = iconSelected;
this.text = text;
}
public int getIcon() { return icon; }
public void setIcon(int icon) { this.icon = icon; }
public int getIconSelected() { return iconSelected; }
public void setIconSelected(int iconSelected) { this.iconSelected = iconSelected; }
public String getText() { return text; }
public void setText(@NonNull String text) { this.text = text; }
public Fragment getFragment() { return fragment; }
public void setFragment(Fragment fragment) { this.fragment = fragment; }
@Override
public String toString() {
return "TableAndViewPage{" +
"icon=" + icon +
", iconSelected=" + iconSelected +
", text='" + text + '\'' +
", fragment=" + fragment +
'}';
}
}
调用
测试fragment
fragment_tab.xml文件里就一个textview这里就不贴了
public class ViewPagerFragment extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tab, container, false);
}
public static ViewPagerFragment newInstance(String label) {
Bundle args = new Bundle();
args.putString("label", label);
ViewPagerFragment fragment = new ViewPagerFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onStart() {
super.onStart();
LogUtil.d("页面","创建fragment");
String label = getArguments().getString("label");
TextView text = getView().findViewById(R.id.tv_bg);
text.setText(label);
text.setBackgroundColor(Color.rgb((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255)));
}
}
准备数据
ViewPagerFragment.newInstance("123")参数是fragment替换为自己的fragment就行了
SelfViewPageFragmentControl selfVierPageFragmentControl = findViewById(R.id.self_view_page_1);
List<TableAndViewPage> data = new ArrayList<>();
data.add(new TableAndViewPage("测试1",com.pksh.tools.R.mipmap.sel_lie_biao,0,ViewPagerFragment.newInstance("123")));
data.add(new TableAndViewPage("测试2",com.pksh.tools.R.mipmap.def_map_select,0,ViewPagerFragment.newInstance("123")));
data.add(new TableAndViewPage("测试3",com.pksh.tools.R.mipmap.def_map_navigation_neibu,0,ViewPagerFragment.newInstance("123")));
data.add(new TableAndViewPage("测试4",com.pksh.tools.R.mipmap.def_map_navigation_tengxun,0,ViewPagerFragment.newInstance("123")));
使用默认布局调用
默认布局可以设置角标
selfVierPageFragmentControl.setData(data).build();
selfVierPageFragmentControl.setJiaoBiaoNO(0,45);
selfVierPageFragmentControl.setJiaoBiaoNO(3,45);
selfVierPageFragmentControl.setJiaoBiaoNO(1,0);
使用tabLayout原始布局加载
selfVierPageFragmentControl.setData(data).setLoadTypeToDefault().build();
tabLayout原始布局将导航栏加载到顶部
selfVierPageFragmentControl.setData(data).isTop(true).setLoadTypeToDefault().build();
自定义tabLayout布局 并将tab放置在上面
onTabSelected() 可在该回调中通过tab.getCustomView().findViewById(控件id)获取控件直接修改,返回NULL即可 onTabUnselected()可在该回调中通过tab.getCustomView().findViewById(控件id)获取控件直接修改,返回NULL即可
selfVierPageFragmentControl.setData(data).isTop(true).setTabCustomLayout(new SelfViewPageFragmentControl.TabLayoutLoadCustomView() {
@Override
public View loadTabLayoutView(TabLayout.Tab tab, int position) {
View tabView = LayoutInflater.from(getBaseContext()).inflate(R.layout.tab_test_text,null);
TextView textView = tabView.findViewById(R.id.test_textview);
textView.setText(data.get(position).getText());
tab.setCustomView(tabView);
return null;
}
@Override
public View onTabSelected(TabLayout.Tab tab, int position) {
return null;
}
@Override
public View onTabUnselected(TabLayout.Tab tab, int position) {
return null;
}
}).build();
以上就是全部的调用方式了
附录
角标图片链接:https://lxh-customer.oss-cn-qingdao.aliyuncs.com/def_img_jiao_biao.png
|