iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Android如何模仿实现微博详情页滑动固定顶部栏的效果
  • 669
分享到

Android如何模仿实现微博详情页滑动固定顶部栏的效果

android 2023-05-30 17:05:57 669人浏览 安东尼
摘要

这篇文章主要介绍了Android如何模仿实现微博详情页滑动固定顶部栏的效果,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。先来看下我们今天要实现的效果:滑动固定顶部栏效果图这段

这篇文章主要介绍了Android如何模仿实现微博详情页滑动固定顶部栏的效果,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

先来看下我们今天要实现的效果:

Android如何模仿实现微博详情页滑动固定顶部栏的效果
滑动固定顶部栏效果图

这段时间公司准备重构一个项目,刚好用到这个效果,我就顺带写了篇文章,关于这个效果网上可以找到一些相关资料的,昨晚看了一些,感觉都不是很好,有点模棱两可的样子,也没提到需要注意的一些关键点,这里来做下整理,由于涉及到公司的代码,这里我就写个简单的Demo来讲解。

Android如何模仿实现微博详情页滑动固定顶部栏的效果
简单Demo

传统套路:

写两个一模一样的固定栏,外层用帧布局(FrameLayout)包裹,然后把外层的固定栏先隐藏,当内层的固定栏滑动到外层固定栏位置的时候,把内层固定栏隐藏,外层的固定栏显示,反之滑回来的时候把外层固定栏隐藏,内存固定栏显示。

Android如何模仿实现微博详情页滑动固定顶部栏的效果
传统套路图

这样做的有几个不好的地方:

      1、重复写了一样的布局,在XML渲染的时候耗费了性能(比如更多次的测量,布局等)

      2、当页面快速滚动的时候可能出现一系列的问题(布局重复,闪烁)

      3、当这个固定布局带有状态的时候,逻辑会变得很复杂,比如上面那张GIF动图,固定栏中带有筛选分类,地区,年月信息,如果按照传统套路来写,那么在内层固定栏隐藏的时候需要把状态记录并且带给外层固定栏,而且相对应很多动作监听事件也需要写多次。

新套路:

这里我换了一种思路,大体布局还是不变的,只是把两个固定栏简化成了一个,只是利用removeView和addView根据坐标点在页面滑动的时候动态的把固定栏在内外部切换,这样做的好处很好的解决了上面提到的1、2点问题,当然在快速的removeView和addView还是会出现页面闪烁不自然的问题,后面会提到解决的小窍门。

先来看下XML布局:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="Http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.lcw.view.FixedHeaderScrollView.ObservableScrollView android:id="@+id/sv_contentView" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none" > <LinearLayout android:id="@+id/ll_contentView" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/tv_headerView" android:layout_width="match_parent" android:layout_height="200dp" android:text="我是头部布局" android:textSize="30sp" android:background="#ad29e1" android:gravity="center"/> <LinearLayout android:id="@+id/ll_topView" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:orientation="vertical"> <TextView  android:id="@+id/tv_topView"  android:layout_width="match_parent"  android:layout_height="50dp"  android:text="我是内层固定的布局"  android:background="#3be42f"  android:textSize="30sp"  android:gravity="center"/> </LinearLayout> <TextView android:id="@+id/tv_contentView" android:layout_width="match_parent" android:layout_height="1000dp" android:text="我是内容布局" android:textSize="30sp" android:background="#dc7f28" android:paddingTop="160dp" android:gravity="top|center_horizontal"/> </LinearLayout> </com.lcw.view.FixedHeaderScrollView.ObservableScrollView> <LinearLayout android:id="@+id/ll_fixedView" android:layout_width="match_parent" android:layout_height="50dp" android:orientation="vertical"/></FrameLayout>

这里和上面提到的一样,最外层用了FrameLayout(RelativeLayout也可以)包裹着一个ScrollView和一个LinearLayout,当我们页面滑动到指定点的时候,需要把内层的“我是内层固定布局”移除,同时添加到外层的ViewGroup(LinearLayout)中。

自定义ScrollView,利用回调接口的方式使滑动数据对外暴露:

虽然谷歌官方给ScrollView提供了一个设置滑动监听方法setOnScrollChangeListener,不过这个方法需要基于api23之上(Android6.0系统),在日常开发中,我们需要对老系统用户进行兼容(当前兼容版本为Android4.1系统以上),所以这里我们需要去继承ScrollView并把这个监听事件通过接口的方式对外暴露,这里把这个View取名为ObservableScrollView。

package com.lcw.view.FixedHeaderScrollView;import android.content.Context;import android.util.AttributeSet;import android.widget.ScrollView;public class ObservableScrollView extends ScrollView{ public ObservableScrollView(Context context) { this(context,null); } public ObservableScrollView(Context context, AttributeSet attrs) { this(context, attrs,0); } public ObservableScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private OnObservableScrollViewScrollChanged mOnObservableScrollViewScrollChanged; public void setOnObservableScrollViewScrollChanged(OnObservableScrollViewScrollChanged mOnObservableScrollViewScrollChanged) { this.mOnObservableScrollViewScrollChanged = mOnObservableScrollViewScrollChanged; } public interface OnObservableScrollViewScrollChanged{ void onObservableScrollViewScrollChanged(int l, int t, int oldl, int oldt); }  @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if(mOnObservableScrollViewScrollChanged!=null){ mOnObservableScrollViewScrollChanged.onObservableScrollViewScrollChanged(l,t,oldl,oldt); } }}

这里就可以开始写我们的调用类了

