粘性头部效果的实现

Android 从零开始实现RecyclerView分组及粘性头部效果,《Android面试题及解析》分享给大家 groupList.add(groupItem); } @Override public void buildGroupView(View groupView, GroupItem groupItem) { //构建groupView,通过groupView.findViewById找到内部控件(暂不支持点击事件等),例如 TextView textName = (TextView) groupView.findViewById(R.id.text_name); textName.setText(group 阅读详情

现在app很多有粘性头部的效果,网上搜了下实现方法,发现大同小异,大部分都是根据recyclerview的itemdecoration来实现。我在做这个功能的时候可能没有这么麻烦,直接根据recyclerview的滑动监听来实现这个效果的,好了,先看图:

 

一、实现布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="@dimen/statusbar_view_height"
        android:background="@color/gray_f2f2f2" />

    <com.aspsine.swipetoloadlayout.SwipeToLoadLayout
        android:id="@+id/swipeToLoadLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:descendantFocusability="blocksDescendants"
        android:overScrollMode="never"
        app:default_to_loading_more_scrolling_duration="500"
        app:load_more_complete_delay_duration="0"
        app:load_more_final_drag_offset="@dimen/load_more_final_offset_google"
        app:load_more_trigger_offset="@dimen/load_more_trigger_offset_google"
        app:refresh_final_drag_offset="@dimen/refresh_final_offset_google"
        app:refresh_trigger_offset="@dimen/refresh_trigger_offset_google"
        app:swipe_style="blew">

        <include
            android:id="@id/swipe_refresh_header"
            layout="@layout/layout_refresh_header" />

        <android.support.v7.widget.RecyclerView
            android:id="@id/swipe_target"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:overScrollMode="never" />

        <include
            android:id="@id/swipe_load_more_footer"
            layout="@layout/layout_refresh_footer" />

    </com.aspsine.swipetoloadlayout.SwipeToLoadLayout>
    
    <!-- 标题栏布局 -->
    <include layout="@layout/item_autotrophy_title_bar" />

    <!-- 筛选栏 -->
    <include layout="@layout/item_autotrophy_type" />

</RelativeLayout>

标题栏布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_bg"
    android:layout_width="match_parent"
    android:layout_height="@dimen/home_banner_det"
    android:layout_below="@id/tv"
    android:layout_marginTop="-1.5dp"
    android:background="@color/white_ffffff"
    android:orientation="horizontal">

    <LinearLayout
        android:id="@+id/ll_back"
        android:layout_width="44dp"
        android:layout_height="44dp"
        android:gravity="center_vertical|left"
        android:paddingBottom="10dp"
        android:paddingTop="10dp">

        <ImageView
            android:id="@+id/iv_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:src="@drawable/back_gray" />
    </LinearLayout>

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_marginRight="44dp"
        android:layout_weight="1"
        android:gravity="center"
        android:text=""
        android:textColor="@color/gray_333333"
        android:textSize="16sp" />

</LinearLayout>

筛选栏布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_title_type"
    android:layout_width="match_parent"
    android:layout_height="@dimen/autotrophy_type_height"
    android:layout_marginTop="@dimen/autotrophy_height"
    android:background="@color/white_ffffff"
    android:orientation="vertical">

    <View
        android:id="@+id/view_line"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_alignParentBottom="true"
        android:background="@color/gray_dcdcdc" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal">

        <LinearLayout
            android:id="@+id/ll_autotrophy_price"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/iv_sort_price"
                style="@style/sort_icon_style" />

            <TextView
                android:id="@+id/tv_autotrophy_price"
                style="@style/autotrohpy_text"
                android:text="按价格" />

            <ImageView
                android:id="@+id/iv_autotrophy_price"
                style="@style/autotrophy_imageview"
                android:src="@drawable/autotrofy_bottom" />

        </LinearLayout>

        <View style="@style/view_height" />

        <LinearLayout
            android:id="@+id/ll_autotrophy_by_sales"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/iv_sort_sales"
                style="@style/sort_icon_style" />

            <TextView
                android:id="@+id/tv_autotrophy_by_sales"
                style="@style/autotrohpy_text"
                android:text="按销量" />

            <ImageView
                android:id="@+id/iv_autotrophy_by_sales"
                style="@style/autotrophy_imageview"
                android:src="@drawable/autotrofy_bottom" />

        </LinearLayout>

        <View style="@style/view_height" />

        <LinearLayout
            android:id="@+id/ll_autotrophy_by_star"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/iv_sort_star"
                style="@style/sort_icon_style" />

            <TextView
                android:id="@+id/tv_autotrophy_by_star"
                style="@style/autotrohpy_text"
                android:text="按评分" />

            <ImageView
                android:id="@+id/iv_autotrophy_by_star"
                style="@style/autotrophy_imageview"
                android:src="@drawable/autotrofy_bottom" />

        </LinearLayout>

        <View style="@style/view_height" />

        <LinearLayout
            android:id="@+id/ll_autotrophy_by_rent"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1.2"
            android:gravity="center"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tv_autotrophy_by_rent"
                style="@style/autotrohpy_text"
                android:text="出租类型" />

            <ImageView
                android:id="@+id/iv_autotrophy_by_rent"
                style="@style/autotrophy_imageview"
                android:src="@drawable/autotrofy_bottom" />

        </LinearLayout>
    </LinearLayout>

    <View
        style="@style/ViewStyle"
        android:background="@color/gray_dcdcdc" />


</LinearLayout>

二、标题栏透明度的滑动变化

首先得默认标题栏的透明度为0,添加代码:

/**
     * 设置标题栏背景透明度
     *
     * @param alpha 透明度
     */
    private void setSystemBarAlpha(int alpha) {
//        if (alpha >= 125) {
//            alpha = 125;
//        } else {
        //标题栏渐变。a:alpha透明度 r:红 g:绿 b蓝
//        titlebar.setBackgroundColor(Color.rgb(57, 174, 255));//没有透明效果
//        titlebar.setBackgroundColor(Color.argb(alpha, 57, 174, 255));//透明效果是由参数1决定的,透明范围[0,255]
//        titlebar.getBackground().setAlpha(alpha);
        llBg.setBackgroundColor(Color.argb(alpha, 255, 255, 255));
        viewLine.setBackgroundColor(Color.argb(alpha, 220, 220, 220));
        tvTitle.setTextColor(Color.argb(alpha, 51, 51, 51));
//        }
    }

然后就可以设置recyclerview的滑动监听方法addOnScrollListener(),来进行透明度的变化。

在onScrolled()方法中做透明度变化的操作:

LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                int firstPosition = layoutManager.findFirstVisibleItemPosition();

 

if (firstPosition > 1 || getScollYDistance() >= UIUtils.getDimensResource(mContext, R.dimen.autotrophy_height) - UIUtils.getDimensResource(mContext, R.dimen.title_bar_auto)) {
    setSystemBarAlpha(255);
    StatusBarUtil.setColor(AutoTrophyActivity.this, UIUtils.getColorResource(mContext, R.color.gray_f2f2f2));
} else {
    float dimen = UIUtils.getDimensResource(mContext, R.dimen.autotrophy_height) - UIUtils.getDimensResource(mContext, R.dimen.title_bar_auto);
    int alpha = (int) ((getScollYDistance() / dimen) * 255);
    setSystemBarAlpha(alpha);
    StatusBarUtil.setTranslucentForImageView(AutoTrophyActivity.this, 0, null);
}

其中setSystemBarAlpha(int alpha)这个方法就是根据滑动的距离来进行透明度变化的设置,方法在前面已经展示过了。

三、设置筛选栏固定到标题栏底部

其实原理和标题栏透明度的变化差不多,只不过一个是根据滑动的距离来设置透明度的变化,一个是根据滑动的距离来设置其在竖直方向的位置。好了,下面就是实现的方法,同样是在onScrolled()方法中来进行操作:

 

top = llTitleType.getTop(); // 筛选栏的y方向位置
titleTop = llBg.getTop(); //标题栏的y方向的位置
detTop = top - getScollYDistance();//滑动过程中筛选栏的位置 = 当前位置 -  y方向滑动的距离
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // 4.4以上
    if (detTop <= (titleTop + UIUtils.getDimensResource(mContext, R.dimen.home_banner_det)) && detTop > 0) { // detTop小于标题栏所在的位置
        llTitleType.setY(titleTop + UIUtils.getDimensResource(mContext, R.dimen.autotrophy_type_height) + headHeight);
    } else if (detTop > 0) {//
        llTitleType.setY(detTop + footerHead + headHeight);
    }
} else {
    if (detTop <= titleTop && detTop > 0) {
        llTitleType.setY(titleTop + UIUtils.getDimensResource(mContext, R.dimen.autotrophy_type_height));
    } else if (detTop > 0) {
        llTitleType.setY(detTop + footerHead);
    }
}

