首页 > 其他分享 >【Android】折叠效果CoordinatorLayout+AppBarLayout首页效果&& CoordinatorLayout抖动问题解决方案--100个经典UI设计模板(95/100)

【Android】折叠效果CoordinatorLayout+AppBarLayout首页效果&& CoordinatorLayout抖动问题解决方案--100个经典UI设计模板(95/100)

时间:2023-09-19 11:31:37浏览次数:42  
标签:AppBarLayout int child headerBehaviorType CoordinatorLayout 100 null type


亲测效果如下:

【Android】折叠效果CoordinatorLayout+AppBarLayout首页效果&& CoordinatorLayout抖动问题解决方案--100个经典UI设计模板(95/100)_Android

布局结构

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    xmlns:tools="http://schemas.android.com/tools">
    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#F7F7F7"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        >

        <android.support.design.widget.AppBarLayout
            android:id="@+id/layout_app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#F5F5F7"
            app:elevation="0dp">


            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:expandedTitleMarginEnd="60dp"
                app:contentScrim="@color/red"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <!--头部背景图-->
                <ImageView
                    android:id="@+id/iv_header_bg"
                    android:layout_width="match_parent"
                    android:layout_height="220dp"
                    android:background="@color/purple_500"
                    app:layout_collapseMode="parallax"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
                <!--                正在热播-->
                <android.support.constraint.ConstraintLayout
                    android:id="@+id/layout_living"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="55dp"
                    android:layout_marginBottom="19dp"
                    app:layout_collapseParallaxMultiplier="0.5">

                    <TextView
                        android:id="@+id/tv_hothint"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"

                        android:layout_marginTop="25dp"
                        android:text="正在热播"
                        android:textColor="#ffffffff"
                        android:textSize="16sp"
                        app:layout_constraintStart_toStartOf="@id/gl_start_hot_live"
                        app:layout_constraintTop_toTopOf="parent" />

                    <android.support.constraint.Guideline
                        android:id="@+id/gl_end_hot_live"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        app:layout_constraintGuide_end="20dp" />
                    <!-- 正在热播-->
                    <android.support.constraint.Guideline
                        android:id="@+id/gl_start_hot_live"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        app:layout_constraintGuide_begin="20dp" />

                    <android.support.v7.widget.RecyclerView
                        android:id="@+id/recycleView_live"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="10dp"
                        android:nestedScrollingEnabled="false"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@id/tv_hothint" />
                </android.support.constraint.ConstraintLayout>

                <!--Toolbar放在下面不然会被挡住-->
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

            </android.support.design.widget.CollapsingToolbarLayout>
            <!--            精彩视频-->
            <android.support.constraint.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/white">

                <android.support.design.widget.TabLayout
                    android:id="@+id/layout_tab"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:fillViewport="false"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:tabIndicatorColor="#FF5252"
                    app:tabIndicatorFullWidth="false"
                    app:tabIndicatorHeight="1.0dp"
                    app:tabMaxWidth="100dp"
                    app:tabMinWidth="12dp"
                    app:tabMode="scrollable"
                    app:tabPaddingEnd="9dp"
                    app:tabPaddingStart="9dp"
                    app:tabSelectedTextColor="#FF666666"
                    app:tabTextColor="#66666666">
                    <!--指示器颜色-->
                    <!-- app:tabIndicatorColor="#0835f8"-->
                    <!--tab条目中字体颜色-->
                    <!--app:tabSelectedTextColor="#0835f8"-->
                    <android.support.design.widget.TabItem
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="最新" />

                    <android.support.design.widget.TabItem
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="最热" />

                </android.support.design.widget.TabLayout>
            </android.support.constraint.ConstraintLayout>
        </android.support.design.widget.AppBarLayout>

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/nestedScrollView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#FFFFFFFF"
            android:fillViewport="true"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        </android.support.v4.widget.NestedScrollView>

    </android.support.design.widget.CoordinatorLayout>
    <!--返回、标题 更多-->
    <android.support.constraint.ConstraintLayout
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:id="@+id/layout_header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        app:layout_collapseMode="pin"
        app:layout_collapseParallaxMultiplier="0.5">

        <ImageView
            android:id="@+id/iv_return"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="TODO"
            app:layout_constraintStart_toStartOf="@id/gl_start"
            app:layout_constraintTop_toTopOf="parent" />

        <ImageView
            android:id="@+id/iv_header_icbc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="TODO"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <!--返回-->
        <ImageView
            android:id="@+id/ivmore"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:layout_marginRight="20dp"
            app:layout_constraintEnd_toEndOf="@id/gl_end"
            app:layout_constraintTop_toTopOf="parent" />

        <!--    标题图片-->
        <android.support.constraint.Guideline
            android:id="@+id/gl_end"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_end="20dp" />
        <!--更多-->
        <android.support.constraint.Guideline
            android:id="@+id/gl_start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_begin="20dp" />
    </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

