当前位置: 代码迷 >> Android >> 【FastDev4Android框架开发】HorizontalScrollView,Fragment,FragmentStatePagerAdapter制造网易新闻Tab及滑动页面效果(三十六)
  详细解决方案

【FastDev4Android框架开发】HorizontalScrollView,Fragment,FragmentStatePagerAdapter制造网易新闻Tab及滑动页面效果(三十六)

热度:494   发布时间:2016-04-27 22:02:37.0
【FastDev4Android框架开发】HorizontalScrollView,Fragment,FragmentStatePagerAdapter打造网易新闻Tab及滑动页面效果(三十六)

转载请标明出处:

http://blog.csdn.net/developer_jiangqq/article/details/50145759

本文出自:【江清清的博客】

().前言:   

          仿36Kr客户端开发过程中,因为他们网站上面的新闻文章分类比较多,所以我这边还是打算模仿网易新闻APP的主界面新闻标签Tab以及页面滑动效果来进行实现。要实现的顶部的Tab标签的效果有很多方法例如采用开源项目ViewPagerIndicator中的TabPageIndicator就可以实现,不过查看了源码发现该控件其实就是继承自HorizontalScrollView自定义出来的。那既然这样我这边就准备带着大家直接使用HorizontalScrollView来实现顶部tab标签效果。底部的页面滑动直接采用Fragment+ViewPager+FragmentStatePagerAdapter实现即可。后面我也会更新一篇直接使用ViewPagerIndicator开源控件实现tab标签效果的文章,敬请期待~

          本例子具体代码已经上传到下面的项目中,欢迎各位去star和fork一下。

         FastDev4Android框架项目地址:https://github.com/jiangqqlmj/FastDev4Android

().实现原理:   


         上面我这边直接贴了36Kr官方APP的主界面顶部Tab标签,我这边直接模仿这个做。首先看上面截图红色框起来的部分,这边的Tab是可以横向滑动的那可以采用HorizontalScrollView控件实现,并且里边的每一项Tab Item都是可以进行添加和点击。我们直接往HorizontalScrollView addView子控件即可。Tab下面是若干个新闻文章列表的页面且可以进行左右滑动可以采用ViewPager实现,每个页面采用Fragment实现。


上图是具体控件的分布和嵌套,下面我们来看一下具体实现:

().具体实现

            3.1.首先我们需要有一个继承自FragmentActivityMainInfoActivity,该用来承载Fragment,该Activity中实现基本没有啥代码,就不贴详细到时候去FastDev4Android项目中下载即可,这边我们看一下Activity的布局文件:

<?xmlversion="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"   xmlns:tools="http://schemas.android.com/tools"    android:orientation="vertical"android:layout_width="match_parent"   android:layout_height="match_parent"    >    <includelayout="@layout/common_top_bar_layout"/>    <fragment       android:id="@+id/info_fragment"       class="com.chinaztt.fda.fragment.InfoFragment"       android:layout_width="fill_parent"       android:layout_height="fill_parent"       tools:layout="@layout/info_fragment_layout"        /></LinearLayout>

该布局文件中直接把承载的InfoFragment写在里边了,当我们Activity加载的时候该Fragment也被加载了。

      3.2.接下来就是InfoFragment了,让我们首先看下我这边定义的布局文件:

<?xmlversion="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"android:layout_width="match_parent"   android:layout_height="match_parent"   android:background="@color/white">    <!--横向滑动的容器-->    <HorizontalScrollView       android:id="@+id/horizontal_info"       android:layout_width="fill_parent"       android:layout_height="wrap_content"        android:scrollbars="none">        <!--装入每一个Tab项容器-->        <LinearLayout           android:id="@+id/linearlayout_container"           android:layout_width="fill_parent"           android:layout_height="49dp"           android:orientation="horizontal">        </LinearLayout>    </HorizontalScrollView>    <android.support.v4.view.ViewPager       android:id="@+id/info_viewpager"       android:layout_width="fill_parent"       android:layout_height="fill_parent"/></LinearLayout>

           该布局中主要分为两部分,第一部分就是HorizontalScrollView控件该用来实现横向滑动,为标签Tab的容器,我们可以往里边动态的添加Tab Item。第二部分为ViewPager控件该用来实现页面的左右滑动,其中每一项Item为Fragment。以上关键控件已经定义好了,下面就是需要在InfoFragment中实现Tab效果了。

