Android高级UI开发(二十九)自定义动画框架-让scrollview里的所有控件随着滑动的距离执行各自的动画

举报
yd_57386892 发表于 2020/12/28 22:55:14 2020/12/28
【摘要】         这次我们做一个动画框架,配置scrollview里包含的控件的自定义属性,就可以实现滑动Scrollview时,里面的控件根据滑动的距离执行各自的动画进度。scrollivew里包含的这些控件可以是任意常用的控件,如 imageView,Button,TextView等。我们将给这些普通的系统控件配置自定义属性!看到这里是不是觉得无法实现,因为系统的Image...

        这次我们做一个动画框架,配置scrollview里包含的控件的自定义属性,就可以实现滑动Scrollview时,里面的控件根据滑动的距离执行各自的动画进度。scrollivew里包含的这些控件可以是任意常用的控件,如 imageView,Button,TextView等。我们将给这些普通的系统控件配置自定义属性!看到这里是不是觉得无法实现,因为系统的ImageView,Button等是无法识别我们自定义的属性值的,系统的控件怎么识别我们随便定义的属性呢。今天我们就来解决这个问题,解决这个问题的意义在于让系统控件能像我们自定义控件一样,配置了属性就可以执行相应的动画。我们先来看一下运行效果:

源码下载地址:https://download.csdn.net/download/gaoxiaoweiandy/11136228

 

我们还是从界面布局讲起,直观上分析一下。

1. 布局

   activity_main.xml


  
  1. <com.example.animateframe1.DiscrollView xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. xmlns:app="http://schemas.android.com/apk/res/com.example.animateframe1">
  6. <com.example.animateframe1.DiscrollViewContent
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent">
  9. <TextView
  10. android:layout_width="match_parent"
  11. android:layout_height="600dp"
  12. android:background="@android:color/white"
  13. android:textColor="@android:color/black"
  14. android:textSize="25sp"
  15. android:padding="25dp"
  16. tools:visibility="gone"
  17. android:gravity="center"
  18. android:fontFamily="serif"
  19. android:text="冯绍峰对着倪妮发誓说:‘’如果有一天我离开了你,我就把名字倒着念‘’。倪妮说:‘我也是’’!——尼玛,看着我也是醉了!" />
  20. <View
  21. android:layout_width="match_parent"
  22. android:layout_height="200dp"
  23. android:background="#007788"
  24. app:discrollve_alpha="true"
  25. />
  26. <ImageView
  27. android:layout_width="200dp"
  28. android:layout_height="120dp"
  29. app:discrollve_alpha="true"
  30. app:discrollve_translation="fromLeft|fromBottom"
  31. android:src="@drawable/baggage" />
  32. <View
  33. android:layout_width="match_parent"
  34. android:layout_height="200dp"
  35. app:discrollve_fromBgColor="#ffff00"
  36. app:discrollve_toBgColor="#88EE66" />
  37. <ImageView
  38. android:layout_width="220dp"
  39. android:layout_height="110dp"
  40. android:layout_gravity="right"
  41. android:src="@drawable/camera"
  42. app:discrollve_translation="fromRight" />
  43. <TextView
  44. android:layout_width="match_parent"
  45. android:layout_height="wrap_content"
  46. android:padding="20dp"
  47. android:fontFamily="serif"
  48. android:gravity="center"
  49. android:text="眼见范冰冰与李晨在一起了,孩子会取名李冰冰;李冰冰唯有嫁给范伟,生个孩子叫范冰冰,方能扳回一城。"
  50. android:textSize="23sp"
  51. app:discrollve_alpha="true"
  52. app:discrollve_translation="fromBottom" />
  53. <ImageView
  54. android:layout_width="wrap_content"
  55. android:layout_height="wrap_content"
  56. android:layout_margin="20dp"
  57. android:layout_gravity="center"
  58. android:src="@drawable/sweet"
  59. app:discrollve_scaleX="true"
  60. app:discrollve_scaleY="true" />
  61. <ImageView
  62. android:layout_width="wrap_content"
  63. android:layout_height="wrap_content"
  64. android:layout_margin="20dp"
  65. android:layout_gravity="center"
  66. android:src="@drawable/camera"
  67. app:discrollve_translation="fromLeft|fromBottom"
  68. />
  69. </com.example.animateframe1.DiscrollViewContent>
  70. </com.example.animateframe1.DiscrollView>