布局结构解析:
消除系统自带Toolbar的UI设计冲突问题。这样便于UI布局还原UI设计效果
折叠效果得到保证。头部布局放最后在上拉过程中不会被遮挡
这样的布局后续可以很方便的进化调整。比如进行滑动和tablayout联动等等
如果是不太复杂的首页这个可以直接拿来就用哦!

源码地址:
gitee:https://gitee.com/lc951/my-android github:https://github.com/lichong951/MyAndroid/

参考

ConstraintLayout:约束布局ConstraintLayout看这一篇就够了 CollapsingToolbarLayout:android新特性:使用CollapsingToolbarLayout实现折叠效果及问题解决

CoordinatorLayout+AppBarLayout抖动问题

本想自己复现一下的,结果发现抖动效果没那么明显。借用一下这张图

【Android】折叠效果CoordinatorLayout+AppBarLayout首页效果&& CoordinatorLayout抖动问题解决方案--100个经典UI设计模板(95/100)_交互设计_02


解决方案如下:

/**
 * <pre>
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2019/03/13
 *     desc  : 自定义Behavior
 *     revise: 解决appbarLayout若干问题
 *              1)快速滑动appbarLayout会出现回弹
 *              2)快速滑动appbarLayout到折叠状态下,立马下滑,会出现抖动的问题
 *              3)滑动appbarLayout,无法通过手指按下让其停止滑动
 * </pre>
 */
public class AppBarLayoutBehavior extends AppBarLayout.Behavior {

    private static final String TAG = "AppbarLayoutBehavior";
    private static final int TYPE_FLING = 1;
    private boolean isFlinging;
    private boolean shouldBlockNestedScroll;

