XML中配置网易云歌手详情滑动效果

拓朴棱镜
• 阅读 388

HeaderLayout

    • *

  网易云音乐App给用户的体验效果一直都非常好,尤其是流畅的动画和滑动的联动效果,都给人一种如丝滑般的感受,这一点在其歌手详情页面体现得尤为突出。那么我们就来实现这样的效果,但是我们不能只局限在实现当中,否则当需求变化就需要改动大量的代码,同时也不能保证它的复用性,放到其他界面则需要写许多重复代码。因此我们需要跳出实现的限制,将其中的元素抽取出来,制作成一个通用的库,并且保证其可拓展性和充分的用户自定义性。经过研究,最终实现了此控件,并取名为HeaderLayout,那么我们先来看看实现效果以便直观的感受一下。

XML中配置网易云歌手详情滑动效果

效果图

如何使用

    • *

  效果图中所有的头部控件滑动联动效果都只需要在xml中配置几行代码即可完成,由于HeaderLayout是根据CoordinatorLayout的机制来实现的,所以HeaderLayout需要包裹在CoordinatorLayout中才会有效果。

  • 引入依赖
implementation "com.imurluck:headerlayout:$lastVersion"
  • 编写布局
      HeaderLayout继承自FrameLayout,且并没有改写FrameLayout的测量和布局逻辑,所以子控件的布局方式和FrameLayout相同即可,我们只需要关注HeaderLayout新增的几个属性。这里以效果图为例。
  <androidx.coordinatorlayout.widget.CoordinatorLayout
          ...>

      <com.zzx.headerlayout_kotlin.HeaderLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              //新增属性
              app:extend_height="30%">

          <androidx.appcompat.widget.AppCompatImageView
                  android:layout_width="match_parent"
                  android:layout_height="300dp"
                  android:src="@drawable/singer"
                  android:scaleType="centerCrop"
                  //新增属性
                  app:transformation="scroll|extend_scale"
                  />

          ...

      </com.zzx.headerlayout_kotlin.HeaderLayout>

      <androidx.viewpager.widget.ViewPager
              android:id="@+id/viewPager"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              //配置依赖布局的layout_behavior
              app:layout_behavior="@string/header_layout_scrolling_view_behavior"/>

  </androidx.coordinatorlayout.widget.CoordinatorLayout>

  如上所示,HeaderLayout工作在CoordinatorLayout中并且是其直接子View。ViewPager由于需要根据HeaderLayout的滑动做出界面的调整,所以需要配置layout_behavior,并且其值为@string/header_layout_scrolling_view_behavior,这里和AppBarLayout的使用方式一致。我们的工作重点是头部控件的联动效果,因此咱们聚焦于HeaderLayout和其子View。我们看AppCompatImageView,它用来展示效果图中的歌手。仔细分析效果图中AppCompatImageView的变换方式,可以发现它是根据父控件HeaderLayout的滑动而做出的相应的变化效果,HeaderLayout向上滑动,其跟随向上,HeaderLayout向下滑动,则跟着向下。并且,在HeaderLayout滑动到底部继续向下拓展时,AppCompatImageView做了一个收缩的变换。这一切的一切都需要归功于app:transformation属性,可以在代码中看见其值为"scroll|extend_scale",那么其含义是什么呢?对此,我们引出了一个概念----Transformation,它是一个接口,其意在为根据HeaderLayout的滑动及状态而做出相应的变化行为。在介绍Transformation之前,有必要介绍一下HeaderLayout滑动中的几种状态。

XML中配置网易云歌手详情滑动效果

HeadeerLayout状态图

  HeaderLayout的滑动实际上是HeaderLayout高度的动态变化,所以需要了解图中三种高度的含义。maxHeight是HeaderLayout第一次加载测量后的高度,minHeight是设置了app:sticky_until_exit="true"属性的子View的高度之和,此属性表示子View不随着HeaderLayout而滑出屏幕,形成一种粘连在屏幕顶部的效果,且子View是按照顺序排列的。extendHeight则是拓展的高度,展示在效果图中就是图片收缩scale时下滑的高度,extendHeight可以在xml中为HeaderLayout设置,其值可以为dimension,百分数,或者float比例,百分数和float比例是按照maxHeight而计算的。
  而图中五种状态用来表示HeaderLayout高度变化过程中用来表示滑动状态的,Transformation就是根据应这五种状态而生,Transformation作用于HeaderLayout的直接子View或者间接子View(间接子View需要自己进行处理,可以参考CommonToolbarTransformation),一个子View可以同时拥有多个Transformation,HeaderLayout在其状态变化时,则会遍历子View的所有Transformation,通知其做出改变。
  XML中作用于AppCompatImageView的app:transformation="scroll|extend_scale"属性,scroll 和 extend_scale则是内置的两种Transformation,如下表所示。