我们可以看出布局结构图如下

 

DisScrollview(重写了Scrollview) --->DisScrollviewContent(重写了LinearLayout)--->包含的系统控件。系统控件中类似于app:discrollve_translation="fromRight" 的属性都是自定义属性。现在我们来解释下为什么要重写DisScrollview与DisScrollviewContent以及如何让系统控件如Imageview等来识别我们的自定义属性。

1.1  为什么需要自定义DisScrollview

为什么要重写Scrollview,这个是为了重写

protected void onScrollChanged(int l, int t, int oldl, int oldt)函数,用于获取滚动的距离t,对于第一个控件来说的话,t/height(第一个控件的View的高度)就是aplha透明度的比例。当t=height时,aplha=1,为不透明。alpha在0-1之间。
 

在这里我们先不细谈onScrollChanged里的具体算法,我们现在只需大概知道它是用来获取滑动的距离t的,然后t/控件的height就可以得出一个比例,执行动画(透明度,平移X,平移Y等)的比例。

 

1.2 为什么需要DisScrollviewContent

这个是关键,为了解决系统控件(如Imageview)不识别我们的自定义属性的问题。

DisScrollviewContent继承于LinearLayout,我们自定义LinearLayout,无非是想改变LinearLayout的行为。那么想改变什么行为呢。我们想利用DisScrollviewContent来获取DisScrollviewContent包含的各个系统控件,并且解析到为系统控件配置的自定义属性值。这个我们很容易用一个for循环获取到各个子控件及相关XML自定义属性的值。但是我们获取到了这些自定义控件属性又能如何,imageview等系统控件又不识别,就不能执行动画。那我们获取这些自定义属性给谁用??

我们可以在imageview外再包裹一个自定义父布局ViewGroup,然后把这些获取到的自定义属性(动画属性值)赋予这个包裹的VIEWGROUP,然后让父布局可以根据属性值来执行动画,那么里面的imageview是不是也就跟着动起来了呢?这个想法应该可以实现,整体布局都执行动画飞了起来,子布局自然就跟着动了起来,相当于我们的系统控件(如Imageview)执行了动画。这是一个瞒天过海的做法,关于如何在LinearLayout addView之前给每一个系统控件包裹VIEWGROUP的事情,就交给了我们自定义的LinearLayout:DisScrollviewContent。这就是我们为什么需要DisScrollviewContent的原因:“”包裹+动画 = 子控件动画 = 瞒天过海“” 现在我们的布局应该是这样子的:

至于代码的具体实现我们后面章节讲解,当然不看讲解,直接去下载源码看也行。

 

我们总结一下上面的分析:

1. 自定义LinearLayout:DisScrollviewContent,改变布局结构,用自定义VIEWGROUP包裹系统控件如imageview等。

2. 自定义VIEWGROUP(用于包裹)

3. 自定义Scrollview:DisScrollview,根据滑动的距离来计算动画执行的进度比例。

Ok,接下来我们就分析一下上面1,2,3的核心代码是如何实现的。

2. 代码