其中的footerHead 以及 headHeight 是上拉加载更多高度和下拉刷新的高度,这两个参数是在你添加了刷新和上拉加载更多功能的时候需要添加这两个参数来进行位置适配,如果没有这两个功能,那可以忽略这两个参数。。。

如果有这两个功能,那么首先需要在刷新控件中添加监听方法,可以获取到每次刷新或者上拉加载时移动的距离:

刷新监听

 

public interface OnHeaderRefreshListener {
    void onHeaderRefresh(int y, HeaderRefreshView headerRefreshView);
}
@Override
public void onMove(int y, boolean isComplete, boolean automatic) {
    float alpha = y / (float) mTriggerOffset;
    ViewCompat.setAlpha(progressView, alpha);
    if (onHeaderRefreshListener != null) {
        onHeaderRefreshListener.onHeaderRefresh(y, this);
    }
}

上拉监听

 

public interface OnFooterRefreshListener {
    void onFooterRefresh(int y, FooterRefreshView footerRefreshView);
}
 @Override
    public void onMove(int y, boolean isComplete, boolean automatic) {
//        float alpha = -y / (float) mTriggerOffset;
//        ViewCompat.setAlpha(progressView, alpha);
//        if (!isComplete) {
//            progressView.setProgressRotation(-y / (float) mFinalOffset);
//        }
        if (onFooterRefreshListener != null) {
            onFooterRefreshListener.onFooterRefresh(y, this);
        }
    }