package com.lcw.view.FixedHeaderScrollView;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends AppCompatActivity implements ObservableScrollView.OnObservableScrollViewScrollChanged{ private ObservableScrollView sv_contentView; private LinearLayout ll_topView; private TextView tv_topView; private LinearLayout ll_fixedView; //用来记录内层固定布局到屏幕顶部的距离 private int mHeight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sv_contentView= (ObservableScrollView) findViewById(R.id.sv_contentView); ll_topView= (LinearLayout) findViewById(R.id.ll_topView); tv_topView= (TextView) findViewById(R.id.tv_topView); ll_fixedView= (LinearLayout) findViewById(R.id.ll_fixedView); sv_contentView.setOnObservableScrollViewScrollChanged(this);// ViewTreeObserver viewTreeObserver=ll_topView.getViewTreeObserver();// viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {// @Override// public void onGlobalLayout() {// ll_topView.getViewTreeObserver().removeOnGlobalLayoutListener(this);// mHeight=ll_topView.getTop();// }// }); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if(hasFocus){ //获取HeaderView的高度,当滑动大于等于这个高度的时候,需要把topView移除当前布局,放入到外层布局 mHeight=ll_topView.getTop(); } }  @Override public void onObservableScrollViewScrollChanged(int l, int t, int oldl, int oldt) { if(t>=mHeight){ if(tv_topView.getParent()!=ll_fixedView){  ll_topView.removeView(tv_topView);  ll_fixedView.addView(tv_topView); } }else{ if(tv_topView.getParent()!=ll_topView){  ll_fixedView.removeView(tv_topView);  ll_topView.addView(tv_topView); } } }}

这里我们实现了ObservableScrollView.OnObservableScrollViewScrollChanged接口,当我们对ScrollView注册监听的时候,就可以在回调接口里拿到对应的滑动数据,其中第二个参数t就是滑动y轴的距离,现在我们只需要拿到固定布局到顶部的距离就可以判断什么时候需要移除和添加View了。

相关讲解:

首先我们需要知道,在Activity生命周期里的onCreate方法里对一个View去执行getWidth,getHeight,getTop,getBottom等一系列的方法是拿不到数据的,得到的结果都为0,由于此时Activity还没有得到焦点,依附在Activity的View自然也就得不到数据,所以我们需要在onResume后去进行对View的数据获取。

这里我们可以通过onGlobalLayoutListener或者onWidnowFocusChanged等方法去获取,这里的执行顺序是:Activity.onCreate->Activity.onResume->View.onMeasure->View.onLayout->onGlobalLayoutListener->Activity.onWidnowFocusChanged..(具体用哪个,看当前环境情况,比如在Fragment里是没有onWidnowFocusChanged,如果需要获取一个View的相关数据,就可以根据onGlobalLayoutListener来做,上面代码提供两种示例)

关于获取滑动的高度,首先我们来看一张图:

Android如何模仿实现微博详情页滑动固定顶部栏的效果 

Andorid里关于View的坐标系

这里需要注意的是,除了getRawX和getRawY是相对屏幕的位置,其他的是相对应所在父布局的位置,所以在确定数据的时候,需要注意布局的嵌套。

当我们拿到所需要滑动的高度时,我们需要对固定布局进行临界值做判断(这里设当前滑动值为t,所需滑动值为y)
比如当我们界面一开始向上滑的时候t值是小于y值的,此时内部固定栏是不需要移除的,而当我们超过y值往回滑t值又小于y值的时候,此时内部固定栏是需要从外部移除添加到内部的,所以这里我们需要对固定栏所在的父布局(ViewGroup)做判断。

最后补充:

Android如何模仿实现微博详情页滑动固定顶部栏的效果
微博详情页

不管你的顶部固定栏布局多简单,建议在外套一层ViewGroup,这样方便addView的操作,不然需要去控制外层ViewGroup的addView的index位置。

确定View的宽高度数据可以借助onGlobalLayoutListener或者onWidnowFocusChanged来做,注意相对父布局的嵌套。

这种页面的设计最早来源于iOS的设计,在iOS里ScrollView嵌套TableView(相当于ListView)是没有问题的,但是在Android里,这样子的嵌套会导致ListView的复用机制作废,也就是会不断是去进行onMeasure的计算,执行多次Adapter里的getView,也就意味着多次的findViewById,使得ViewHolder失效。

这是个小技巧,在快速滑动的时候有些人会出现固定布局的闪烁,其实这个和removeView和addView有关系,如果你的ViewGroup设置成了warp_content,这是一个测量的耗时操作,这里只需要配合上面提到的第1点,给固定栏外层布局一个固定的高度值即可(与固定栏高度保持一致)。

感谢你能够认真阅读完这篇文章,希望小编分享的“Android如何模仿实现微博详情页滑动固定顶部栏的效果”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网精选频道,更多相关知识等着你来学习!

--结束END--

本文标题: Android如何模仿实现微博详情页滑动固定顶部栏的效果

本文链接: https://www.lsjlt.com/news/220122.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android如何模仿实现微博详情页滑动固定顶部栏的效果
    这篇文章主要介绍了Android如何模仿实现微博详情页滑动固定顶部栏的效果,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。先来看下我们今天要实现的效果:滑动固定顶部栏效果图这段...
    99+
    2023-05-30
    android
  • Android实现简单底部导航栏 Android仿微信滑动切换效果
    Android仿微信滑动切换最终实现效果:大体思路: 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标;2. 底部导航栏的设置方法类似于TabLayout的关联,View...
    99+
    2023-05-30
    android 导航栏
  • vue+jquery+lodash如何实现滑动时顶部悬浮固定效果
    这篇文章给大家分享的是有关vue+jquery+lodash如何实现滑动时顶部悬浮固定效果的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。这个效果是一个项目中抽出来的一个demo效...
    99+
    2024-04-02
  • 微信小程序如何实现顶部导航栏滑动tab效果
    这篇文章将为大家详细讲解有关微信小程序如何实现顶部导航栏滑动tab效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体内容如下效果图:首先是滑动的效果:<scro...
    99+
    2024-04-02
  • Android view如何实现滑动悬浮固定效果
    这篇文章主要介绍了Android view如何实现滑动悬浮固定效果,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.背景在项目开发过程中,有时候会碰到这样的需求:在滑动的过程...
    99+
    2023-05-30
    android
  • 微信小程序如何自定义可滑动顶部TabBar选项卡实现页面切换功能
    这篇文章主要介绍微信小程序如何自定义可滑动顶部TabBar选项卡实现页面切换功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体如下:顶部滚动选项卡话不多说,直接上代码pages/...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作