    public AppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
        LogUtil.d(TAG, "onInterceptTouchEvent:" + child.getTotalScrollRange());
        shouldBlockNestedScroll = isFlinging;
        switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                //手指触摸屏幕的时候停止fling事件
                stopAppbarLayoutFling(child);
                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(parent, child, ev);
    }

    /**
     * 反射获取私有的flingRunnable 属性,考虑support 28以后变量名修改的问题
     * @return Field
     * @throws NoSuchFieldException
     */
    private Field getFlingRunnableField() throws NoSuchFieldException {
        Class<?> superclass = this.getClass().getSuperclass();
        try {
            // support design 27及一下版本
            Class<?> headerBehaviorType = null;
            if (superclass != null) {
                headerBehaviorType = superclass.getSuperclass();
            }
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("mFlingRunnable");
            }else {
                return null;
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            // 可能是28及以上版本
            Class<?> headerBehaviorType = superclass.getSuperclass().getSuperclass();
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("flingRunnable");
            } else {
                return null;
            }
        }
    }

    /**
     * 反射获取私有的scroller 属性,考虑support 28以后变量名修改的问题
     * @return Field
     * @throws NoSuchFieldException
     */
    private Field getScrollerField() throws NoSuchFieldException {
        Class<?> superclass = this.getClass().getSuperclass();
        try {
            // support design 27及一下版本
            Class<?> headerBehaviorType = null;
            if (superclass != null) {
                headerBehaviorType = superclass.getSuperclass();
            }
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("mScroller");
            }else {
                return null;
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            // 可能是28及以上版本
            Class<?> headerBehaviorType = superclass.getSuperclass().getSuperclass();
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("scroller");
            }else {
                return null;
            }
        }
    }

    /**
     * 停止appbarLayout的fling事件
     * @param appBarLayout
     */
    private void stopAppbarLayoutFling(AppBarLayout appBarLayout) {
        //通过反射拿到HeaderBehavior中的flingRunnable变量
        try {
            Field flingRunnableField = getFlingRunnableField();
            Field scrollerField = getScrollerField();
            if (flingRunnableField != null) {
                flingRunnableField.setAccessible(true);
            }
            if (scrollerField != null) {
                scrollerField.setAccessible(true);
            }
            Runnable flingRunnable = null;
            if (flingRunnableField != null) {
                flingRunnable = (Runnable) flingRunnableField.get(this);
            }
            OverScroller overScroller = (OverScroller) scrollerField.get(this);
            if (flingRunnable != null) {
                LogUtil.d(TAG, "存在flingRunnable");
                appBarLayout.removeCallbacks(flingRunnable);
                flingRunnableField.set(this, null);
            }
            if (overScroller != null && !overScroller.isFinished()) {
                overScroller.abortAnimation();
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child,
                                       View directTargetChild, View target,
                                       int nestedScrollAxes, int type) {
        LogUtil.d(TAG, "onStartNestedScroll");
        stopAppbarLayoutFling(child);
        return super.onStartNestedScroll(parent, child, directTargetChild, target,
                nestedScrollAxes, type);
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout,
                                  AppBarLayout child, View target,
                                  int dx, int dy, int[] consumed, int type) {
        LogUtil.d(TAG, "onNestedPreScroll:" + child.getTotalScrollRange()
                + " ,dx:" + dx + " ,dy:" + dy + " ,type:" + type);
        //type返回1时,表示当前target处于非touch的滑动,
        //该bug的引起是因为appbar在滑动时,CoordinatorLayout内的实现NestedScrollingChild2接口的滑动
        //子类还未结束其自身的fling
        //所以这里监听子类的非touch时的滑动,然后block掉滑动事件传递给AppBarLayout
        if (type == TYPE_FLING) {
            isFlinging = true;
        }
        if (!shouldBlockNestedScroll) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
        }
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
                               View target, int dxConsumed, int dyConsumed, int
            dxUnconsumed, int dyUnconsumed, int type) {
        LogUtil.d(TAG, "onNestedScroll: target:" + target.getClass() + " ,"
                + child.getTotalScrollRange() + " ,dxConsumed:"
                + dxConsumed + " ,dyConsumed:" + dyConsumed + " " + ",type:" + type);
        if (!shouldBlockNestedScroll) {
            super.onNestedScroll(coordinatorLayout, child, target, dxConsumed,
                    dyConsumed, dxUnconsumed, dyUnconsumed, type);
        }
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl,
                                   View target, int type) {
        LogUtil.d(TAG, "onStopNestedScroll");
        super.onStopNestedScroll(coordinatorLayout, abl, target, type);
        isFlinging = false;
        shouldBlockNestedScroll = false;
    }

    private static class LogUtil{
        static void d(String tag, String string){
            Log.d(tag,string);
        }
    }

}

应用:

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    app:layout_behavior="org.yczbj.ycrefreshview.sticky.AppBarLayoutBehavior"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

关于这个抖动的问题已经有大佬博客写的很细致了。参考下面即可:
【亲测】CoordinatorLayout滑动抖动问题

解决CoordinatorLayout+AppBarLayout滑动抖动(回弹)问题

COORDINATORLAYOUT+APPBARLAYOUT+RECYCLERVIEW 滑动冲突引发屏幕抖动的解决方案

CoordinatorLayout滑动抖动问题

解决CoordinatorLayout的动画抖动以及回弹问题

CoordinatorLayout和AppBarLayout 嵌套滑动时抖动的一个原生bug

自研产品推荐

历时一年半多开发终于smartApi-v1.0.0版本在2023-09-15晚十点正式上线
smartApi是一款对标国外的postman的api调试开发工具,由于开发人力就作者一个所以人力有限,因此v1.0.0版本功能进行精简,大功能项有:

  • api参数填写
  • api请求响应数据展示
  • PDF形式的分享文档
  • Mock本地化解决方案
  • api列表数据本地化处理
  • 再加上UI方面的打磨

为了更好服务大家把之前的公众号和软件激活结合,如有疑问请大家反馈到公众号即可,下个版本30%以上的更新会来自公众号的反馈。

嗯!先解释不上服务端原因,API调试工具的绝大多数时候就是一个数据模型、数据处理、数据模型理解共识的问题解决工具,所以作者结合自己十多年开发使用的一些痛点来打造的,再加上服务端开发一般是面向企业的,作者目前没有精力和时间去打造企业服务。再加上没有资金投入所以服务端开发会滞后,至于什么时候会进行开发,这个要看募资情况和用户反馈综合考虑。虽然目前国内有些比较知名的api工具了,但作者使用后还是觉得和实际使用场景不符。如果有相关吐槽也可以在作者的公众号里反馈蛤!