然后在recyclerview 监听的同时也需要做这两个监听来进行位置的变化:

 

@Override
public void onHeaderRefresh(int y, HeaderRefreshView headerRefreshView) {
    headHeight = y;
    int titleHeght = llBg.getTop(); // 标题栏位置
    if (y > 0) { //向下下拉刷新
        llBg.setY((titleHeght + y));
    } else {//没有刷新
        llBg.setY(titleHeght);
    }
    int top = llTitleType.getTop();//筛选栏位置
    if (y > 0) {//向下下拉刷新
        llTitleType.setY(top + y);
    }
}
@Override
public void onFooterRefresh(int y, FooterRefreshView footerRefreshView) {
    footerHead = y;
    if (getScollYDistance() == 0 && y < 0) {//滑动距离为0 并且向上上拉加载更多
        llTitleType.setY(llTitleType.getTop() + footerHead);
    } else if (getScollYDistance() < UIUtils.getDimensResource(this, R.dimen.autotrophy_height) - llBg.getTop()) { // recyclerview 列表不满一屏的时候处理方式
        llTitleType.setY(llTitleType.getTop() - getScollYDistance() + footerHead);
    }
}

做了这个监听后,记得在刷新或者上拉结束后,让headHeight 以及 footerHead 归零,要不然会存在问题。。。

四、小结

按照这个思路来做就可以做出gif图的效果了。现在觉得还是挺简单方便的,当时做的过程中碰到了很多问题,刚开始我们没要求刷新,基本没问题,快做完产品觉得加个刷新比较好,添加刷新后就出现新的问题了,重新捋了下思路终于实现了。不过应该还会存在问题,后期大家发现问题欢迎给我留言指正~~~

 

 

 

