• 带你实现开发者头条APP(四)---首页优化(加入design包)



    title: 带你实现开发者头条APP(四)---首页优化(加入design包)
    tags: design,Toolbar,TabLayout,RecyclerView
    grammar_cjkRuby: true

    一 、前言

    上次模仿开发者头条首页实现了一个版本,给345大神,我的产品经理一看,又被鄙视了一把,说还在用老的技术,于是乎这三天把整个design包研究了一遍,然后把首页的代码几乎重写了一遍。。。。顺便用上了android studio,方便大家导入。。。

    效果图如下:
    效果图
    从gif动态效果图中我们可以看出,跟上次没有啥变化,唯一变化的就是列表上拉的时候会隐藏标题栏。。。其实里面的代码几乎重写了一遍,用了Android Design Support Library。

    Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件。最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2。这不得不说是一个良心之作。

    二、Toolbar+TabLayout 实现 标题栏+三个切换Tab

    标题栏我之前引用的一个布局文件,现在改成了Toolbar。一个控件就够了。
    三个切换的Tab之前用的三个TextView,现在换成了TabLayout。
    换了之后有哪些优点:

    1).跟的上时代,逼格提高,更加规范的MD设计风格
    2).控件变少了,现在一个功能一个控件就够
    3).点击Tab文字变色,还有指示器的滑动在xml加个属性就行。
    4).隐藏显示标题栏很方便。只需要在布局文件中改动就行.

    1.布局文件

    最外层是CoordinatorLayout,里面主要就分两块,AppBarLayout+ViewPager(AppBarLayout里面包含标题栏的Toolbar+TabLayout,ViewPager用来切换Fragment显示)

    为了使得Toolbar有滑动效果,必须做到如下三点:

    1. CoordinatorLayout作为布局的父布局容器。
    2. 给需要滑动的组件设置 app:layout_scrollFlags=”scroll|enterAlways” 属性。
    3. 滑动的组件必须是AppBarLayout顶部组件。
    4. 给滑动的组件设置app:layout_behavior属性
      5.ViewPager显示的Fragment里面不能是ListView,必须是RecyclerView。
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/coordinatorLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appBarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/launcher_item_select"
                app:layout_scrollFlags="scroll|enterAlways"
                app:titleTextAppearance="@style/ansenTextTitleAppearance">
            </android.support.v7.widget.Toolbar>
            <android.support.design.widget.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:background="@color/main_color"
                app:tabIndicatorColor="@color/white_normal"
                app:tabIndicatorHeight="2dp"
                app:tabSelectedTextColor="@color/main_title_text_select"
                app:tabTextAppearance="@style/AnsenTabLayoutTextAppearance"
                app:tabTextColor="@color/main_title_text_normal"/>
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />
    </android.support.design.widget.CoordinatorLayout>
    
    2.代码实现 MainFragment.java

    1).初始化Toolbar,加载menu布局,实现标题栏的自定义。给NavigationIcon设置点击事件等。下面贴出代码实现,还有menu布局文件我就不贴出来了。那个也没啥技术含量。

    Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar);
    		toolbar.inflateMenu(R.menu.ansen_toolbar_menu);
    		toolbar.setNavigationIcon(R.mipmap.ic_menu_white);
    		toolbar.setTitle("关注公众号[Android开发者666]");
    		toolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
    		toolbar.setNavigationOnClickListener(onClickListener);
    

    NavigationIcon监听函数,回调到MainActivity去。

    	private View.OnClickListener onClickListener=new View.OnClickListener(){
    		@Override
    		public void onClick(View view) {
    			if(drawerListener!=null){
    				drawerListener.open();
    			}
    		}
    	};
    

    MainActivity.java
    首先写了一个用来回调的接口

    	public interface MainDrawerListener{
    		public void open();//打开Drawer
    	}
    

    初始化Fragment的时候把MainDrawerListener对象传递过去 这样才能实现回调

    mainFragment=new MainFragment(drawerListener);
    
    	private MainDrawerListener drawerListener=new MainDrawerListener() {
    		@Override
    		public void open() {
    			mDrawerLayout.openDrawer(Gravity.LEFT);
    		}
    	};
    

    2).给ViewPager设置Fragment适配器,给TabLayout绑定ViewPager,这样ViewPager滑动的时候或者选择tab的时候都会切换fragment。

    		vPager = (ViewPager) rootView.findViewById(R.id.viewPager);
    		vPager.setOffscreenPageLimit(2);//设置缓存页数
    		vPager.setCurrentItem(0);
    
    		FragmentAdapter pagerAdapter = new FragmentAdapter(getActivity().getSupportFragmentManager());
    		SelectedFragment selectedFragment=new SelectedFragment();
    		SubscribeFragment subscribeFragment=new SubscribeFragment();
    		FindFragment findFragment=new FindFragment();
    
    		pagerAdapter.addFragment(selectedFragment,"精选");
    		pagerAdapter.addFragment(subscribeFragment,"订阅");
    		pagerAdapter.addFragment(findFragment,"发现");
    
    		vPager.setAdapter(pagerAdapter);
    
    		TabLayout tabLayout = (TabLayout) rootView.findViewById(R.id.tabLayout);
    		tabLayout.setupWithViewPager(vPager);
    

    三 、分析TabLayout切换源码

    我们调用TabLayout的setupWithViewPager(ViewPager viewPager)方法的时候就是设置切换监听的时候。

        public void setupWithViewPager(ViewPager viewPager) {
            PagerAdapter adapter = viewPager.getAdapter();
            if(adapter == null) {
                throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
            } else {
                this.setTabsFromPagerAdapter(adapter);
                viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(this));
                this.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager));
            }
        }
    

    从上面代码中我们可以看到主要设置了两个监听函数。先说第一个。
    在TabLayout里面有一个静态类TabLayoutOnPageChangeListener,用来处理ViewPager改变状态(切换或者增加)监听,看过我第三篇文章的同学对ViewPager的状态改变监听应该很熟悉了。

     viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(this));
    

    TabLayoutOnPageChangeListener实现了ViewPagerde 的OnPageChangeListener接口,在onPageSelected方法中调用了当前选中的某个Tab的select方法。

            public void onPageSelected(int position) {
                TabLayout tabLayout = (TabLayout)this.mTabLayoutRef.get();
                if(tabLayout != null) {
                    tabLayout.getTabAt(position).select();
                }
    
            }
    

    然后继续跟踪TabLayout.Tab类的select() 看看如何实现的。我们可以看到又调用了父类(TabLayout)的selectTab。

            public void select() {
                this.mParent.selectTab(this);
            }
    

    然后跟踪selectTab方法,这里大家可以看到参数是某个具体Tab对象,首先判断是不是当前tab,如果不是设置选择当前的tab,开启tab滑动动画。

     void selectTab(TabLayout.Tab tab) {
            if(this.mSelectedTab == tab) {
                if(this.mSelectedTab != null) {
                    if(this.mOnTabSelectedListener != null) {
                        this.mOnTabSelectedListener.onTabReselected(this.mSelectedTab);
                    }
    
                    this.animateToTab(tab.getPosition());
                }
            } else {
                int newPosition = tab != null?tab.getPosition():-1;
                this.setSelectedTabView(newPosition);
                if((this.mSelectedTab == null || this.mSelectedTab.getPosition() == -1) && newPosition != -1) {
                    this.setScrollPosition(newPosition, 0.0F, true);
                } else {
                    this.animateToTab(newPosition);
                }
    
                if(this.mSelectedTab != null && this.mOnTabSelectedListener != null) {
                    this.mOnTabSelectedListener.onTabUnselected(this.mSelectedTab);
                }
    
                this.mSelectedTab = tab;
                if(this.mSelectedTab != null && this.mOnTabSelectedListener != null) {
                    this.mOnTabSelectedListener.onTabSelected(this.mSelectedTab);
                }
            }
    
        }
    

    上面的代码我就不一一解释了,直接看最下面那两行代码。调用tab的选择方法。

                if(this.mSelectedTab != null && this.mOnTabSelectedListener != null) {
                    this.mOnTabSelectedListener.onTabSelected(this.mSelectedTab);
                }
    

    选择监听的接口

        public interface OnTabSelectedListener {
            void onTabSelected(TabLayout.Tab var1);
    
            void onTabUnselected(TabLayout.Tab var1);
    
            void onTabReselected(TabLayout.Tab var1);
        }
    

    在TabLayout内部实现了OnTabSelectedListener接口,在onTabSelected方法中调用了ViewPager的setCurrentItem(),这个方法大家应该都熟悉吧,我就不多做解释了。

        public static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
            private final ViewPager mViewPager;
    
            public ViewPagerOnTabSelectedListener(ViewPager viewPager) {
                this.mViewPager = viewPager;
            }
    
            public void onTabSelected(TabLayout.Tab tab) {
                this.mViewPager.setCurrentItem(tab.getPosition());
            }
    
            public void onTabUnselected(TabLayout.Tab tab) {
            }
    
            public void onTabReselected(TabLayout.Tab tab) {
            }
        }
    

    上面说到了第一种监听,就是ViewPager滑动的时候如何切换item,如果切换tab。现在来说第二种情况,就是点击选择tab的时候。如何切换的。继续回到TabLayout的setupWithViewPager(ViewPager viewPager)方法。

     this.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager));
    

    看到ViewPagerOnTabSelectedListener类是不是很熟悉,其实就是第一种方法最后调用的那个类。。。。。因为点击某个tab的时候,tab切换的代码已经运行,所以我们这里只需要设置下ViewPager当前选中的item就行。

    从源码分析的文章第一次写,不知道这样写出来大家看的懂么,还有不对的地方也欢迎大家提出,可以给我评论哦,我会第一时间回复大家。

    四 、透剧

    本来打算顺便写下RecyclerView的实现的,但是发现内容已经不少了,那就留着下篇文章吧,下篇文章打算左滑里面的布局用NavigationView实现。然后加上RecyclerView吧。

    五 、源码下载

    点击下载源码

    六 、相关文章阅读

    带你实现开发者头条(一) 启动页实现
    带你实现开发者头条(二) 实现左滑菜单
    带你实现开发者头条APP(三) 首页实现

    各位看官如果觉得文章不错,帮忙点个赞吧,对于你来说是举手之劳,但对于我来说这就是坚持下去的动力。

    **推荐下自己创建的Android开发 QQ群: 202928390欢迎大家的加入. **

    如果你想第一时间看我们的后期文章,扫码关注公众号,每周不定期推送Android开发实战教程文章,你还等什么,赶快关注吧,学好技术,出任ceo,赢取白富美。。。。

          Android开发666 - 安卓开发技术分享
                扫描二维码加关注
    

    Android开发666

  • 相关阅读:
    最小生成树——prim
    最短路径——floyd(多源最短路径)
    最短路径——Dijkstra(简易版)
    图的遍历——BFS(队列实现)
    图的遍历——DFS(邻接矩阵)
    图的创建——十字链表
    图的创建——邻接表法
    图的创建——邻接矩阵
    队列——链表实现
    队列——数组实现(循环队列)
  • 原文地址:https://www.cnblogs.com/yishaochu/p/5428709.html
Copyright © 2020-2023  润新知