2.1 DisScrollviewContent ( 自定义LinearLayout )


  
  1. package com.example.animateframe1;
  2. import android.content.Context;
  3. import android.content.res.TypedArray;
  4. import android.util.AttributeSet;
  5. import android.view.View;
  6. import android.widget.LinearLayout;
  7. public class DiscrollViewContent extends LinearLayout {
  8. public DiscrollViewContent(Context context, AttributeSet attrs) {
  9. super(context, attrs);
  10. setOrientation(VERTICAL);
  11. }
  12. /**
  13. * 这个函数在加载XML布局时自动调用,可以获取到每一个系统控件配置的布局参数,包括自定义参数。
  14. * 每加载一个系统控件(如Imageview),则调用一次这个函数。
  15. * @param attrs
  16. * @return
  17. */
  18. @Override
  19. public LayoutParams generateLayoutParams(AttributeSet attrs) {
  20. //从attrs所有参数里提取自定义属性值,并保持在MyLayoutParams对象里,以供“自定义包裹VIEWGROUP"使用并执行动画。
  21. return new MyLayoutParams(getContext(),attrs);
  22. }
  23. /**
  24. * 这个函数是在generateLayoutParams之后执行,在这里我们可以获取到generateLayoutParams函数返回的MyLayoutParams里的自定义属性值。
  25. * 然后在addview系统控件(如Imageview)之前,先创建并添加一个“自定义包裹VIEWGROUP"视图,然后将自定义属性赋给这个视图,最后在把系统控件
  26. * addview到"自定义包裹VIEWGROUP"里,从而实现了在代码中为XML里的每一个系统控件外层包裹一个“自定义包裹VIEWGROUP"视图。
  27. * @param child
  28. * @param index
  29. * @param params
  30. */
  31. @Override
  32. public void addView(View child, int index,
  33. android.view.ViewGroup.LayoutParams params) {
  34. MyLayoutParams p = (MyLayoutParams) params;
  35. if(!isDiscrollvable(p)){ //没有自定义属性的系统控件,我们就不需要外层包裹一个“自定义包裹VIEWGROUP"视图。直接addview即可。
  36. super.addView(child, index, params);
  37. }else{
  38. //有自定义属性的系统控件,我们需要外层包裹一个“自定义包裹VIEWGROUP"视图。
  39. DiscrollvableView discrollvableView = new DiscrollvableView(getContext());
  40. discrollvableView.setmDiscrollveAlpha(p.mDiscrollveAlpha);
  41. discrollvableView.setmDisCrollveTranslation(p.mDisCrollveTranslation);
  42. discrollvableView.setmDiscrollveScaleX(p.mDiscrollveScaleX);
  43. discrollvableView.setmDiscrollveScaleY(p.mDiscrollveScaleY);
  44. discrollvableView.setmDiscrollveFromBgColor(p.mDiscrollveFromBgColor);
  45. discrollvableView.setmDiscrollveToBgColor(p.mDiscrollveToBgColor);
  46. //先为child包裹一个外层视图
  47. discrollvableView.addView(child);
  48. //然后再把外层父视图添加到LinearLayout里。
  49. super.addView(discrollvableView, index, params);
  50. }
  51. }
  52. private boolean isDiscrollvable(MyLayoutParams p) {
  53. // TODO Auto-generated method stub
  54. return p.mDiscrollveAlpha||
  55. p.mDiscrollveScaleX||
  56. p.mDiscrollveScaleY||
  57. p.mDisCrollveTranslation!=-1||
  58. (p.mDiscrollveFromBgColor!=-1&&
  59. p.mDiscrollveToBgColor!=-1);
  60. }
  61. public static class MyLayoutParams extends LayoutParams{
  62. public int mDiscrollveFromBgColor;//背景颜色变化开始值
  63. public int mDiscrollveToBgColor;//背景颜色变化结束值
  64. public boolean mDiscrollveAlpha;//透明度
  65. public int mDisCrollveTranslation;//平移ֵ
  66. public boolean mDiscrollveScaleX;//宽度缩放
  67. public boolean mDiscrollveScaleY;//高度缩放
  68. public MyLayoutParams(Context context, AttributeSet attrs) {
  69. super(context, attrs);
  70. // 备份自定义属性值
  71. TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DiscrollView_LayoutParams);
  72. mDiscrollveAlpha = a.getBoolean(R.styleable.DiscrollView_LayoutParams_discrollve_alpha, false);
  73. mDiscrollveScaleX = a.getBoolean(R.styleable.DiscrollView_LayoutParams_discrollve_scaleX, false);
  74. mDiscrollveScaleY = a.getBoolean(R.styleable.DiscrollView_LayoutParams_discrollve_scaleY, false);
  75. mDisCrollveTranslation = a.getInt(R.styleable.DiscrollView_LayoutParams_discrollve_translation, -1);
  76. mDiscrollveFromBgColor = a.getColor(R.styleable.DiscrollView_LayoutParams_discrollve_fromBgColor, -1);
  77. mDiscrollveToBgColor = a.getColor(R.styleable.DiscrollView_LayoutParams_discrollve_toBgColor, -1);
  78. a.recycle();
  79. }
  80. }
  81. }

