转载请标明出处:http://blog.csdn.net/qizhenghao/article/details/66975485

仿微博、人人的feed详情页面:Listview上下滑动,导航栏view可吸附在顶部的效果。

一、实现效果

上图:

Github: https://github.com/qizhenghao/StickyNavigationBar

欢迎拍砖,拍拍更进步。

没有对比,怎么会有伤害,下面是 微博、人人的Feed详情页:

二、实现原理

1、

实例化两个一样的导航栏view,一个放在页面根布局顶部的view1,另一个放在ListView的headerView中的view2,在OnScrollListener的onScroll方法中,检测view2在屏幕中的位置是不是滑动到了顶部,决定顶部view1的显示与隐藏,以达到看起来只有一个导航栏view显示的效果;

2、

为了保持两个导航栏view的状态同步,使用了观察者模式;

3、

导航栏中的Tab切换,即切换ListView的adapter,并且记录滑动的位置信息。


三、UML图


StickyNavHostSubject:它把所有的自定义导航栏view的引用保存到一个list里。AbstractSubject提供了接口,可以增加和删除观察者对象。

StickyNavHost:自定义的导航栏view,继承自ViewGroup,可以根据具体需求自行更改显示的布局、样式等。

NavListViewScollListener:需要为ListView设置的滑动事件,封装了对吸附导航栏显示、隐藏的逻辑。

MainActivity:用于演示demo,包含了对导航栏view的初始化,以及切换tab的操作等。


三、具体细节

1、

NavListViewScollListener的onScroll()方法:

@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {//处理了root导航栏的显示与隐藏, 本质上只是控制root导航栏的显示//而在listView的headerView中的导航栏不做处理,因为它会随着listView的滑动自行滑出页面if (NavBean.IS_NEED_ATTACH && rootView != null && nav != null) {rootView.getLocationOnScreen(rootLocation);headView.getLocationOnScreen(headLocation);//根据两者在屏幕中的location位置信息,决定root导航栏的显示与隐藏if (rootLocation[1] > headLocation[1]) {rootView.setVisibility(View.VISIBLE);} else {rootView.setVisibility(View.INVISIBLE);}//记录当前listView的滑动位置nav.setFirstVisibleItem(firstVisibleItem);nav.setTopDistance((view.getChildAt(0) == null) ? 0 : view.getChildAt(0).getTop());}}
2、

MainActivity中初始化操作:

    private void initNavsView() {initNavsData();stickyNavHostRoot.setTabItemClickListener(this);//设置点击回调stickyNavHostHead.setTabItemClickListener(this);//设置点击回调stickyNavHostRoot.setShowTopLine(false);stickNavHostSubject = new StickNavHostSubject();stickNavHostSubject.attachObserver(stickyNavHostRoot);//观察者模式stickNavHostSubject.attachObserver(stickyNavHostHead);NavBean[] sortedNavs = new NavBean[mNavs.size()];//指定导航栏的排列顺序sortedNavs[0] = mNavs.get(NavBean.TYPE_REPOST);sortedNavs[1] = mNavs.get(NavBean.TYPE_COMMENT);sortedNavs[2] = mNavs.get(NavBean.TYPE_LIKE);stickNavHostSubject.initTabData(sortedNavs);scrollListener = new NavListViewScrollListener(stickyNavHostRoot, stickyNavHostHead);mListView.setOnScrollListener(scrollListener);//为listView设置滑动监听,内部处理了吸附view的显示与隐藏}protected void initNavsData() {mNavs = new SparseArray<>(NAV_LENGTH);mNavs.put(NavBean.TYPE_REPOST, new NavBean(NavBean.TYPE_REPOST, new TestAdapter(20, "我是转发", this)));mNavs.put(NavBean.TYPE_COMMENT, new NavBean(NavBean.TYPE_COMMENT, new TestAdapter(20, "我是评论", this)));mNavs.put(NavBean.TYPE_LIKE, new NavBean(NavBean.TYPE_LIKE, new TestAdapter(20, "我是赞", this)));}private void initView() {mListView = (ListView) findViewById(R.id.list_view);stickyNavHostRoot = (StickyNavHost) findViewById(R.id.sticky_nav_layout);stickyNavHostRoot.setVisibility(View.INVISIBLE);View testHeaderView = LayoutInflater.from(this).inflate(R.layout.listview_head_view_test_layout, null);mListView.addHeaderView(testHeaderView);View inflateView = LayoutInflater.from(this).inflate(R.layout.sticky_nav_host_layout, null);stickyNavHostHead = (StickyNavHost) inflateView.findViewById(R.id.sticky_nav_layout);stickyNavHostHead.setVisibility(View.VISIBLE);mListView.addHeaderView(stickyNavHostHead);STICKY_POSITION_IN_HEADER = mListView.getHeaderViewsCount();}
3、

MainActivity中点击切换导航栏Tab的回调:

    @Overridepublic void onTabItemSelected(@NavBean.TYPE int type) {NavBean currNav = mNavs.get(type);stickNavHostSubject.setSelectedType(type);//事件分发给注册者,注册者进行相应的变化if (currNav.type == NavBean.TYPE_CURRENT)//等于当前选中的tab,可以屏蔽掉return;NavBean.TYPE_CURRENT = currNav.type;scrollListener.setNav(currNav);mListView.setAdapter(currNav.adapter);if (stickyNavHostRoot.getVisibility() == View.VISIBLE) {//吸附在顶部的rootView正在展示if (currNav.getFirstVisibleItem() < STICKY_POSITION_IN_HEADER)mListView.setSelectionFromTop(STICKY_POSITION_IN_HEADER, stickyNavHostRoot.getHeight() - 2);elsemListView.setSelectionFromTop(currNav.getFirstVisibleItem(), currNav.getTopDistance());} else {//吸附在顶部的rootView没有展示,说明在切换导航栏的时候是不需要进行滑动的,保持上次的位置即可mListView.setSelectionFromTop(NavBean.firstVisibleItemUniversal, NavBean.topDistanceUniversal);}}
4、

StickyNavHostSubject做的事情就很简单了,和常见的观察者模式没区别:

public class StickNavHostSubject extends AbstractSubject<IStickyNavHostObserver> {private List<IStickyNavHostObserver> observers;public StickNavHostSubject() {observers = new ArrayList<>();}public void attachObserver(IStickyNavHostObserver observer) {observers.add(observer);}public void detachObserver(IStickyNavHostObserver observer) {observers.remove(observer);}@Overridepublic void initTabData(NavBean[] navs) {for (IStickyNavHostObserver observer : observers)observer.initTabData(navs);}@Overridepublic void refreshTabData(NavBean nav) {for (IStickyNavHostObserver observer : observers)observer.refreshTabData(nav);}@Overridepublic void setSelectedType(@NavBean.TYPE int type) {for (IStickyNavHostObserver observer : observers)observer.setSelectedType(type);}@Overridepublic void setSelectedPosition(int position) {for (IStickyNavHostObserver observer : observers)observer.setSelectedPosition(position);}

Android仿微博、人人Feed详情页吸附导航栏相关推荐

  1. android吸附菜单,Android仿微博、人人Feed详情页吸附导航栏

    仿微博.人人的feed详情页面:Listview上下滑动,导航栏view可吸附在顶部的效果. 一.实现效果 上图: 效果图.gif 欢迎拍砖,拍拍更进步. 没有对比,怎么会有伤害,下面是 微博.人人的 ...

  2. Android 仿淘宝商品详情页下拉足迹Demo

    DropDownMultiPager 仿淘宝等商品详情页下拉足迹效果SimpleDemo 可colne之后看MainActivity的调用,方便二次开发 依赖 compile 'com.nineold ...

  3. 【商城开发三】Android 仿淘宝商品详情页下拉足迹修改版

    开发商城的快有半个月了,需要做到详情页下拉足迹的效果,网上找了找没找到,找到一个差不多还有点问题,然后在基础上进行了二次开发 感谢http://blog.csdn.net/yaphetzhao/art ...

  4. Android仿微信底部菜单栏+今日头条顶部导航栏

    背景 Android应用几乎都会用到底部菜单栏,在Material Design还没有出来之前,TabHost等技术一直占主流,现在Google新sdk中提供了TabLayout类可以便捷的做出底部菜 ...

  5. android 网易item广告,Android仿网易严选商品详情页

    仿照网易严选商品详情页面,整个页面分为两个部分,上面一部分是Native的ScrollView,下面一部分则是WebView,其目的是为了可以进行分步加载.滑动到ScrollView底部时,继续向上拖 ...

  6. android 美团商家详情页,Android仿美团团购详情页下拉图片放大效果,简单可直接用在项目中...

    一:介绍 大家在项目中,可能需要像美团团购详情页面下拉的时候美食图片放大的效果,在这里就给大家介绍如何实现这种效果,只有很少的代码,而且控件全部是安卓源生控件. 二:运行效果图 三.然后来看看如何实现 ...

  7. Android 仿当乐游戏详情页面(二)

    写在前面 在上一篇文章里面,基本上算是实现了该效果的布局,有了布局,接下来就要对布局进行移动处理. android 仿当乐游戏详情页面(一) 对于移动的分析 通过第一篇文章的分析,在所有控件里面,能移 ...

  8. Android 仿微信小程序开屏页加载loading

    Android 仿微信小程序开屏页加载loading 废话不多说,先上效果图~ 首先就是底层有一个灰色的圆,然后按照圆形的轨迹进行绘制. 啊~说那么多也没用,还是直接上代码吧,哈哈哈哈 绘制底部圆形及 ...

  9. [Android]仿京东手机端类别页

    [Android]仿京东手机端类别页 京东手机端的类别标签页, 是一个左侧滑动可选择类别, 右侧一个类别明细的列表联动页面. 当用户选择左侧选项, 可在右侧显示更多选项来选择. 实现方式也不少. 最常 ...

最新文章

  1. 省选专练[CQOI2007]涂色
  2. Ubuntu下利用JDK的Keytool配置Tomcat7.0的SSL协议(单向认证简易版)
  3. python数据科学实践指南_《Python数据科学实践指南》——导读-阿里云开发者社区...
  4. Java演示手机发送短信验证码功能实现
  5. Spring框架–应用程序上下文–到达应用程序上下文的三种方法
  6. 烂泥:通过vsphere给esxi添加本地硬盘
  7. 客户机服务器文件更新,服务端数据更新,如何更新客户端缓存
  8. Java讲课笔记07:计数循环与嵌套循环
  9. 【算法】剑指 Offer 47. 礼物的最大价值
  10. 【广告技术】隐私集合交集运算结合同态加密,在保障数据安全的同时追踪广告效果
  11. MySQL常见问题及解决方案
  12. 传输层协议(12):拥塞控制(1)
  13. python中的作用域_python中作用域
  14. 【Jectpack】DataStore
  15. oracle所有分区表分区,Oracle分区表及分区目录
  16. 宇宙机器人超级计算机,宇宙机器人无线控制器使用指南白金攻略
  17. OpenTCS打造移动机器人交通管制系统(四)
  18. java菜鸟mysql_十面阿里,菜鸟,天猫,蚂蚁金服面试精选73题:Java+Spring+MySQL+JVM.......
  19. 生产制造追溯系统-再说条码打印
  20. 游戏网络同步——MMO位置同步

热门文章

  1. 用win-acme生成免费的泛域名证书,域名使用的阿里云
  2. 初识web安全2--被动攻击与同源策略
  3. 魅族手机root办法
  4. 苹果iCloud的同步机制
  5. 【WORD】02 图片自动编号
  6. 2021年天猫淘宝双十一预售便宜还是当天便宜?
  7. KDDCUP99数据集处理(Keras)
  8. 拖拽效果遇到的问题及解决方案
  9. Pandas 04-分组
  10. 在Centos7.X版本下的UsbEAm LAN Party的自定义节点部署