首先定义和初始化控件:

/**     * 当前选择的分类     */    private int mCurClassIndex=0;    /**     * 选择的分类字体颜色     */    private int mColorSelected;    /**     * 非选择的分类字体颜色     */    private int mColorUnSelected;    /**     * 水平滚动的Tab容器     */    private HorizontalScrollView mScrollBar;    /**     * 分类导航的容器     */    private ViewGroup mClassContainer;    /**     * 水平滚动X     */    private int mScrollX=0; mScrollBar=(HorizontalScrollView)mView.findViewById(R.id.horizontal_info); mClassContainer=(ViewGroup)mView.findViewById(R.id.linearlayout_container);

 对于Tab Item的动态添加使用下面写得方法addScrollView()

 /**     * 动态添加顶部Tab滑动的标签     * @param titles     */    private void addScrollView(String[]titles){        LayoutInflater mLayoutInflater=LayoutInflater.from(FDApplication.getInstance());        final int count=titles.length;        for(int i=0;i<count;i++){            final String title=titles[i];            final Viewview=mLayoutInflater.inflate(R.layout.horizontal_item_layout,null);            final LinearLayout linearLayout=(LinearLayout)view.findViewById(R.id.horizontal_linearlayout_type);            final ImageView img_type=(ImageView)view.findViewById(R.id.horizontal_img_type);            final TextView type_name=(TextView)view.findViewById(R.id.horizontal_tv_type);            type_name.setText(title);            if(i==mCurClassIndex){                //已经选中               type_name.setTextColor(mColorSelected);               img_type.setImageResource(R.drawable.bottom_line_blue);            }else {                //未选中               type_name.setTextColor(mColorUnSelected);               img_type.setImageResource(R.drawable.bottom_line_gray);            }            final int index=i;            //点击顶部Tab标签,动态设置下面的ViewPager页面            view.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    //首先设置当前的Item为正常状态                    View currentItem=mClassContainer.getChildAt(mCurClassIndex);                   ((TextView)(currentItem.findViewById(R.id.horizontal_tv_type))).setTextColor(mColorUnSelected);                   ((ImageView)(currentItem.findViewById(R.id.horizontal_img_type))).setImageResource(R.drawable.bottom_line_gray);                    mCurClassIndex=index;                    //设置点击状态                   img_type.setImageResource(R.drawable.bottom_line_blue);                   type_name.setTextColor(mColorSelected);                    //跳转到指定的ViewPager                   info_viewpager.setCurrentItem(mCurClassIndex);                }            });            mClassContainer.addView(view);        }    }
   该方法传入了标签的数组,根据标签的数量进行遍历动态添加,主要步骤如下:

  • 加载每一项Tab Item的布局,并且获取Item中的相关控件并且设置数据和资源文件
  • 判断当前是否选中项,对于选中和未选中设置不同的字体颜色和资源文件
  • 给每一项Item添加点击事件,用来切换ViewPager跳转到具体每一项页面(Fragment)
  • 最终每一项Tab Item加入到容器中

 

         上面我们有讲到,使用Fragment+ViewPager实现页面滑动切换,那我们需要一个页面的自定义适配器了,我这边创建了CNKFixedPagerAdapter该类继承自FragmengStatePagerAdaper具体实现代码如下,比较简单就不详细讲解了:

public class CNKFixedPagerAdapter extends FragmentStatePagerAdapter {    private String[] titles;    public void setTitles(String[] titles) {        this.titles = titles;    }    private List<Fragment> fragments;    public CNKFixedPagerAdapter(FragmentManager fm) {        super(fm);    }     @Override    public Fragment getItem(int position) {        return this.fragments.get(position);    }    @Override    public int getCount() {        return this.fragments.size();    }     @Override    public Object instantiateItem(ViewGroup container, int position) {        Fragment fragment=null;        try {           fragment=(Fragment)super.instantiateItem(container,position);        }catch (Exception e){         }        return fragment;    }     @Override    public void destroyItem(ViewGroup container, int position, Object object) {     }     public List<Fragment> getFragments(){        return fragments;    }    public void setFragments(List<Fragment> fragments) {        this.fragments = fragments;    }}
       然后我们实例化ViewPager以及自定义适配器和显示的Fragment数据绑定即可:

fragments=new ArrayList<>();        for(int i=0;i<12;i++){            OneFragment oneFragment=new OneFragment();            Bundle bundle=new Bundle();           bundle.putString("extra",titles[i]);            oneFragment.setArguments(bundle);            fragments.add(oneFragment);        }         mPagerAdater=new CNKFixedPagerAdapter(getChildFragmentManager());        mPagerAdater.setTitles(titles);        mPagerAdater.setFragments(fragments);       info_viewpager.setAdapter(mPagerAdater);  

       最后我们不要忘记有一点是:当我们的ViewPager页面切换的时候我们需要实习改变顶部Tab Item的选中情况以及字体颜色等。所以我们需要给ViewPager添加页面切换监听器OnPageChangeListener,然后在回调的onPageSelected()方法中重新设置一下Tab Item的效果。

info_viewpager.setOnPageChangeListener(this);

//下面三个回调方法 分别是在ViewPager进行滑动的时候调用    @Override    public void onPageScrolled(int position,float positionOffset, int positionOffsetPixels) {     }    @Override    public void onPageSelected(int position) {        //首先设置当前的Item为正常状态        View preView=mClassContainer.getChildAt(mCurClassIndex);       ((TextView)(preView.findViewById(R.id.horizontal_tv_type))).setTextColor(mColorUnSelected);       ((ImageView)(preView.findViewById(R.id.horizontal_img_type))).setImageResource(R.drawable.bottom_line_gray);        mCurClassIndex=position;        //设置当前为选中状态        View currentItem=mClassContainer.getChildAt(mCurClassIndex);       ((ImageView)(currentItem.findViewById(R.id.horizontal_img_type))).setImageResource(R.drawable.bottom_line_blue);       ((TextView)(currentItem.findViewById(R.id.horizontal_tv_type))).setTextColor(mColorSelected);        //这边移动的距离 是经过计算粗略得出来的        mScrollX=currentItem.getLeft()-300;        Log.d("zttjiangqq","mScrollX:" + mScrollX);        mScrollBar.post(new Runnable() {            @Override            public void run() {               mScrollBar.scrollTo(mScrollX,0);            }        });    }    @Override    public void onPageScrollStateChanged(int state) {    }

   上面onPageSelected()方法中我们首先设置原先的Item的颜色为正常未选中状态,然后设置当前的位置选中以及字体颜色改变,最后让HorizontalScrollView平移到合适的位置即可:

   3.3.以上我们的核心代码已经讲解完成了,下面我们看一下运行效果:


  3.4.为了大家方便阅读代码,我这边把InfoFragment的全部代码贴出来:

public class InfoFragment extends Fragment implements ViewPager.OnPageChangeListener{     private View mView;    ViewPager info_viewpager;    private List<Fragment> fragments;    private CNKFixedPagerAdapter mPagerAdater;    private String[] titles=new String[]{"全部","氪TV","O2O","新硬件","Fun!!","企业服务","Fit&Health","在线教育","互联网金融","大公司","专栏","新产品"};    /**     * 当前选择的分类     */    private int mCurClassIndex=0;    /**     * 选择的分类字体颜色     */    private int mColorSelected;    /**     * 非选择的分类字体颜色     */    private int mColorUnSelected;    /**     * 水平滚动的Tab容器     */    private HorizontalScrollView mScrollBar;    /**     * 分类导航的容器     */    private ViewGroup mClassContainer;    /**     * 水平滚动X     */    private int mScrollX=0;    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        if(mView==null){           mView=inflater.inflate(R.layout.info_fragment_layout,container,false);            initViews();            initValidata();         }        return mView;    }    /**     * 初始化布局控件     */    private void initViews(){       info_viewpager=(ViewPager)mView.findViewById(R.id.info_viewpager);       mScrollBar=(HorizontalScrollView)mView.findViewById(R.id.horizontal_info);       mClassContainer=(ViewGroup)mView.findViewById(R.id.linearlayout_container);     }    private void initValidata(){        mColorSelected=FDApplication.getInstance().getResources().getColor(R.color.color_selected);       mColorUnSelected=FDApplication.getInstance().getResources().getColor(R.color.color_unselected);        //添加Tab标签        addScrollView(titles);        mScrollBar.post(new Runnable() {            @Override            public void run() {                mScrollBar.scrollTo(mScrollX,0);            }        });        fragments=new ArrayList<>();        for(int i=0;i<12;i++){            OneFragment oneFragment=new OneFragment();            Bundle bundle=new Bundle();           bundle.putString("extra",titles[i]);            oneFragment.setArguments(bundle);            fragments.add(oneFragment);        }         mPagerAdater=new CNKFixedPagerAdapter(getChildFragmentManager());        mPagerAdater.setTitles(titles);        mPagerAdater.setFragments(fragments);       info_viewpager.setAdapter(mPagerAdater);       info_viewpager.setOnPageChangeListener(this);    }    /**     * 动态添加顶部Tab滑动的标签     * @param titles     */    private void addScrollView(String[]titles){        LayoutInflater mLayoutInflater=LayoutInflater.from(FDApplication.getInstance());        final int count=titles.length;        for(int i=0;i<count;i++){            final String title=titles[i];            final View view=mLayoutInflater.inflate(R.layout.horizontal_item_layout,null);            final LinearLayout linearLayout=(LinearLayout)view.findViewById(R.id.horizontal_linearlayout_type);            final ImageView img_type=(ImageView)view.findViewById(R.id.horizontal_img_type);            final TextView type_name=(TextView)view.findViewById(R.id.horizontal_tv_type);            type_name.setText(title);            if(i==mCurClassIndex){                //已经选中               type_name.setTextColor(mColorSelected);               img_type.setImageResource(R.drawable.bottom_line_blue);            }else {                //未选中               type_name.setTextColor(mColorUnSelected);               img_type.setImageResource(R.drawable.bottom_line_gray);            }            final int index=i;            //点击顶部Tab标签,动态设置下面的ViewPager页面            view.setOnClickListener(newView.OnClickListener() {                @Override                public void onClick(View v) {                    //首先设置当前的Item为正常状态                    View currentItem=mClassContainer.getChildAt(mCurClassIndex);                   ((TextView)(currentItem.findViewById(R.id.horizontal_tv_type))).setTextColor(mColorUnSelected);                   ((ImageView)(currentItem.findViewById(R.id.horizontal_img_type))).setImageResource(R.drawable.bottom_line_gray);                    mCurClassIndex=index;                    //设置点击状态                   img_type.setImageResource(R.drawable.bottom_line_blue);                   type_name.setTextColor(mColorSelected);                    //跳转到指定的ViewPager                   info_viewpager.setCurrentItem(mCurClassIndex);                }            });            mClassContainer.addView(view);        }    }    //下面三个回调方法 分别是在ViewPager进行滑动的时候调用    @Override    public void onPageScrolled(int position,float positionOffset, int positionOffsetPixels) {     }     @Override    public void onPageSelected(int position) {        //首先设置当前的Item为正常状态        View preView=mClassContainer.getChildAt(mCurClassIndex);       ((TextView)(preView.findViewById(R.id.horizontal_tv_type))).setTextColor(mColorUnSelected);       ((ImageView)(preView.findViewById(R.id.horizontal_img_type))).setImageResource(R.drawable.bottom_line_gray);        mCurClassIndex=position;        //设置当前为选中状态        View currentItem=mClassContainer.getChildAt(mCurClassIndex);       ((ImageView)(currentItem.findViewById(R.id.horizontal_img_type))).setImageResource(R.drawable.bottom_line_blue);       ((TextView)(currentItem.findViewById(R.id.horizontal_tv_type))).setTextColor(mColorSelected);        //这边移动的距离 是经过计算粗略得出来的        mScrollX=currentItem.getLeft()-300;        Log.d("zttjiangqq","mScrollX:" + mScrollX);        mScrollBar.post(new Runnable() {            @Override            public void run() {               mScrollBar.scrollTo(mScrollX,0);            }        });    }     @Override    public void onPageScrollStateChanged(int state) {     }}

().最后总结

           今天我们通过Fragment+ViewPager+FragmentStatePagerAdapter+HorizontalScrollView实现了仿照网易新闻客户端(或者36Kr)首页的页面滑动和顶部Tab效果。

           本次实例代码因为比较多,代码全贴比较浪费篇幅,重点在于讲解思路了。不过实例注释过的全部代码已经上传到Github项目中了。同时欢迎大家去Github站点进行clone或者fork浏览整个开源快速开发框架项目~

https://github.com/jiangqqlmj/FastDev4Android

 

尊重原创,转载请注明:From Sky丶清(http://blog.csdn.net/developer_jiangqq) 侵权必究!

关注我的微博,可以获得更多精彩内容

 

  相关解决方案