上面代码已经很详细,我们还是有必要解释下这几个重写函数,以及为什么要重写它们。


  
  1. 2.1.1 generateLayoutParams(atrr):
  2. 是在addview之前执行的。由于我们想要在addview里实现为系统控件(如Imageview)添加外层包裹VIEWGOURP,并且把系统控件里的自定义属性赋给“”自定义包裹VIEWGROUP",为了这个自定义VIEWGROUP将来能根据这些属性带着子控件一起飞起来(执行动画)。为了获取这些自定义属性,所以我们得重写generateLayoutParams函数。这个函数返回的LayoutParams恰好是接下来要调用的addview函数的LayoutParams params参数。因此我们在generateLayoutParams函数里从attr里筛选出自定义属性并保存到自定义的MyLayoutParams对象里,将来传递到addview中的LayoutParams就是MyLayoutParams类型。

2.1.2  addView(View child, int index, android.view.ViewGroup.LayoutParams params)

 addView是在generateLayoutParams之后执行,其中params参数就是2.1.1中generateLayoutParams函数返回的MyLayoutParams参数,从这个参数里可以获取到自定义属性,然后在addview系统控件(如Imageview)之前,先创建并添加一个“自定义包裹VIEWGROUP"视图,并将自定义属性赋给这个视图类,最后在把系统控件(如Imageview) *addview到"自定义包裹VIEWGROUP"里,最终一起添加到LinearLayout里。从而实现了在代码中为XML里的每一个系统控件外层包裹一个“自定义包裹VIEWGROUP"视图。

OK,至此我们已经实现了在系统控件外包裹一层可以识别自定义属性的VIEWGROUP父布局,接下来我们就来看一下这个自定义VIEWGROUP是如何执行动画的。

 

