Tab导航的实现(一)-Tablayout

目前主流实现方式

a 运用Material Design提供的插件TabLayout

b 运用Material Design提供的BottomNavigationView

c FragmentTabHost

一 TabLayout

资料来源:

https://blog.csdn.net/qq_23205911/article/details/73430979

准备工作

由于Material Design属于扩展库,需要实现添加依赖

 
implementation 'com.android.support:design:27.1.1'

后面的版本号必须跟V7包的版本一致

implementation 'com.android.support:appcompat-v7:27.1.1'

1.1通过代码动态实现tablayout

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">
    <FrameLayout
        android:id="@+id/home_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
        
    </FrameLayout>
    
    <view
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:alpha="0.6"
        android:background="@android:color/darker_gray"
        />

    <android.support.design.widget.TabLayout
        android:id="@+id/host_tab_layout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        app:tabSelectedTextColor="@android:color/black"//标题选中的颜色
        app:tabTextColor="@android:color/darker_gray"//未选中的颜色
        app:tabIndicatorHeight="0dp">

    </android.support.design.widget.TabLayout>
</LinearLayout>

indicator指示器

指的就是当前标签页底部的红色的线,设置属性有color和height

UI效果通过代码实现(安装并添加里ButterKnife插件)

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tablayout);
        initView();
    }

    /**
     * 用ButterKnife快速绑定View控件
     */
    private void initView() {

        unbinder=ButterKnife.bind(this);
        hostTabLayout.addTab(hostTabLayout.newTab().setText("TDab1"));
        hostTabLayout.addTab(hostTabLayout.newTab().setText("TDab2"));
        hostTabLayout.addTab(hostTabLayout.newTab().setText("TDab3"));

    }

1.2在布局文件中实现

 <android.support.design.widget.TabLayout
        android:id="@+id/host_tab_layout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        app:tabIndicatorHeight="0dp"
        app:tabSelectedTextColor="@android:color/black"
        app:tabTextColor="@android:color/darker_gray">
        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab1"/>

        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab2"/>

        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab3"/>


    </android.support.design.widget.TabLayout>

实现效果图

1.3添加新的功能

1.4TabLayout的监听事件

hostTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {

//                选中了标签的逻辑
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

//                未选中tab的逻辑
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

//                再次选中tab的逻辑
            }
        });

三个回调接口的执行顺序

当切换新的tab时A--B

onTabUnselected(A)

onTabReselected(B)

onTabSelected(B)

当重复选择当前tab时C---C

onTabReselected(C)

 

2ViewPaper

思路

ViewPaper实现了若干个界面的滑动切换效果,通过跟tabLayout关联,实现两者的联动效果

2.1布局文件

 <android.support.v4.view.ViewPager
            android:id="@+id/vp_context"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        </android.support.v4.view.ViewPager>

2.2代码实现

ViewPaper要实现若干个界面的切换,需要进行适配器填装paperadapter,目前主流的上使用FragmentPaperAdapter

创建自己的Adapter

public class FragAdapter extends FragmentPagerAdapter{
    private List<Fragment> mfragments=null;

    public FragAdapter(FragmentManager fm,List<Fragment> fragments) {
        super(fm);
        mfragments=fragments;
    }

    @Override
    public Fragment getItem(int position) {
        return mfragments.get(position);
    }

    @Override
    public int getCount() {
        return mfragments.size();
    }
}

只需要实现getItem()和getCount()方法

然后,在活动中初始化调用

//        设置FragmentList
        List<Fragment> fragmentList=new ArrayList<Fragment>();
        fragmentList.add(BlankFragment.newInstance());
        fragmentList.add(BlankFragment2.newInstance());
        fragmentList.add(BlankFragment3.newInstance());

//        设置适配器并装载
       adapter=new FragAdapter(getSupportFragmentManager(),fragmentList);
        vpContext.setAdapter(adapter);

4和ViewPager的联动

有资料建议用setupWithViewPaper()关联两者,实验后,发现tab标签变成里空白,原因上在关联代码内部封装函数中,移除里所有tab

tabLayout.setupWithViewPager(Viewpager);

所以采用在监听器中回调互相指定变化

        hostTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                vpContext.setCurrentItem(tab.getPosition());