下面是一段smartApi使用介绍:

【Android】折叠效果CoordinatorLayout+AppBarLayout首页效果&& CoordinatorLayout抖动问题解决方案--100个经典UI设计模板(95/100)_viewpager_03

下载地址:

https://pan.baidu.com/s/1kFAGbsFIk3dDR64NwM5y2A?pwd=csdn


标签:AppBarLayout,int,child,headerBehaviorType,CoordinatorLayout,100,null,type
From: https://blog.51cto.com/u_16264967/7523907

相关文章

  • AI绘画变现渠道:日入100+,推荐一个本人实操的方法
    关于AI绘画变现,之前写了几篇相关的文章,需要的自己查阅:AI绘画:如何让图片开口说话生成视频?变现渠道有哪些?无私分享我的AI绘画变现之路,普通人可实操可模仿AI壁纸号一周增加上千粉丝,轻松变现的成功案例分享今天给大家推荐一篇之前没有介绍过的变现方式。前段时间偷偷上线了一个产......
  • 各快 100 倍?4G、5G、6G 相差这么多吗
    二狗子今天晚上有点emo,为什么呢?原来是二狗子心心念很久的一个手游上线了,二狗子兴冲冲地下载了40多分钟,终于下载完了游戏。结果打开游戏一看,发现游戏内部的更新写着预计30分钟完成更新。这就把二狗子搞得emo了。二狗子突然发现自己的室友已经在这款游戏的新手村大杀四方了......
  • 【直接收藏】前端JavaScript面试100问(上)
    1、解释一下什么是闭包?闭包:就是能够读取外层函数内部变量的函数。闭包需要满足三个条件:访问所在作用域;函数嵌套;在所在作用域外被调用。优点:可以重复使用变量,并且不会造成变量污染。缺点:会引起内存泄漏使用闭包的注意点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,......
  • 用python求100到999以内的水仙花数(不用除法求各项)
    c=0forainrange(100,1000):forbinstr(a):a1=int(b)c=c+a1**3ifa==c:print(a)c=0输出结果为153370371407使用for循环来取数字中的每一位,不过数字要先化为str格式来取然后再化为int格式来赋值,要注意c的值每一次......
  • 100033. 最大合金数-363
    100033.最大合金数假设你是一家合金制造公司的老板,你的公司使用多种金属来制造合金。现在共有n种不同类型的金属可以使用,并且你可以使用k台机器来制造合金。每台机器都需要特定数量的每种金属来创建合金。对于第i台机器而言,创建合金需要composition[i][j]份j类型金属......
  • 100031. 计算 K 置位下标对应元素的和-363
    100031.计算K置位下标对应元素的和给你一个下标从0开始的整数数组nums和一个整数k。请你用整数形式返回nums中的特定元素之和,这些特定元素满足:其对应下标的二进制表示中恰存在k个置位。整数的二进制表示中的1就是这个整数的置位。例如,21的二进制表示为10......
  • Oracle不能in超过1000条数据吗
    在Oracle数据库中,对于IN子句的值列表有一个默认限制,该限制取决于数据库的版本。在早期版本的Oracle中,默认情况下,对于IN子句的值列表限制为1000个值。然而,从Oracle12c开始,引入了LISTAGG函数和SYS.ODCIVARCHAR2LIST类型,可以用于处理超过1000个值的IN子句。您可......
  • 复习C语言-题目 1008: [编程入门]成绩评定
    题目描述给出一百分制成绩,要求输出成绩等级‘A’、‘B’、‘C’、‘D’、‘E’。90分以及90分以上为A,80-89分为B,70-79分为C,60-69分为D,60分以下为E。输入格式一个整数0-100以内输出格式一个字符,表示成绩等级样例输入复制90样例输出复制A1#inclu......
  • 复习C语言-题目 1009: [编程入门]数字的处理与判断
    题目描述给出一个不多于5位的整数,要求1、求出它是几位数2、分别输出每一位数字3、按逆序输出各位数字,例如原数为321,应输出123输入格式一个不大于5位的数字输出格式三行第一行位数第二行用空格分开的每个数字,注意最后一个数字后没有空格第三行按逆序输出......
  • 代码随想录算法训练营-回溯算法-2|55. 跳跃游戏、45. 跳跃游戏 II、1005. K 次取反后
    55. 跳跃游戏1.跳跃的覆盖范围。这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点!2. 贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。时间复杂度:O(n)空间复杂度:O(1)1classSolution:2defca......