2.1 自定义VIEWGROUP:  DiscrollvableView


  
  1. package com.example.animateframe1;
  2. import android.animation.ArgbEvaluator;
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.widget.FrameLayout;
  6. public class DiscrollvableView extends FrameLayout implements DiscrollvableInterface{
  7. private static final int TRANSLATION_FROM_TOP = 0x01;
  8. private static final int TRANSLATION_FROM_BOTTOM = 0x02;
  9. private static final int TRANSLATION_FROM_LEFT = 0x04;
  10. private static final int TRANSLATION_FROM_RIGHT = 0x08;
  11. //颜色估值器
  12. private static ArgbEvaluator sArgbEvaluator = new ArgbEvaluator();
  13. /**
  14. * 自定义属性
  15. */
  16. private int mDiscrollveFromBgColor;//背景颜色变化开始值
  17. private int mDiscrollveToBgColor;//背景颜色变化结束值
  18. private boolean mDiscrollveAlpha;//是否需要透明度动画
  19. private int mDisCrollveTranslation;//平移值
  20. private boolean mDiscrollveScaleX;//是否需要x轴方向缩放
  21. private boolean mDiscrollveScaleY;//是否需要y轴方向缩放
  22. private int mHeight;//本view的高度
  23. private int mWidth;//宽度
  24. public void setmDiscrollveFromBgColor(int mDiscrollveFromBgColor) {
  25. this.mDiscrollveFromBgColor = mDiscrollveFromBgColor;
  26. }
  27. public void setmDiscrollveToBgColor(int mDiscrollveToBgColor) {
  28. this.mDiscrollveToBgColor = mDiscrollveToBgColor;
  29. }
  30. public void setmDiscrollveAlpha(boolean mDiscrollveAlpha) {
  31. this.mDiscrollveAlpha = mDiscrollveAlpha;
  32. }
  33. public void setmDisCrollveTranslation(int mDisCrollveTranslation) {
  34. this.mDisCrollveTranslation = mDisCrollveTranslation;
  35. }
  36. public void setmDiscrollveScaleX(boolean mDiscrollveScaleX) {
  37. this.mDiscrollveScaleX = mDiscrollveScaleX;
  38. }
  39. public void setmDiscrollveScaleY(boolean mDiscrollveScaleY) {
  40. this.mDiscrollveScaleY = mDiscrollveScaleY;
  41. }
  42. @Override
  43. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  44. // TODO Auto-generated method stub
  45. super.onSizeChanged(w, h, oldw, oldh);
  46. mWidth = w;
  47. mHeight = h;
  48. onResetDiscrollve();
  49. }
  50. public DiscrollvableView(Context context, AttributeSet attrs) {
  51. super(context, attrs);
  52. // TODO Auto-generated constructor stub
  53. }
  54. public DiscrollvableView(Context context) {
  55. super(context);
  56. // TODO Auto-generated constructor stub
  57. }
  58. @Override
  59. public void onDiscrollve(float ratio) {
  60. // ratio:0~1
  61. //根据ratio执行动画进度
  62. if(mDiscrollveAlpha){
  63. setAlpha(ratio);
  64. }
  65. if(mDiscrollveScaleX){
  66. setScaleX(ratio);
  67. }
  68. if(mDiscrollveScaleY){
  69. setScaleY(ratio);
  70. }
  71. if(isDiscrollTranslationFrom(TRANSLATION_FROM_BOTTOM)){
  72. setTranslationY(mHeight*(1-ratio));//mHeight-->0(代表原来的位置)
  73. }
  74. if(isDiscrollTranslationFrom(TRANSLATION_FROM_TOP)){
  75. setTranslationY(-mHeight*(1-ratio));//-mHeight-->0(代表原来的位置)
  76. }
  77. if(isDiscrollTranslationFrom(TRANSLATION_FROM_LEFT)){
  78. setTranslationX(-mWidth*(1-ratio));//-width-->0(代表原来的位置)
  79. }
  80. if(isDiscrollTranslationFrom(TRANSLATION_FROM_RIGHT)){
  81. setTranslationX(mWidth*(1-ratio));//width-->0(代表原来的位置)
  82. }
  83. //颜色渐变动画
  84. if(mDiscrollveFromBgColor!=-1&&mDiscrollveToBgColor!=-1){
  85. //ratio=0.5 color=中间颜色
  86. setBackgroundColor((Integer) sArgbEvaluator.evaluate(ratio, mDiscrollveFromBgColor, mDiscrollveToBgColor));
  87. }
  88. }
  89. private boolean isDiscrollTranslationFrom(int translationMask) {
  90. if(mDisCrollveTranslation==-1){
  91. return false;
  92. }
  93. //fromLeft|fromBottom & fromBottom = fromBottom
  94. return (mDisCrollveTranslation & translationMask)==translationMask;
  95. }
  96. @Override
  97. public void onResetDiscrollve() {
  98. //控制自身的动画属性
  99. if(mDiscrollveAlpha){
  100. setAlpha(0);
  101. }
  102. if(mDiscrollveScaleX){
  103. setScaleX(0);
  104. }
  105. if(mDiscrollveScaleY){
  106. setScaleY(0);
  107. }
  108. if(isDiscrollTranslationFrom(TRANSLATION_FROM_BOTTOM)){
  109. setTranslationY(mHeight);//mHeight-->0(代表原来的位置)
  110. }
  111. if(isDiscrollTranslationFrom(TRANSLATION_FROM_TOP)){
  112. setTranslationY(-mHeight);//-mHeight-->0(代表原来的位置)
  113. }
  114. if(isDiscrollTranslationFrom(TRANSLATION_FROM_LEFT)){
  115. setTranslationX(-mWidth);//-width-->0(代表原来的位置)
  116. }
  117. if(isDiscrollTranslationFrom(TRANSLATION_FROM_RIGHT)){
  118. setTranslationX(mWidth);//width-->0(代表原来的位置)
  119. }
  120. }
  121. }