XML中配置网易云歌手详情滑动效果

XML中配置网易云歌手详情滑动效果

transformation表示内置的几中Transformation,但是想要自定义Transformation应该如何做呢?

自定义Transformation

    • *

  custom_transformation属性则是专为自定义Transformation而服务,其值为自己实现的Transformation类的全路径。自定义Transformation有两种方式,其一是实现Transformation接口,另一种方式是继承TransformationAdapter类,TransformationAdapter是Transformation是Transformation接口的空实现,继承于此则不需要实现所有的方法。

interface Transformation<in V: View> {
    /**
     * @see [HeaderLayout.scrollState]为STATE_MIN_HEIGHT, 这个方法回调表示[HeaderLayout]的Bottom已经收缩到了最小高度
     * @param child 当前需要做变换的view
     * @param parent [HeaderLayout]
     * @param unConsumedDy 由其他状态到此状态未消耗完的dy
     */
    fun onStateMinHeight(child: V, parent: HeaderLayout, unConsumedDy: Int)

    /**
     * @see [HeaderLayout.scrollState]为STATE_NORMAL_PROCESS, 在STATE_MIN_HEIGHT和STATE_MAX_HEIGHT之间
     * 这个方法回调表示[HeaderLayout]的Bottom正在最小高度与最大高度之间
     * @param child 当前需要做变换的view
     * @param parent [HeaderLayout]
     * @param percent 0<percent<1, 值为([HeaderLayout.getBottom] - [HeaderLayout.minHeight]) / ([HeaderLayout.maxHeight] - [HeaderLayout.minHeight]])
     * 且值不会为0或者1, 为0相当于是回调了[onStateMinHeight], 为1相当于回调了[onStateMaxHeight], 由于值不会为0或1,
     * 所以在回调[onStateMinHeight]和[onStateMaxHeight]时会有一个未消耗的dy
     * @param dy 滑动的距离
     */
    fun onStateNormalProcess(child: V, parent: HeaderLayout, percent: Float, dy: Int)

    /**
     * @see [HeaderLayout.scrollState]为STATE_MAX_HEIGHT
     * 这个方法回调表示[HeaderLayout]的Bottom正处于[HeaderLayout.maxHeight]
     * @param child 当前需要做变换的view
     * @param parent [HeaderLayout]
     * @param unConsumedDy 由其他状态到此状态未消耗完的dy
     */
    fun onStateMaxHeight(child: V, parent: HeaderLayout, unConsumedDy: Int)

    /**
     * @see [HeaderLayout.scrollState]为STATE_EXTEND_PROCESS, 在STATE_MAX_HEIGHT和STATE_EXTEND_MAX_END之间
     * 这个方法回调表示[HeaderLayout]的Bottom正处于[HeaderLayout.maxHeight] 和 [HeaderLayout.maxHeight] + [HeaderLayout.extendHeight]之间
     * @param child 当前需要做变换的view
     * @param parent [HeaderLayout]
     * @param percent 0<percent<1, 值为([HeaderLayout.getBottom] - [HeaderLayout.maxHeight]) / [HeaderLayout.extendHeight]
     * 且值不会为0或者1, 为0相当于是回调了[onStateMaxHeight], 为1相当于回调了[onStateExtendMaxEnd], 由于值不会为0或1,
     * 所以在回调[onStateMaxHeight]和[onStateExtendMaxEnd]时会有一个未消耗的dy
     */
    fun onStateExtendProcess(child: V, parent: HeaderLayout, percent: Float, dy: Int)

    /**
     * @see [HeaderLayout.scrollState]为STATE_EXTEND_MAX_END,
     * 这个方法回调表示[HeaderLayout]的Bottom正处于[HeaderLayout.maxHeight] + [HeaderLayout.extendHeight]
     * @param child 当前需要做变换的view
     * @param parent [HeaderLayout]
     * @param unConsumedDy 由其他状态到此状态未消耗完的dy
     *
     */
    fun onStateExtendMaxEnd(child: V, parent: HeaderLayout, unConsumedDy: Int)
}

  HeaderLayout在状态变化的时候会遍历子View的所有Transformation,也即是会回调Transformation接口中的这几个方法,使用者可以根据这几个方法的含义来变换子View。

