解读(四):分析主界面顶部Tab的实现

来源:互联网 发布:淘宝提前收款条件 编辑:程序博客网 时间:2024/06/14 12:41

解读(四):分析主界面顶部Tab的实现

使用Tab管理类管理顶部Tab

上次分析到了利用Tabs的管理类来动态更新首页顶部tabs的显示

Fragment mTab = new BaseTabMainFragment() {            @Override            public void onSetupTabs() {                //添加要显示主界面Tabs项                addTab(getResources().getString(R.string.new_news), ListNewsFragment.class, NewsList.CATALOG_ALL); //最新资讯                addTab(getResources().getString(R.string.week_news), ListNewsFragment.class, NewsList.CATALOG_WEEK); //周度资讯                addTab(getResources().getString(R.string.month_news), ListNewsFragment.class, NewsList.CATALOG_MONTH); //月度资讯            }        };

可以发现继承关系 BaseTabMainFragment –> BaseTabFragment –> BaseFragment, 从父类开始分析

BaseFragment类

/** * Fragment的基类 */public abstract class BaseFragment<P extends Presenter> extends NucleusFragment<P> {    public Context mContext;    public Resources resources;    public static final String BUNDLE_TYPE = "BUNDLE_TYPE";    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mContext = getActivity(); //获得所附加的activity对象        resources = mContext.getResources(); //便于获取资源    }}

BaseTabFragment类

/** * Tab的Fragment基类 */public abstract class BaseTabFragment extends BaseFragment {    protected ViewPager mViewPager;    protected FragmentStatePagerAdapter mAdapter;    protected ArrayList<ViewPageInfo> mTabs;    @Override    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        mViewPager = (ViewPager) view.findViewById(R.id.view_pager);        if (mAdapter == null) {            mTabs = new ArrayList<>();            //设置tab项            onSetupTabs();            //设置适配器, 这里有个疑问, 一直都没有为mAdapter赋值,那么每次是不是都会走 mAdapter==null的流程?            mViewPager.setAdapter(new FragmentStatePagerAdapter(getGenuineFragmentManager()) {                @Override                public Fragment getItem(int position) {                    //获得ViewPagerInfo中管理的fragment                    return mTabs.get(position).fragment;                }                @Override                public int getCount() {                    return mTabs.size();                }                @Override                public CharSequence getPageTitle(int position) {                    //获得标题, 这个tag也就是fragment的标题                    return mTabs.get(position).tag;                }            });        } else {            mViewPager.setAdapter(mAdapter);        }    }    /**     * 导航元素, 也就是Tab页卡上的View     */    public abstract View setupTabItemView(String title);    /**     * 设置Fragment, 由子类实现     */    public abstract void onSetupTabs();    /**     * 获得FragmentManager, 这个封装也真是够了, 是为了增加方法数吗?     */    public FragmentManager getGenuineFragmentManager() {        return getFragmentManager();    }    /**     * 添加Fragment对象到ViewPager     */    public void addTab(String tag, Class<? extends Fragment> fragment, int catalog) {        Bundle bundle = new Bundle();        bundle.putInt(BUNDLE_TYPE, catalog);        mTabs.add(new ViewPageInfo(tag, Fragment.instantiate(getActivity(), fragment.getName(), bundle)));    }    public void addTab(String tag, Class<? extends Fragment> fragment) {        mTabs.add(new ViewPageInfo(tag, Fragment.instantiate(getActivity(), fragment.getName())));    }    public void addTab(String tag, Fragment fragment) {        mTabs.add(new ViewPageInfo(tag, fragment));    }    /**     * 设置ViewPager当前选中的item     */    public void setCurrentItem(int index) {        mViewPager.setCurrentItem(index);    }    /**     * 获得ViewPager当前选中的item     */    public int getCurrentItem() {        return mViewPager.getCurrentItem();    }    /**     * 获得tabs的数量     */    public int getPageCount() {        return mTabs.size();    }    /**     * ViewPageInformation     * 将Fragment和tag封装成一个对象,形成一一对应关系     */    public static class ViewPageInfo {        public String tag; //fragment绑定的tag        public View view; //这个View是为了自定义底部导航栏而设置的        public Fragment fragment; //内部持有一个Fragment        public ViewPageInfo(String tag, Fragment fragment) {            this.tag = tag;            this.fragment = fragment;        }    }}
  • 可以看到 addTab()是在BaseTabFragment类中, 就是将传入的getResources().getString(R.string.new_news)和ListNewsFragment 一一绑定起来. 这里要注意的是三个Tab都是使用的ListNewsFragment, 区分他们显示内容的是addTab()的第三个参数NewsList.CATALOG_ALL,NewsList.CATALOG_WEEK和NewsList.CATALOG_MONTH.
mTabs.add(new ViewPageInfo(tag, Fragment.instantiate(getActivity(), fragment.getName(), bundle)));
  • 这里将三个类别使用Bundle封装, 携带到ListNewsFragment中, 可以通过getArguments()获得传入的Bundle对象.

  • 这里使用的创建Fragment的方法是instantiate()创建一个指定类名的Fragment对象,相当于调用了Fragment的空参构造.

 public static Fragment instantiate(Context context, String fname, @Nullable Bundle args){...}
  • 上面留有疑问的地方是mAdapter一直都没有赋值, 那么每次都会走mAdapter==null的流程,每次创建一个新的适配器吗?

BaseTabMainFragment类

/** * 主界面Tabs的fragment基类 **/public abstract class BaseTabMainFragment extends BaseTabFragment {    @Bind(R.id.tab_nav)    TabLayout mTabLayout;    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        super.onCreateView(inflater, container, savedInstanceState);        //加载通用布局        return inflater.inflate(R.layout.fragment_universal_tab, container, false);    }    @SuppressWarnings("all")    @Override    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        ButterKnife.bind(this, view);        //设置Z轴的高度,显示阴影效果        ViewCompat.setElevation(mTabLayout, 7);        if (mAdapter == null) {            //将TabLayout和ViewPager关联起来,只需要关联一次            mTabLayout.setupWithViewPager(mViewPager);        }    }    /**     * 设置Tab页卡上的View, 这里是由父类提供了抽象,子类提供实现,子类最后调用的是子类自己的该方法     */    @Override    public TextView setupTabItemView(String tag) {        //设置一个TextView        RelativeLayout layout = (RelativeLayout) View.inflate(mContext, R.layout.view_tab_item, null);        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);        params.weight = 1; //设置权重        layout.setLayoutParams(params); //这里有点疑问? 为什么线性布局的params设置到了RelativeLayout中去了        TextView tabItemView = (TextView) layout.findViewById(R.id.pager_nav_item);         tabItemView.setText(tag); //设置显示为Fragment绑定的tag        return tabItemView;    }}
  • 代码中有个疑问: 为什么LinearLayout的布局参数可以设置到RelativeLayout中去? 目前没有想清白.
  • –> 之前是想错了, 现在过来更正. 这里的含义是将一个RelativeLayout作为子布局添加到一个LinearLayout的父布局中, 并设置RelativeLayout的layout_weight为1. [2016-04-28 update]

  • 这里实现tab页卡的方式TableLayout+ViewPager. 从加载layout/fragment_universal_tab.xml可以看到.

<LinearLayout 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">    <!--tab navigation-->    <android.support.design.widget.TabLayout        android:id="@+id/tab_nav"        android:background="?attr/colorPrimary"        android:layout_width="match_parent"        android:layout_height="40dp"        app:tabGravity="fill"        app:tabMode="fixed"        app:tabIndicatorColor="?attr/tab_item_underline"        app:tabSelectedTextColor="?attr/tab_item_selected"        app:tabTextColor="?attr/tab_item_unselected" />    <android.support.v4.view.ViewPager        android:id="@+id/view_pager"        android:layout_width="match_parent"        android:layout_height="match_parent"/></LinearLayout>

具体实现方式可以参考这篇文章: ViewPager实现页卡的最新方法–简洁的TabLayout(谷歌支持包)

BaseTabNavFragment类

BaseTabNavFragment类也是继承自BaseTabFragment, 用于添加底部导航元素.
(这个在后面的自定义表情回复评论的Fragment中得以使用)

/** * 自定义底部emotion导航元素的viewpager.  * 使用场景:表情选项卡,轮番等 **/public abstract class BaseTabNavFragment extends BaseTabFragment implements ViewPager.OnPageChangeListener {    protected LinearLayout mNavLayout;    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        super.onCreateView(inflater, container, savedInstanceState);        //布局中预留了一个LinearLayout用来动态添加View        return inflater.inflate(R.layout.fragment_dot_nav, container, false);    }    @Override    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {        //获得底部tab的LinearLayout容器        mNavLayout = (LinearLayout) view.findViewById(R.id.tab_nav);        super.onViewCreated(view, savedInstanceState);        mViewPager.addOnPageChangeListener(this); //设置ViewPager的滑动监听    }    /**     * 重写父类的addTab()方法,用于添加底部元素     */    @Override    public void addTab(String title, Class<? extends Fragment> fragment, int catalog) {        super.addTab(title, fragment, catalog);        View view = setupTabItemView(title);        mNavLayout.addView(view);//添加到底部元素        mTabs.get(mTabs.size() - 1).view = view; //设置到ViewPagerInfo中    }    @Override    public void addTab(String title, Class<? extends Fragment> fragment) {        super.addTab(title, fragment);        View view = setupTabItemView(title);        mNavLayout.addView(view);        mTabs.get(mTabs.size() - 1).view = view;    }    @Override    public void addTab(String title, Fragment fragment) {        super.addTab(title, fragment);        View view = setupTabItemView(title);        mNavLayout.addView(view);        mTabs.get(mTabs.size() - 1).view = view;    }    /**     * 设置当前选中的item     */    public void setCurrentItem(int index) {        mViewPager.setCurrentItem(index);        mTabs.get(index).view.setSelected(true);//设置被tab被选中    }    @Override    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {    }    /**     * 当页面被选中时回调     */    @Override    public void onPageSelected(int position) {        //遍历改变选中状态        for (int i = 0; i < mTabs.size(); i++) {            if (position == i)                mTabs.get(i).view.setSelected(true);            else                mTabs.get(i).view.setSelected(false);        }    }    @Override    public void onPageScrollStateChanged(int state) {    }}
  • 看完这一段, 我瞬间对作者抽取能力佩服极了. 抽象的BaseTabNavFragment类既能用于顶部的tab,也能用于底部添加view的tab. 而且tab是动态添加进去的. 这个设计确实可以. 点个赞!

时间有点晚了, 明天再战吧. to be continue….

1 0
原创粉丝点击