我们发现自定义控件里实现了接口DiscrollvableInterface并重写了

public void onDiscrollve(float ratio)  //根据比例,执行动画进度

public void onResetDiscrollve();//逆向动画,恢复到初始状态。

在这两个函数里会根据自定义属性值与ratio来执行 这个“自定义VIEWGROUP包裹”的动画,从而内部包含的系统控件(如Imageview)等也会跟着动起来。那这两个函数是在什么地方调用的,以及ratio是怎么算出来的,那这个与Scrollview的滑动有关系。那我们就来看一下自定义Scrollview。

2.2 自定义Scrollview

DiscrollView.java


  
  1. package com.example.animateframe1;
  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.util.Log;
  5. import android.view.View;
  6. import android.widget.ScrollView;
  7. public class DiscrollView extends ScrollView {
  8. String TAG = "DiscrollView";
  9. private DiscrollViewContent mContent;
  10. public DiscrollView(Context context, AttributeSet attrs) {
  11. super(context, attrs);
  12. // TODO Auto-generated constructor stub
  13. }
  14. @Override
  15. protected void onFinishInflate() {
  16. // TODO Auto-generated method stub
  17. super.onFinishInflate();
  18. View content = getChildAt(0);
  19. mContent = (DiscrollViewContent)content;
  20. }
  21. @Override
  22. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  23. // TODO Auto-generated method stub
  24. super.onSizeChanged(w, h, oldw, oldh);
  25. View first = mContent.getChildAt(0);
  26. first.getLayoutParams().height = getHeight();
  27. }
  28. @Override
  29. protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  30. // TODO Auto-generated method stub
  31. super.onScrollChanged(l, t, oldl, oldt);
  32. int scrollViewHeight = getHeight();
  33. //监听滑动----接口---->控制DiscrollViewContent的属性
  34. for(int i=0;i<mContent.getChildCount();i++){//遍历MyLinearLayout里面所有子控件(MyViewGroup)
  35. View child = mContent.getChildAt(i);
  36. if(!(child instanceof DiscrollvableInterface)){
  37. continue;
  38. }
  39. //ratio:0~1
  40. DiscrollvableInterface discrollvableInterface = (DiscrollvableInterface) child;
  41. //1.child离scrollview顶部的高度 a
  42. int discrollvableTop = child.getTop();
  43. int discrollvableHeight = child.getHeight();
  44. //2.得到scrollview滑出去的高度 b 就是int t,
  45. //3.得到child离屏幕顶部的高度 c
  46. int discrollvableAbsoluteTop = discrollvableTop - t;
  47. Log.i(TAG,"discrollvableHeight0="+discrollvableHeight+
  48. "\r\nscrollViewHeight="+scrollViewHeight+",discrollvableAbsoluteTop="+discrollvableAbsoluteTop+"\r\nt="+t+",discrollvableTop="+discrollvableTop);//一屏的高度
  49. //什么时候执行动画?当child滑进屏幕的时候
  50. if(discrollvableAbsoluteTop <= scrollViewHeight)
  51. {
  52. int visibleGap = scrollViewHeight - discrollvableAbsoluteTop;
  53. Log.i(TAG,"visibleGap="+visibleGap+",discrollvableHeight="+discrollvableHeight+
  54. "\r\nscrollViewHeight="+scrollViewHeight+",discrollvableAbsoluteTop="+discrollvableAbsoluteTop+"\r\nt="+t+",discrollvableTop="+discrollvableTop);//一屏的高度
  55. //确保ratio是在0~1,超过了1 也设置为1
  56. discrollvableInterface.onDiscrollve(clamp(visibleGap/(float)discrollvableHeight, 1f,0f));
  57. }else{//否则,就恢复到原来的位置
  58. discrollvableInterface.onResetDiscrollve();
  59. }
  60. }
  61. }
  62. public static float clamp(float value, float max, float min){
  63. return Math.max(Math.min(value, max), min);
  64. }
  65. }

