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

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

一、实现效果

上图:

7fe153e8d237

效果图.gif

欢迎拍砖,拍拍更进步。

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

7fe153e8d237

微博、人人Feed详情页.jpeg

二、实现原理

1、

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

2、

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

3、

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

三、UML图

7fe153e8d237

UML图.png

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

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

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

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

三、具体细节

1、

NavListViewScollListener的onScroll()方法:

@Override

public 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的回调:

@Override

public 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);

else

mListView.setSelectionFromTop(currNav.getFirstVisibleItem(), currNav.getTopDistance());

} else {//吸附在顶部的rootView没有展示,说明在切换导航栏的时候是不需要进行滑动的,保持上次的位置即可

mListView.setSelectionFromTop(NavBean.firstVisibleItemUniversal, NavBean.topDistanceUniversal);

}

}

4、

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

public class StickNavHostSubject extends AbstractSubject {

private List observers;

public StickNavHostSubject() {

observers = new ArrayList<>();

}

public void attachObserver(IStickyNavHostObserver observer) {

observers.add(observer);

}

public void detachObserver(IStickyNavHostObserver observer) {

observers.remove(observer);

}

@Override

public void initTabData(NavBean[] navs) {

for (IStickyNavHostObserver observer : observers)

observer.initTabData(navs);

}

@Override

public void refreshTabData(NavBean nav) {

for (IStickyNavHostObserver observer : observers)

observer.refreshTabData(nav);

}

@Override

public void setSelectedType(@NavBean.TYPE int type) {

for (IStickyNavHostObserver observer : observers)

observer.setSelectedType(type);

}

@Override

public void setSelectedPosition(int position) {

for (IStickyNavHostObserver observer : observers)

observer.setSelectedPosition(position);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/441259.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android 居右属性,使用layoutDirection属性设置布局靠左或靠右

通过设置layoutDirection属性值为mx.core.LayoutDirection.RTL(右到左)或mx.core.LayoutDirection.LTR(左到右)&#xff0c;使布局为靠左或靠右(如下图)。该属性可设置3种值&#xff0c;LayoutDirection.RTL、LayoutDirection.LTR和null(ILayoutDirectionElement时)/undefined(…

html表格全屏显示,tableView滑动全屏显示

今天要分享的一个效果是在一个页面弹出视图展示一个tableview&#xff0c;然后手指滑动tableview时&#xff0c;视图随着tableview偏移量增加而慢慢增加&#xff0c;到达临界时&#xff0c;全屏显示&#xff0c;然后再次向下滑动时&#xff0c;当偏移量到达临界点&#xff0c;视…

大量html乱码seo,HTTPS改造之后网页错位乱码,影响SEO和正常访问,应该这样改

有一些朋友可能不太知道https改造怎么做&#xff0c;就学着网站的步骤进行&#xff0c;实际操作过程中可能会遇到很多问题。比如说有的会出现网页错位、页面乱码、后台功能无法使用的情况。昨天我们就有一个客户他自己做了https改造&#xff0c;但是造成后台无法上传图片的情况…

微型计算机中最小的单位,微型计算机中最小的数据单位是

微型计算机中最小的数据单位是比特。微型计算机&#xff0c;是指由微处理器作为CPU的计算机。由大规模集成电路组成的、体积较小的电子计算机。由微处理机(核心)、存储片、输入和输出片、系统总线等组成。特点是体积小、灵活性大、价格便宜、使用方便。这类计算机的普遍特征就是…

琴生不等式一般形式_001.二次函数、方程和不等式知识点

学法指导&#xff1a;本专题讲授不等式内容&#xff0c;这部分内容是学生的难点&#xff0c;为此有几点说明&#xff1a;1.把握好学习的难度。按教材内不等式部分展现的内容看&#xff0c;它很简单&#xff0c;但学过的知道&#xff0c;这部分内容很难&#xff0c;直白的讲&…

伺服电机停的时候会冲一下_造成伺服电机抖动的原因竟然是它!内附解决方法...

伺服电机(servo motor )是指在伺服系统中控制机械元件运转的发动机&#xff0c;是一种补助马达间接变速装置。它可使控制速度&#xff0c;位置精度非常准确&#xff0c;可以将电压信号转化为转矩和转速以驱动控制对象。伺服电机转子转速受输入信号控制&#xff0c;并能快速反应…

【 HDU - 5363】Key Set(水题,快速幂,组合数学)

题干&#xff1a; soda has a set SS with nn integers {1,2,…,n}{1,2,…,n}. A set is called key set if the sum of integers in the set is an even number. He wants to know how many nonempty subsets of SS are key set. Input There are multiple test cases. The…

ajax 更新模型数据_DuangDuangDuang,重点来啦!高薪全靠它——百战Web前端课程更新03.11...

百战程序员九大专业运营&#xff0c;周周有课程更新&#xff0c;保持行业领先。本次更新课程Web前端第三十阶段经典面试题解析章节1—5及课程资料。本次更新可谓是诚意满满&#xff0c;针对市场面试需要&#xff0c;总结经典面试题集&#xff0c;为你揭开企业技术要求的神秘面纱…

combox 增加请选择_娱乐测试:选择四种花束中的一种,测试你对婚姻的看法

阅读本文前&#xff0c;请您先点击上面的“落落天使”&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到文章了。每天都有分享&#xff0c;完全是免费订阅&#xff0c;请放心关注。 …

计算机突然断电恢复供电后,电脑突然断电的坏处有哪些?

对于经常使用计算机进行办公的用户而言&#xff0c;最可怕的事情是计算机在保存文件之前突然断电关机。但是&#xff0c;这对于计算机本身根本不是问题&#xff0c;只要计算机能够正常运行。但是&#xff0c;如果断电导致以下任何一种情况&#xff0c;则需要小心&#xff01;1、…

手游 自建服务器,英灵神殿自己搭建服务器怎么弄

英灵神殿是一款冒险生存类游戏&#xff0c;在英灵神殿游戏中小伙伴要自己搭建服务器才能玩&#xff0c;那么要怎么搭建&#xff0c;有什么技巧吗?接下来和小编一起来看看吧!Valheim英灵神殿服务器搭建技巧第一步&#xff1a;SteamCMD和安装内容从这里下载SteamCMD。将其提取到…

【POJ - 1463】Strategic game (树上最小点覆盖,树形dp)

题干&#xff1a; Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad. Now he has the following problem. He must defend a medieval city, the roads of which form a tree…

恐怖黎明稳定服务器,恐怖黎明新人联机图文教程 怎么联机-游侠网

恐怖黎明怎么联机?不少玩家想体验联机&#xff0c;但是不知道方法&#xff0c;小编这里给大家带来了新人联机图文教程&#xff0c;不会的萌新来学习下吧。联机图文教程:A1 联机&#xff1a;因为gd(grimdawn)没有自己的战网平台(就是专供联机玩的专职服务器 server)&#xff0c…

github 上传代码_leetcode爬虫:爬取代码;生成readme;上传github

Leetcode-Helper哪个程序员 不想一键下写过的代码&#xff0c;自动上传Github&#xff0c;并且还能生成好看的README呢&#xff1f;有用的话点个⭐吧&#xff0c;谢谢你。Leetcode-Helper传送门​github.com主要功能 模拟登陆力扣中国站(leetcode-cn)爬取每题提交的ac代码&…

绝地求生信号枪只能在服务器吗,绝地求生信号枪怎么用?信号枪刷新点及用法详解...

绝地求生信号枪怎么用&#xff1f;信号枪刷新点及用法详解2018-03-15 15:22:12来源&#xff1a;吃鸡小助手编辑&#xff1a;野狐禅评论(0)绝地求生近日更新中悄悄加入了信号枪&#xff0c;引得广大玩家热情满满的在游戏中寻找&#xff0c;信号枪到底怎么用呢&#xff1f;下面就…

文件服务器共享文件夹访问权限,5对文件服务器中的共享文件夹进行访问权限控制...

对文件服务器中的共享文件夹进行访问权限控制1. 实训目的在Windows Server 2003环境下设置文件服务器的目的是要对多用户进行资源共享&#xff0c;这其中经常遇到不同用户应该分配不同权限的问题&#xff0c;通过这个实训希望读者了解Windows Server 2003中访问权限设置方法和具…

渲染服务器位置,如何用服务器做渲染

如何用服务器做渲染 内容精选换一换&#xfffd;&#xfffd;&#xfffd;&#xfffd;BoostKit ARMԭ&#xfffd;&#xfffd;ʹ&#xfffd;&#xfffd;&#xfffd;׼&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;嵥&#xfffd;&#xfffd…

【HDU - 2376】Average distance (树,平均距离,算贡献)

题干&#xff1a; Given a tree, calculate the average distance between two vertices in the tree. For example, the average distance between two vertices in the following tree is (d 01 d 02 d 03 d 04 d 12 d 13 d 14 d 23 d 24 d 34)/10 (63799131510122)/10…

两台虚拟服务器如何级联,[教程] 利用open vswitch建立vxlan隧道实现不同主机上的虚拟交换机级联...

写在开头在某些环境下&#xff0c;需要实现两台物理机中的openvswitch交换机级联&#xff0c;以实现两台交换机中的设备互相通讯&#xff0c;这里使用vxlan隧道技术&#xff0c;将数据包封装在UDP中&#xff0c;通过以太网实现数据包传输。VXLAN是一种大二层的虚拟技术&#xf…

华为虚拟服务器lanip地址,2018软考网络工程师《华为基础实验》十九配置路由器为DHCPServer...

原标题&#xff1a;2018软考网络工程师《华为基础实验》十九配置路由器为DHCPServer实验要求:在R1上使能DHCP 功能。创建三个全局地址池&#xff0c;用于为三个不同部门的PC分配IP 地址。配置地址池的相关属性。在R1的接口下配置基于全局地址池的服务方式&#xff0c;实现DHCP …