//                选中了标签的逻辑
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
//                未选中tab的逻辑
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
//                再次选中tab的逻辑
            }
        });

        vpContext.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                
            }

            @Override
            public void onPageSelected(int position) {
                hostTabLayout.getTabAt(position).select();
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

填坑:

1,我自己理解的上,在ViewPaper变化时,应该在onPageScrolled()方法中设置标签,结果造成通过标签无法切换界面

个人认为因为nPageScrolled()的不断调用,阻止了界面的变化.

实际上应该在onPageSelected()中设置tab的标签.

参考资料:https://www.cnblogs.com/Dionexin/p/5727297.html

ViewPaper监听器的方法执行顺序:

用手指拖动翻页时,最先执行一遍onPageScrollStateChanged(1),然后不断执行onPageScrolled,放手指的时候,直接立即执行一次onPageScrollStateChanged(2),然后立即执行一次onPageSelected,然后再不断执行onPageScrollStateChanged,最后执行一次onPageScrollStateChanged(0)。

通过setCurrentItem()设置界面的时候,直接立即执行一次onPageScrollStateChanged(2),然后立即执行一次onPageSelected,然后再不断执行onPageScrollStateChanged,最后执行一次onPageScrollStateChanged(0)。

2.限定vieewPager预加载数量

通过vp.setOffscreenPageLimit()方法,可以指定加载当前frag时,提前加载frag的数量.

默认的设置是自动预加载下一个页面,最多持有当前frag,上一个和下一个3个frag,多余的frag会被销毁

如果我们的页面固定显示4个,直接用该方法,设置viewPager加载4个页面即可.

 

 

3 实现标签选中跟未选中的变化

3.1tablayout自带的标签

首先,对图标和标签标题进行数组管理

        final int[] tabResPressed=new int[]{R.drawable.ic_left,R.drawable.ic_stop,R.drawable.ic_right};
        final int[] tabRes=new int[]{R.drawable.ic_insmall,R.drawable.ic_location,R.drawable.ic_inbigger};
        final String[] tabTitle=new String[]{"tab1","tab2","tab3"};

第二步,通过数组初始化标签图标,(文本和图标两部分)

文本 tab.setText(string)

图标 tab.setIcon(resources)

//        给TablLayout添加标签
        for(int i=0;i<tabTitle.length;i++){
            hostTabLayout.addTab(hostTabLayout.newTab().setText(tabTitle[i]).setIcon(getResources().getDrawable(tabRes[i])));
        }

第三步,在tablayout的监听器中,对选中图标进行设置

A---B,设置B

@Override
            public void onTabSelected(TabLayout.Tab tab) {
//                ViewPaper联动
                vpContext.setCurrentItem(tab.getPosition());
//                图标变为选中状态
                for (int i=0;i<tabTitle.length;i++){
                    if (tab.getText().equals(tabTitle[i])){
                        tab.setIcon(tabResPressed[i]);
                    }
                }
            }

第四步,对tablayout监听器中,对原来被选中的图标更新图标

A--B,设置A

           @Override
            public void onTabUnselected(TabLayout.Tab tab) {
//                图标变回未选中状态
                for (int i=0;i<tabTitle.length;i++){
                    if (tab.getText().equals(tabTitle[i])){
                        tab.setIcon(tabRes[i]);
                    }
                }
//                未选中tab的逻辑
            }

第五步,设置默认  

/        设置默认选中第一个tab并改变图标
        hostTabLayout.getTabAt(0).select();
        setIconViewSelected(0);

具体的实现方法

    private void setIconView(TabLayout.Tab tab,int position) {
        View mView=tab.getCustomView();
        ImageView mImageView=(ImageView) mView.findViewById(R.id.iv_icon);
        TextView mtextView=(TextView)mView.findViewById(R.id.tv_title);
        mImageView.setImageResource(tabRes[position]);
        mtextView.setTextColor(getResources().getColor(android.R.color.darker_gray));
    }

    private void setIconViewSelected(int position) {
        View mView=hostTabLayout.getTabAt(position).getCustomView();
        ImageView mImageView=(ImageView) mView.findViewById(R.id.iv_icon);
        TextView mtextView=(TextView)mView.findViewById(R.id.tv_title);
        mImageView.setImageResource(tabResPressed[position]);
        mtextView.setTextColor(getResources().getColor(android.R.color.black));
    }

 

 

github地址:

 

https://github.com/wwqby/MyApplication.git
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值