我们主要来看一下onScrollChanged函数:


  
  1. @Override
  2. protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  3. 参数:left:滚动后,滚动条左端水平方向上的x位置。
  4. 参数:top:滚动后,滚动条上端垂直方向上的y位置
  5. 参数:oldl:滚动前,滚动条左端水平方向上的x位置。
  6. 参数:oldt:滚动前,滚动条上端垂直方向上的y位置
  7. super.onScrollChanged(l, t, oldl, oldt);
  8. int scrollViewHeight = getHeight();这个scrollViewHeight 实质就是一屏的高度。
  9. //for选好遍历“自定义VIWEGROUP”,根据滑动距离比例,执行动画
  10. for(int i=0;i<mContent.getChildCount();i++){
  11.   View child = mContent.getChildAt(i);
  12. if(!(child instanceof DiscrollvableInterface)){
  13. continue;
  14. }
  15. 由于自定义VIEWGROUP包裹都实现了DiscrollvableInterface,所以没有实现的就没有包裹,不用执行动画直接continue
  16. //ratio:0~1
  17. DiscrollvableInterface discrollvableInterface = (DiscrollvableInterface) child;
  18. //1.childscrollview顶部的高度 a
  19. int discrollvableTop = child.getTop();
  20. int discrollvableHeight = child.getHeight();//执行动画时的总距离,比如平移
  21. //2.得到scrollview滑出去的高度 就是参数int t,
  22. //3.得到child离屏幕顶部的高度
  23. int discrollvableAbsoluteTop = discrollvableTop - t;//离屏幕顶端的初始高度 减去 滚动的距离就是当前时刻离屏幕顶端的高度
  24. //当前时刻离屏幕顶端的的距离 如果 小于 1屏的高度时,说明VIEWGROUP已进入屏幕,则开始执行动画
  25. if(discrollvableAbsoluteTop <= scrollViewHeight)
  26. {
  27. 表示当上滑屏幕时,VIEWGROUP从屏幕底部探出的高度visibleGap
  28. int visibleGap = scrollViewHeight - discrollvableAbsoluteTop;
  29. //确保ratio是在0~1,超过了1 也设置为1visibleGap / VIWGROUP控件的总高度就是ratio,执行动画的进度比例
  30. discrollvableInterface.onDiscrollve(clamp(visibleGap/(float)discrollvableHeight, 1f,0f));
  31. }else{//否则,就恢复到原来的位置
  32. discrollvableInterface.onResetDiscrollve();
  33. }
  34. }
  35. }

OK,所有流程就分析完了。现在总结一下思路:

1. 自定义LinearLayout的addview,让添加imageview等系统控件前,先在外层包裹一个自定义VIEWGROUP,并赋予它自定义属性的配置。

2. 自定义VIEWGROUP,接收滑动的ratio来执行动画进度

3. 自定义Scrollview,计算滑动的ratio,并调用自定义VIEWGROUP里的执行动画函数。

源码下载地址:https://download.csdn.net/download/gaoxiaoweiandy/11136228

 

 

 

文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/89379459

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。