Android 从零开始实现RecyclerView分组及粘性头部效果 if(curTop - groupViewHeight < groupViewHeight){//判断与上一组的碰撞,推动当前的顶部GroupView。//分组对应的startPosition在groupPositions中的索引。加入社区》https://bbs.youkuaiyun.com/forums/4304bb5a486d4c3ab8389e65ecb71ac0。加入社区》https://bbs.youkuaiyun.com/forums/4304bb5a486d4c3ab8389e65ecb71ac0。 阅读详情

相关推荐

Android 从零开始实现RecyclerView分组及粘性头部效果,系统学Android从零开始

之前首先得了解。

m0_60635609的博客 671

前端进阶html+css03----粘性定位

大家都知道position:absoulte/relative/fixed, 今天介绍一个position:sticky(粘性定位)。3.当内容足够多并往下滚动的时候,其它元素变化,但粘性定位的区域会一直固定在你设置的位置不动。2.使用黏性定位必须要有一个“滚动的祖先元素”,没有滚动的时候和relative效果差不多。4.你设置的(top/bottom/right/left)是相对于滚动父元素的。1.粘性定位是相对定位和绝对定位的结合体。top改为20px的时候滚动时效果。

weixin_43795761的博客 821

StickyHeaderDemo:深入实现RecyclerView的粘性头部效果

RecyclerView是Android平台上用于显示列表数据的强大组件。了解和使用接口,可以让开发者对列表项的装饰与间隔进行更为精细的控制。接口为开发者提供了一个扩展点,允许我们在RecyclerView的每个item之间、item和边缘之间插入自定义的绘制和测量元素。这不仅增加了列表的美观性和功能性,还赋予了列表更多的交互性,例如在item之间添加分隔线、分割线等。在接下来的章节中,我们将探讨如何利用接口实现StickyHeader等高级功能,以提升应用的用户体验。是。

weixin_35826166的博客 910

css3 header.sticky,CSS3布局网格 - 粘性标头(CSS3 Layout Grid - Sticky Header)

CSS3布局网格 - 粘性标头(CSS3 Layout Grid - Sticky Header)我正在尝试使用CSS Grid构建布局。 我希望头元素是'粘'。 也就是说,当用户滚动时,标题保持固定在视口顶部,其他内容在标题下滚动。 我想给这个标题一个背景图片。我给背景图像分配了一个背景图像,给定了一个固定的位置值,并且应用了一个z值索引值999.下面的其他元素已经定位并给出了较低的z值索引值。...

weixin_35399228的博客 487

RecyclerView.ItemDecoration实现粘性头部

一份详细的RecyclerView.ItemDecoration实现分组粘性头部的Demo,看了就懂!

数学建模常用模型10 :数据包络(DEA)分析法(投入产出法)

数据包络分析是评价多输入指标和多输出指标的较为有效的方法,将投入与产出进行比较。它的结果包含的意思有: ①θ=1,DEA有效,表示投入与产出比达到最优 ②θ&lt;1,非DEA有效,表示投入与产出比没有达到最优,一般来说,θ越大说明效果越好。 数据包络分析是通过对投入的指标和产出的指标做了一个线性规划,并且进行变换后,然后根据其线性规划的对偶问题(线性规划对偶问题具有经济学意义),求解这个对...

HaLosec_Wei 9万+

Flutter - 一个易用且功能强大的粘性头部组件库,适用于任何支持滚动的组件(一)

【easy_sticky_header】 一个易用且功能强大的粘性头部组件库,适用于任何支持滚动的组件。轻松实现粘性头部、头部跳转、微信通讯录、城市列表等效果。

crasowas的博客 2162

Blender学习笔记——制作向量场

#下载Blender - UE4 - FGA Vector Field Editor插件的压缩包,Github上的下载地址如下:https://github.com/isathar/Blender_UE4_VectorFieldEditor #下载并解压后将FGA VectorFields文件夹复制到C:\Program Files\Blender Foundation\Blender 2.83\2.83\scripts\addons目录下,此步骤可根据blender安装的位置自行调整,只要放入addon

wychao2020的博客 1725

css3 header.sticky,如何用CSS3和jQuery创建一个动态的粘性头部(sticky header)

在一些很长的表格中,常常会使用表头悬浮的设计以方便阅读,即在表格离开窗口之前,表头会一直 fixed 悬浮在表格的最顶上。还有许多诸如评论框顶部标题菜单等元素,也采用了这种被称为 Sticky Pin 或者 粘性元素 的设计。下面就说一下如何用CSS3和jQuery创建一个粘性元素的设计。网站设计中流行的趋势总是来来去去的。那些停留网站时间最长的,就是他们解决了一个特别的问题。而这种趋势的流行,也...

weixin_42469578的博客 514

Python爬虫实战:抓取天气数据并生成可视化图表(完整可复制代码)

工具/库核心作用选型理由requests发送HTTP请求,获取天气网页内容语法简单,上手快,支持Headers配置(反爬)解析HTML页面,提取目标天气数据无需懂复杂XPath,API直观,快速定位标签pandas数据清洗、整理(如日期/温度格式化)一键处理数据格式,与matplotlib无缝适配matplotlib生成可视化图表(折线图/饼图/柱状图)Python主流可视化库,定制性强,支持保存高清图生成随机User-Agent,应对反爬自动更新UA池,避免手动维护。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 909

paddle 43 用onnxruntime实现ppyoloe模型的部署(含python和c++版本)

PP-YOLOE+是PP-YOLOE模型的升级版,PP-YOLOE+_l在COCO test-dev2017达到了53.3的mAP, 同时其速度在Tesla V100上达到了78.1 FPS。PP-YOLOE+_s/m/x同样具有卓越的精度速度性价比。paddle官方只给出了基于paddle框架的部署案例,为了更好的部署,为此实现将paddle模型转换为onnx模型,然后在python下实现onnxruntime部署。后续会补充c++ onnxruntime部署

a486259的博客 1915

Android-Kotlin 实现Recycleview粘性头部分组效果

先上效果图: 可以从图中看到,增加一个粘性头部,也相当于一个直观的分组效果,有比较多的实现方式,例如: 通过RecyclerView的ItemDecoration来实现 通过BaseSectionQuickAdapter适配器来实现 本文是通过重写RecyclerView的ItemDecoration来实现,如果想使用BaseSectionQuickAdapter可以参考使用BRVAH ...

SSBBY的博客 1271

【RT-DETR实战】112、NCNN模型转换与层实现支持:从模型文件到推理引擎的硬核实战

本文详细记录了将RT-DETR模型部署到NCNN框架的全过程及关键要点。作者首先遇到MultiHeadAttention等算子不支持的问题,通过ONNX中间转换和自定义层实现解决。文章具体介绍了PyTorch到NCNN的权重转换技巧、模型优化方法(包括量化和线程优化)以及调试经验,强调逐层对比输出、预处理检查和边界情况测试的重要性。最后分享了保持转换流程可复现性的实用建议,指出手动调试虽然耗时但能加深对模型的理解,体现了工程师在解决技术难题时的专业精神与成就感。

企鹅码农的专属播客,分享10多年的实战案例和经验解读,包含YOLO、RT-DETR、AI等各个工作领域。 41

Android实现RecyclerView粘性头部效果

粘性头部(Sticky Header)是移动端常见的交互设计,微信账单列表的月份标题在滚动时会停留在顶部直至下一组标题将其顶替。Android原生的RecyclerView并未提供该功能,需要借助ItemDecoration和自定义布局实现。核心原理是通过监听RecyclerView的滚动事件,动态计算当前需要置顶的组标题位置,并在RecyclerView顶部绘制一个悬浮的Header视图。当下一组标题接触悬浮Header时,触发替换动画。

ZPh_9yed的博客 220

二极管钳位电路、限幅电路和检波电路Multisim电路仿真

本文系统介绍了二极管钳位、限幅和检波三种基础电路的工作原理及Multisim仿真验证。钳位电路通过电容-二极管配合实现波形整体平移,将波峰或波谷固定在指定电压;限幅电路利用二极管导通特性削除信号超出设定阈值的部分;检波电路则通过半波整流和电容滤波从调幅波中提取音频信号。三种电路均通过Multisim仿真验证了理论分析结果,展示了二极管在信号处理中的关键作用。这些基础电路广泛应用于信号调理、电平保护和通信解调等领域。

XU157303764的博客 1120

【AI智能体】基于OpenCode 搭建Skills环境与项目实战开发详解

基于OpenCode 搭建Skills环境与项目实战开发详解

congge 8899

如何利用CSStickyHeaderFlowLayoutAttributes实现个性化粘性头部效果

想要为你的iOS应用添加酷炫的粘性头部效果吗?CSStickyHeaderFlowLayoutAttributes是实现个性化头部动画的关键工具!这个强大的UICollectionViewLayoutAttributes扩展让开发者能够轻松创建视差滚动、渐变显示等惊艳效果。 ## 🎯 什么是CSStickyHeaderFlowLayoutAttributes? CSStickyHeaderF

gitblog_01039的博客 781

ESP32-C3入门教程 蓝牙篇①——基于Blufi 的 WiFi 智能配网

文章目录一、前言二、WiFi配网方式三、快速运行四、运行效果五、ESP32-C3程序流程5.1 主程序5.2 回调函数5.3 SmartConfig线程5.4 流程图六、关键函数6.1 设置SmartConfig的协议类型6.2 启动SmartConfig6.3 停止SmartConfig七、其他八、参考 一、前言 本文基于VS Code IDE进行编程、编译、下载、运行等操作 基础知识点请查阅:ESP32-C3入门教程 基础篇①——基于VS Code构建Hello World 二、WiFi配网方式 W

7765
上一篇: app 欢迎页的实现以及动画效果添加
下一篇: mvp 架构的分析与学习
cherry459
博客等级 码龄9年 4粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值