Tips

    • *

  开发者在使用app:transformation和app:sticky_untila_exit等属性时,最好用AppCompatImageView代替ImageView,AppCompatTextView代替TextView,这样在XML文件中则不会因为系统控件无法使用自定义属性而报红线,即使报红线也不会影响程序正常的执行,只是看着别扭。

总结

    • *

  HeaderLayout是根据参照网易云音乐的效果而实现的,但又跳出了“实现”的限制,提取出来了一个公共而又与业务无关的控件,其思想则是学习了CoordinatorLayout的behavior和ViewGroup事件的分发思想,将HeaderLayout的滑动状态分发给其子View,从而产生联动效果。
  最后放上Github的地址把:https://github.com/imurluck/H...

Android开发资料+面试架构资料 免费分享 点击链接 即可领取

《Android架构师必备学习资源免费领取(架构视频+面试专题文档+学习笔记)》

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
android手势滑动——左右滑动效果实现
/手势监听@authorlifengfeng/publicclassMainActivityextendsActivityimplementsOnTouchListener,OnGestureListener{//创
App复杂动画实现——Rive保姆级教程
在App开发过程中,如果想实现动画效果,可以粗略分为两种方式。一种是直接用代码编写,像平移、旋转等简单的动画效果,都可以这么干,如果稍微复杂点,就会对开发工程师的数学功底、图形图像学功底有很高的要求。
Easter79 Easter79
3年前
swipe实现app滑动效果
t滑动事件时间,毫秒n次数coidngutf8'''获取当前窗口长宽'''defget_size(dr):xint(dr.get_window_size()'width')yint(dr.get_window_size()'height')returnx,y'''向上滑'''defswip
红橙Darren 红橙Darren
3年前
打造炫酷通用的ViewPager指示器 - Adapter模式适配所有
1.概述上一期我们已经写了一篇可是这种效果虽然绚烂可以装装A和C之间,但是在实际的大多数效果中并不常见,只是在内涵段子中有这个效果而已,那么这一期我们就用Adapter适配器模式适配所有的效果,堪称终结者。附视频地址:    这里写图片描述2.效果实现我还是还是拿上一个实例来做演示吧。这里我贴几种常见的效果,首先声明Android自带的
Stella981 Stella981
3年前
Android 贝塞尔曲线实战之网易云音乐鲸云特效
作者:哈哈将个推Android高级开发工程师前言APP开发市场已经告别“野蛮生长”时代,人们不再满足于APP外形创新,而将目光转向全方面的用户体验上。在这过程中,动效化作为移动互联网产品的新趋势,如何实现酷炫丝滑的动画效果已然成为开发者们的新课题。实现方式其实很简单。本文将为你剖析理论基础以及具体应用。咱们日常使用的APP的时候,
Stella981 Stella981
3年前
React Native (一) react
ReactNative(一)reactnativevideo实现音乐播放器和进度条的功能功能:1.卡片滑动切歌2.显示进度条效果图:!(https://oscimg.oschina.net/oscnet/3c
Stella981 Stella981
3年前
Android 仿淘宝、京东商品详情页向上拖动查看图文详情控件DEMO详解
一、淘宝商品详情页效果!(https://img.jbzj.com/file_images/article/201609/2016090409490116.gif)我们的效果!(https://img.jbzj.com/file_images/article/201609/2016090409490117.gif)二、实现
Stella981 Stella981
3年前
Android 控件抖动效果
利用Android自带的动画效果,实现控件的抖动效果,效果资源文件shark.xml<?xmlversion"1.0"encoding"utf8"?<translatexmlns:android"http://schemas.android.com/apk/res/android"android:fr
Wesley13 Wesley13
3年前
Android 关于Activity的跳转和finish时切换页面动画实现
今天沈阳斌子在做APP时,客户的需求变更是在原有的程序上加入跳转页面的动画切换,类似IPhone的左出右进的方式,返回时是相反的效果。我知道用两种方式可以实现这样的效果,一种就是通过在startActivity后执行overridePendingTransition方法进行动画的切换,同样finish也是一样的。下面就是我封装好的方法:/
绣鸾 绣鸾
1年前
KeyShot 2023.3 Pro for mac(渲染和动画制作)
是一款高级渲染和动画软件,它可以帮助用户快速创建高质量的渲染效果和动画效果。KeyShotPro具有以下特点:1.实时渲染:KeyShotPro支持实时渲染,用户可以在渲染过程中实时预览效果,节省了大量的时间和精力。2.高质量渲染:KeyShotPro支持