带你实现开发者头条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有滑动效果,必须做到如下三点:
- CoordinatorLayout作为布局的父布局容器。
- 给需要滑动的组件设置 app:layout_scrollFlags=”scroll|enterAlways” 属性。
- 滑动的组件必须是AppBarLayout顶部组件。
- 给滑动的组件设置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包)的更多相关文章
- 带你实现开发者头条APP(三) 首页实现
title: 带你实现开发者头条APP(三) 首页实现 tags: 轮播广告,ViewPager切换,圆形图片 grammar_cjkRuby: true --- 一.前言 今天实现开发者头条APP的 ...
- 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载
title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...
- jq+swiper 实现今日头条App的选项卡效果
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- Selenium实战脚本集(4)--简单的开发者头条客户端
描述 去开发者头条抓取本日的top 10内容,也就是排在前面的10个,需要抓取标题和url 将这些内容保存在数据库,推荐使用sqlite 写个简单的客户端,要求可以展示每日的内容,点击标题后可以打开浏 ...
- 网站的优化----首页优化---app调取服务端数据
高并发经常会发生在有大活跃用户量来访问网站的某个点,例如用户高聚集的业务场景中,如:抢购,促销等.为了让用户流畅的访问网站,来根据自己的业务设计适合系统的处理方案. //对于APP网站首页数据,通常是 ...
- 独立的android开发者开发app如何盈利?
对立android开发者开发app如何盈利?android开发日益兴隆,随着google的大力推广和技术及其android培训的支持,android个人开发者或者android独立开发者也都匆匆欲动加 ...
- 「kuangbin带你飞」专题十四 数论基础
layout: post title: 「kuangbin带你飞」专题十四 数论基础 author: "luowentaoaa" catalog: true tags: mathj ...
- android仿今日头条App、多种漂亮加载效果、选择器汇总、记事本App、Kotlin开发等源码
Android精选源码 android漂亮的加载效果 android各种 选择器 汇总源码 Android仿bilibili搜索框效果 Android记事本app.分类,涂鸦.添加图片或者其他附件 仿 ...
- 今日头条- iOS客户端 启动速度优化实践
版权声明 作者:今日头条iOS团队 原文:https://techblog.toutiao.com/2017/01/17/iosspeed/ 应用启动时间,直接影响用户对一款应用的判断和使用体验.头条 ...
随机推荐
- 【探索】利用 canvas 实现数据压缩
前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...
- Partition:分区切换(Switch)
在SQL Server中,对超级大表做数据归档,使用select和delete命令是十分耗费CPU时间和Disk空间的,SQL Server必须记录相应数量的事务日志,而使用switch操作归档分区表 ...
- Android权限管理之RxPermission解决Android 6.0 适配问题
前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...
- MementoPattern(备忘录模式)
/** * 备忘录模式 * @author TMAC-J * 用于存储bean的状态 */ public class MementoPattern { public class Memento{ pr ...
- Android Studio快捷键
一.android studio 默认快捷键 刚开始接触一款开发软件,想必很想了解它的快捷方式,这会对你的编程起到很好的帮助,提高工作效率,接下来给你介绍下Android Studio一些常用的快 ...
- SQL Server常见问题介绍及快速解决建议
前言 本文旨在帮助SQL Server数据库的使用人员了解常见的问题,及快速解决这些问题.这些问题是数据库的常规管理问题,对于很多对数据库没有深入了解的朋友提供一个大概的常见问题框架. 下面一些问题是 ...
- 第六代智能英特尔® 酷睿™ 处理器图形 API 开发人员指南
欢迎查看第六代智能英特尔® 酷睿™ 处理器图形 API 开发人员指南,该处理器可为开发人员和最终用户提供领先的 CPU 和图形性能增强.各种新特性和功能以及显著提高的性能. 本指南旨在帮助软件开发人员 ...
- NYOJ 975
这道题一开始本着很朴素的想法就是先输入两头的数据,然后对每组的数据范围下测试中间的数据即可,但是是超时的.原因也很明显,比如计算1~1000的数据之后,假如下一组数据是1~1001,本来只需要多测试下 ...
- 用 eric6 与 PyQt5 实现python的极速GUI编程(系列04)---- PyQt5自带教程:地址簿(address book)
[引子] 在PyQt5自带教程中,地址簿(address book)程序没有完全实现界面与业务逻辑分离. 本文我打算用eric6+PyQt5对其进行改写,以实现界面与逻辑完全分离. [概览] 1.界面 ...
- ReactNative入门 —— 动画篇(下)
在上篇动画入门文章中我们了解了在 React Native 中简单的动画的实现方式,本篇将作为上篇的延续,介绍如何使用 Animated 实现一些比较复杂的动画. 动画组合 在 Animated 中提 ...