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 - 安卓开发技术分享
扫描二维码加关注

带你实现开发者头条APP(四)---首页优化(加入design包)的更多相关文章

  1. 带你实现开发者头条APP(三) 首页实现

    title: 带你实现开发者头条APP(三) 首页实现 tags: 轮播广告,ViewPager切换,圆形图片 grammar_cjkRuby: true --- 一.前言 今天实现开发者头条APP的 ...

  2. 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载

    title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...

  3. jq+swiper 实现今日头条App的选项卡效果

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  4. Selenium实战脚本集(4)--简单的开发者头条客户端

    描述 去开发者头条抓取本日的top 10内容,也就是排在前面的10个,需要抓取标题和url 将这些内容保存在数据库,推荐使用sqlite 写个简单的客户端,要求可以展示每日的内容,点击标题后可以打开浏 ...

  5. 网站的优化----首页优化---app调取服务端数据

    高并发经常会发生在有大活跃用户量来访问网站的某个点,例如用户高聚集的业务场景中,如:抢购,促销等.为了让用户流畅的访问网站,来根据自己的业务设计适合系统的处理方案. //对于APP网站首页数据,通常是 ...

  6. 独立的android开发者开发app如何盈利?

    对立android开发者开发app如何盈利?android开发日益兴隆,随着google的大力推广和技术及其android培训的支持,android个人开发者或者android独立开发者也都匆匆欲动加 ...

  7. 「kuangbin带你飞」专题十四 数论基础

    layout: post title: 「kuangbin带你飞」专题十四 数论基础 author: "luowentaoaa" catalog: true tags: mathj ...

  8. android仿今日头条App、多种漂亮加载效果、选择器汇总、记事本App、Kotlin开发等源码

    Android精选源码 android漂亮的加载效果 android各种 选择器 汇总源码 Android仿bilibili搜索框效果 Android记事本app.分类,涂鸦.添加图片或者其他附件 仿 ...

  9. 今日头条- iOS客户端 启动速度优化实践

    版权声明 作者:今日头条iOS团队 原文:https://techblog.toutiao.com/2017/01/17/iosspeed/ 应用启动时间,直接影响用户对一款应用的判断和使用体验.头条 ...

随机推荐

  1. .NET Core系列 :4 测试

    2016.6.27 微软已经正式发布了.NET Core 1.0 RTM,但是工具链还是预览版,同样的大量的开源测试库也都是至少发布了Alpha测试版支持.NET Core, 这篇文章 The Sta ...

  2. 跟我一起云计算(5)——Shards

    什么是sharding Sharding的基本思想就要把一个数据库切分成多个部分放到不同的数据库 (server)上,从而缓解单一数据库的性能问题.不太严格的讲,对于海量数据的数据库,如果是因为表多而 ...

  3. HashSet HashTable 与 TreeSet

    HashSet<T>类 HashSet<T>类主要是设计用来做高性能集运算的,例如对两个集合求交集.并集.差集等.集合中包含一组不重复出现且无特性顺序的元素. HashSet& ...

  4. nodejs中获取时间戳、时间差

    Nodejs中获取时间戳的方法有很多种,例如: new Date().getTime() Date.now() process.uptime() process.hrtime() 平时想获取一个时间戳 ...

  5. MVC CodeFirst简单的创建数据库(非常详细的步骤)

       最近在学习MVC的开发,相信有过开发经验的人初学一个新的框架时候的想法跟我一样最关心的就是这个框架如何架构,每个架构如何分工,以及最最关键的就是如何与数据库通信,再下来才是学习基础的页面设计啊等 ...

  6. 程序员必须要知道的Hadoop的一些事实

    程序员必须要知道的Hadoop的一些事实.现如今,Apache Hadoop已经无人不知无人不晓.当年雅虎搜索工程师Doug Cutting开发出这个用以创建分布式计算机环境的开源软...... 1: ...

  7. FILE文件流的中fopen、fread、fseek、fclose的使用

    FILE文件流用于对文件的快速操作,主要的操作函数有fopen.fseek.fread.fclose,在对文件结构比较清楚时使用这几个函数会比较快捷的得到文件中具体位置的数据,提取对我们有用的信息,满 ...

  8. linux下配置matlab运行环境(MCR)

    在安装好的matlab下有MCR(MatlabCompilerRuntime)在matlab2011/toolbox/compiler/deploy/glnxa64下找到MCRInstaller.zi ...

  9. fhq treap最终模板

    新学习了fhq treap,厉害了 先贴个神犇的版, from memphis /* Treap[Merge,Split] by Memphis */ #include<cstdio> # ...

  10. ENode简介与各种教学视频资源汇总(要进群这篇文章必看)

    ENode是什么 ENode是一个.NET平台开源的应用开发框架,为开发人员提供了一套完整的基于DDD+CQRS+ES+(in-memory)+EDA架构风格的解决方案. ENode的特色是什么 解决 ...