Android高级UI开发(二十九)自定义动画框架-让scrollview里的所有控件随着滑动的距离执行各自的动画
这次我们做一个动画框架,配置scrollview里包含的控件的自定义属性,就可以实现滑动Scrollview时,里面的控件根据滑动的距离执行各自的动画进度。scrollivew里包含的这些控件可以是任意常用的控件,如 imageView,Button,TextView等。我们将给这些普通的系统控件配置自定义属性!看到这里是不是觉得无法实现,因为系统的ImageView,Button等是无法识别我们自定义的属性值的,系统的控件怎么识别我们随便定义的属性呢。今天我们就来解决这个问题,解决这个问题的意义在于让系统控件能像我们自定义控件一样,配置了属性就可以执行相应的动画。我们先来看一下运行效果:
源码下载地址:https://download.csdn.net/download/gaoxiaoweiandy/11136228。
我们还是从界面布局讲起,直观上分析一下。
1. 布局
activity_main.xml
-
<com.example.animateframe1.DiscrollView 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"
-
xmlns:app="http://schemas.android.com/apk/res/com.example.animateframe1">
-
<com.example.animateframe1.DiscrollViewContent
-
android:layout_width="match_parent"
-
android:layout_height="match_parent">
-
-
<TextView
-
android:layout_width="match_parent"
-
android:layout_height="600dp"
-
android:background="@android:color/white"
-
android:textColor="@android:color/black"
-
android:textSize="25sp"
-
android:padding="25dp"
-
tools:visibility="gone"
-
android:gravity="center"
-
android:fontFamily="serif"
-
android:text="冯绍峰对着倪妮发誓说:‘’如果有一天我离开了你,我就把名字倒着念‘’。倪妮说:‘我也是’’!——尼玛,看着我也是醉了!" />
-
-
<View
-
android:layout_width="match_parent"
-
android:layout_height="200dp"
-
android:background="#007788"
-
app:discrollve_alpha="true"
-
/>
-
-
<ImageView
-
android:layout_width="200dp"
-
android:layout_height="120dp"
-
app:discrollve_alpha="true"
-
app:discrollve_translation="fromLeft|fromBottom"
-
android:src="@drawable/baggage" />
-
-
<View
-
android:layout_width="match_parent"
-
android:layout_height="200dp"
-
app:discrollve_fromBgColor="#ffff00"
-
app:discrollve_toBgColor="#88EE66" />
-
-
<ImageView
-
android:layout_width="220dp"
-
android:layout_height="110dp"
-
android:layout_gravity="right"
-
android:src="@drawable/camera"
-
app:discrollve_translation="fromRight" />
-
-
<TextView
-
android:layout_width="match_parent"
-
android:layout_height="wrap_content"
-
android:padding="20dp"
-
android:fontFamily="serif"
-
android:gravity="center"
-
android:text="眼见范冰冰与李晨在一起了,孩子会取名李冰冰;李冰冰唯有嫁给范伟,生个孩子叫范冰冰,方能扳回一城。"
-
android:textSize="23sp"
-
app:discrollve_alpha="true"
-
app:discrollve_translation="fromBottom" />
-
-
<ImageView
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:layout_margin="20dp"
-
android:layout_gravity="center"
-
android:src="@drawable/sweet"
-
app:discrollve_scaleX="true"
-
app:discrollve_scaleY="true" />
-
<ImageView
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:layout_margin="20dp"
-
android:layout_gravity="center"
-
android:src="@drawable/camera"
-
app:discrollve_translation="fromLeft|fromBottom"
-
/>
-
-
</com.example.animateframe1.DiscrollViewContent>
-
-
</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 )
-
package com.example.animateframe1;
-
-
import android.content.Context;
-
import android.content.res.TypedArray;
-
import android.util.AttributeSet;
-
import android.view.View;
-
import android.widget.LinearLayout;
-
-
public class DiscrollViewContent extends LinearLayout {
-
-
public DiscrollViewContent(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
setOrientation(VERTICAL);
-
}
-
-
/**
-
* 这个函数在加载XML布局时自动调用,可以获取到每一个系统控件配置的布局参数,包括自定义参数。
-
* 每加载一个系统控件(如Imageview),则调用一次这个函数。
-
* @param attrs
-
* @return
-
*/
-
@Override
-
public LayoutParams generateLayoutParams(AttributeSet attrs) {
-
-
//从attrs所有参数里提取自定义属性值,并保持在MyLayoutParams对象里,以供“自定义包裹VIEWGROUP"使用并执行动画。
-
return new MyLayoutParams(getContext(),attrs);
-
}
-
-
/**
-
* 这个函数是在generateLayoutParams之后执行,在这里我们可以获取到generateLayoutParams函数返回的MyLayoutParams里的自定义属性值。
-
* 然后在addview系统控件(如Imageview)之前,先创建并添加一个“自定义包裹VIEWGROUP"视图,然后将自定义属性赋给这个视图,最后在把系统控件
-
* addview到"自定义包裹VIEWGROUP"里,从而实现了在代码中为XML里的每一个系统控件外层包裹一个“自定义包裹VIEWGROUP"视图。
-
* @param child
-
* @param index
-
* @param params
-
*/
-
@Override
-
public void addView(View child, int index,
-
android.view.ViewGroup.LayoutParams params) {
-
MyLayoutParams p = (MyLayoutParams) params;
-
if(!isDiscrollvable(p)){ //没有自定义属性的系统控件,我们就不需要外层包裹一个“自定义包裹VIEWGROUP"视图。直接addview即可。
-
super.addView(child, index, params);
-
}else{
-
//有自定义属性的系统控件,我们需要外层包裹一个“自定义包裹VIEWGROUP"视图。
-
DiscrollvableView discrollvableView = new DiscrollvableView(getContext());
-
discrollvableView.setmDiscrollveAlpha(p.mDiscrollveAlpha);
-
discrollvableView.setmDisCrollveTranslation(p.mDisCrollveTranslation);
-
discrollvableView.setmDiscrollveScaleX(p.mDiscrollveScaleX);
-
discrollvableView.setmDiscrollveScaleY(p.mDiscrollveScaleY);
-
discrollvableView.setmDiscrollveFromBgColor(p.mDiscrollveFromBgColor);
-
discrollvableView.setmDiscrollveToBgColor(p.mDiscrollveToBgColor);
-
-
//先为child包裹一个外层视图
-
discrollvableView.addView(child);
-
//然后再把外层父视图添加到LinearLayout里。
-
super.addView(discrollvableView, index, params);
-
}
-
}
-
-
private boolean isDiscrollvable(MyLayoutParams p) {
-
// TODO Auto-generated method stub
-
return p.mDiscrollveAlpha||
-
p.mDiscrollveScaleX||
-
p.mDiscrollveScaleY||
-
p.mDisCrollveTranslation!=-1||
-
(p.mDiscrollveFromBgColor!=-1&&
-
p.mDiscrollveToBgColor!=-1);
-
}
-
-
public static class MyLayoutParams extends LayoutParams{
-
public int mDiscrollveFromBgColor;//背景颜色变化开始值
-
public int mDiscrollveToBgColor;//背景颜色变化结束值
-
public boolean mDiscrollveAlpha;//透明度
-
public int mDisCrollveTranslation;//平移ֵ
-
public boolean mDiscrollveScaleX;//宽度缩放
-
public boolean mDiscrollveScaleY;//高度缩放
-
-
public MyLayoutParams(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
// 备份自定义属性值
-
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DiscrollView_LayoutParams);
-
mDiscrollveAlpha = a.getBoolean(R.styleable.DiscrollView_LayoutParams_discrollve_alpha, false);
-
mDiscrollveScaleX = a.getBoolean(R.styleable.DiscrollView_LayoutParams_discrollve_scaleX, false);
-
mDiscrollveScaleY = a.getBoolean(R.styleable.DiscrollView_LayoutParams_discrollve_scaleY, false);
-
mDisCrollveTranslation = a.getInt(R.styleable.DiscrollView_LayoutParams_discrollve_translation, -1);
-
mDiscrollveFromBgColor = a.getColor(R.styleable.DiscrollView_LayoutParams_discrollve_fromBgColor, -1);
-
mDiscrollveToBgColor = a.getColor(R.styleable.DiscrollView_LayoutParams_discrollve_toBgColor, -1);
-
a.recycle();
-
}
-
-
}
-
-
-
}
上面代码已经很详细,我们还是有必要解释下这几个重写函数,以及为什么要重写它们。
-
2.1.1 generateLayoutParams(atrr):
-
是在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
-
package com.example.animateframe1;
-
import android.animation.ArgbEvaluator;
-
import android.content.Context;
-
import android.util.AttributeSet;
-
import android.widget.FrameLayout;
-
-
public class DiscrollvableView extends FrameLayout implements DiscrollvableInterface{
-
private static final int TRANSLATION_FROM_TOP = 0x01;
-
private static final int TRANSLATION_FROM_BOTTOM = 0x02;
-
private static final int TRANSLATION_FROM_LEFT = 0x04;
-
private static final int TRANSLATION_FROM_RIGHT = 0x08;
-
-
//颜色估值器
-
private static ArgbEvaluator sArgbEvaluator = new ArgbEvaluator();
-
/**
-
* 自定义属性
-
*/
-
private int mDiscrollveFromBgColor;//背景颜色变化开始值
-
private int mDiscrollveToBgColor;//背景颜色变化结束值
-
private boolean mDiscrollveAlpha;//是否需要透明度动画
-
private int mDisCrollveTranslation;//平移值
-
private boolean mDiscrollveScaleX;//是否需要x轴方向缩放
-
private boolean mDiscrollveScaleY;//是否需要y轴方向缩放
-
private int mHeight;//本view的高度
-
private int mWidth;//宽度
-
-
public void setmDiscrollveFromBgColor(int mDiscrollveFromBgColor) {
-
this.mDiscrollveFromBgColor = mDiscrollveFromBgColor;
-
}
-
-
public void setmDiscrollveToBgColor(int mDiscrollveToBgColor) {
-
this.mDiscrollveToBgColor = mDiscrollveToBgColor;
-
}
-
-
public void setmDiscrollveAlpha(boolean mDiscrollveAlpha) {
-
this.mDiscrollveAlpha = mDiscrollveAlpha;
-
}
-
-
public void setmDisCrollveTranslation(int mDisCrollveTranslation) {
-
this.mDisCrollveTranslation = mDisCrollveTranslation;
-
}
-
-
public void setmDiscrollveScaleX(boolean mDiscrollveScaleX) {
-
this.mDiscrollveScaleX = mDiscrollveScaleX;
-
}
-
-
public void setmDiscrollveScaleY(boolean mDiscrollveScaleY) {
-
this.mDiscrollveScaleY = mDiscrollveScaleY;
-
}
-
-
@Override
-
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-
// TODO Auto-generated method stub
-
super.onSizeChanged(w, h, oldw, oldh);
-
mWidth = w;
-
mHeight = h;
-
onResetDiscrollve();
-
}
-
-
-
public DiscrollvableView(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
// TODO Auto-generated constructor stub
-
}
-
-
public DiscrollvableView(Context context) {
-
super(context);
-
// TODO Auto-generated constructor stub
-
}
-
-
@Override
-
public void onDiscrollve(float ratio) {
-
// ratio:0~1
-
//根据ratio执行动画进度
-
if(mDiscrollveAlpha){
-
setAlpha(ratio);
-
}
-
if(mDiscrollveScaleX){
-
setScaleX(ratio);
-
}
-
if(mDiscrollveScaleY){
-
setScaleY(ratio);
-
}
-
-
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_BOTTOM)){
-
setTranslationY(mHeight*(1-ratio));//mHeight-->0(代表原来的位置)
-
}
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_TOP)){
-
setTranslationY(-mHeight*(1-ratio));//-mHeight-->0(代表原来的位置)
-
}
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_LEFT)){
-
setTranslationX(-mWidth*(1-ratio));//-width-->0(代表原来的位置)
-
}
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_RIGHT)){
-
setTranslationX(mWidth*(1-ratio));//width-->0(代表原来的位置)
-
}
-
-
//颜色渐变动画
-
if(mDiscrollveFromBgColor!=-1&&mDiscrollveToBgColor!=-1){
-
//ratio=0.5 color=中间颜色
-
setBackgroundColor((Integer) sArgbEvaluator.evaluate(ratio, mDiscrollveFromBgColor, mDiscrollveToBgColor));
-
}
-
-
}
-
-
private boolean isDiscrollTranslationFrom(int translationMask) {
-
if(mDisCrollveTranslation==-1){
-
return false;
-
}
-
//fromLeft|fromBottom & fromBottom = fromBottom
-
return (mDisCrollveTranslation & translationMask)==translationMask;
-
}
-
-
@Override
-
public void onResetDiscrollve() {
-
//控制自身的动画属性
-
if(mDiscrollveAlpha){
-
setAlpha(0);
-
}
-
if(mDiscrollveScaleX){
-
setScaleX(0);
-
}
-
if(mDiscrollveScaleY){
-
setScaleY(0);
-
}
-
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_BOTTOM)){
-
setTranslationY(mHeight);//mHeight-->0(代表原来的位置)
-
}
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_TOP)){
-
setTranslationY(-mHeight);//-mHeight-->0(代表原来的位置)
-
}
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_LEFT)){
-
setTranslationX(-mWidth);//-width-->0(代表原来的位置)
-
}
-
if(isDiscrollTranslationFrom(TRANSLATION_FROM_RIGHT)){
-
setTranslationX(mWidth);//width-->0(代表原来的位置)
-
}
-
-
}
-
-
}
我们发现自定义控件里实现了接口DiscrollvableInterface并重写了
public void onDiscrollve(float ratio) //根据比例,执行动画进度
public void onResetDiscrollve();//逆向动画,恢复到初始状态。
在这两个函数里会根据自定义属性值与ratio来执行 这个“自定义VIEWGROUP包裹”的动画,从而内部包含的系统控件(如Imageview)等也会跟着动起来。那这两个函数是在什么地方调用的,以及ratio是怎么算出来的,那这个与Scrollview的滑动有关系。那我们就来看一下自定义Scrollview。
2.2 自定义Scrollview
DiscrollView.java
-
package com.example.animateframe1;
-
-
import android.content.Context;
-
import android.util.AttributeSet;
-
import android.util.Log;
-
import android.view.View;
-
import android.widget.ScrollView;
-
-
public class DiscrollView extends ScrollView {
-
String TAG = "DiscrollView";
-
-
private DiscrollViewContent mContent;
-
-
public DiscrollView(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
// TODO Auto-generated constructor stub
-
}
-
-
@Override
-
protected void onFinishInflate() {
-
// TODO Auto-generated method stub
-
super.onFinishInflate();
-
View content = getChildAt(0);
-
mContent = (DiscrollViewContent)content;
-
}
-
-
@Override
-
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-
// TODO Auto-generated method stub
-
super.onSizeChanged(w, h, oldw, oldh);
-
View first = mContent.getChildAt(0);
-
first.getLayoutParams().height = getHeight();
-
}
-
-
-
@Override
-
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
-
// TODO Auto-generated method stub
-
super.onScrollChanged(l, t, oldl, oldt);
-
-
int scrollViewHeight = getHeight();
-
-
//监听滑动----接口---->控制DiscrollViewContent的属性
-
for(int i=0;i<mContent.getChildCount();i++){//遍历MyLinearLayout里面所有子控件(MyViewGroup)
-
View child = mContent.getChildAt(i);
-
if(!(child instanceof DiscrollvableInterface)){
-
continue;
-
}
-
-
//ratio:0~1
-
DiscrollvableInterface discrollvableInterface = (DiscrollvableInterface) child;
-
//1.child离scrollview顶部的高度 a
-
int discrollvableTop = child.getTop();
-
int discrollvableHeight = child.getHeight();
-
-
//2.得到scrollview滑出去的高度 b 就是int t,
-
//3.得到child离屏幕顶部的高度 c
-
int discrollvableAbsoluteTop = discrollvableTop - t;
-
-
Log.i(TAG,"discrollvableHeight0="+discrollvableHeight+
-
"\r\nscrollViewHeight="+scrollViewHeight+",discrollvableAbsoluteTop="+discrollvableAbsoluteTop+"\r\nt="+t+",discrollvableTop="+discrollvableTop);//一屏的高度
-
//什么时候执行动画?当child滑进屏幕的时候
-
if(discrollvableAbsoluteTop <= scrollViewHeight)
-
{
-
-
-
int visibleGap = scrollViewHeight - discrollvableAbsoluteTop;
-
-
Log.i(TAG,"visibleGap="+visibleGap+",discrollvableHeight="+discrollvableHeight+
-
"\r\nscrollViewHeight="+scrollViewHeight+",discrollvableAbsoluteTop="+discrollvableAbsoluteTop+"\r\nt="+t+",discrollvableTop="+discrollvableTop);//一屏的高度
-
-
//确保ratio是在0~1,超过了1 也设置为1
-
discrollvableInterface.onDiscrollve(clamp(visibleGap/(float)discrollvableHeight, 1f,0f));
-
}else{//否则,就恢复到原来的位置
-
discrollvableInterface.onResetDiscrollve();
-
}
-
}
-
}
-
-
public static float clamp(float value, float max, float min){
-
return Math.max(Math.min(value, max), min);
-
}
-
-
}
我们主要来看一下onScrollChanged函数:
-
@Override
-
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
-
参数:left:滚动后,滚动条左端水平方向上的x位置。
-
参数:top:滚动后,滚动条上端垂直方向上的y位置
-
-
参数:oldl:滚动前,滚动条左端水平方向上的x位置。
-
参数:oldt:滚动前,滚动条上端垂直方向上的y位置
-
-
-
super.onScrollChanged(l, t, oldl, oldt);
-
-
int scrollViewHeight = getHeight();这个scrollViewHeight 实质就是一屏的高度。
-
-
-
//for选好遍历“自定义VIWEGROUP”,根据滑动距离比例,执行动画
-
for(int i=0;i<mContent.getChildCount();i++){
-
-
View child = mContent.getChildAt(i);
-
if(!(child instanceof DiscrollvableInterface)){
-
continue;
-
}
-
由于自定义VIEWGROUP包裹都实现了DiscrollvableInterface,所以没有实现的就没有包裹,不用执行动画直接continue。
-
-
//ratio:0~1
-
DiscrollvableInterface discrollvableInterface = (DiscrollvableInterface) child;
-
//1.child离scrollview顶部的高度 a
-
int discrollvableTop = child.getTop();
-
int discrollvableHeight = child.getHeight();//执行动画时的总距离,比如平移
-
-
//2.得到scrollview滑出去的高度 就是参数int t,
-
//3.得到child离屏幕顶部的高度
-
int discrollvableAbsoluteTop = discrollvableTop - t;//离屏幕顶端的初始高度 减去 滚动的距离就是当前时刻离屏幕顶端的高度
-
-
//当前时刻离屏幕顶端的的距离 如果 小于 1屏的高度时,说明VIEWGROUP已进入屏幕,则开始执行动画
-
if(discrollvableAbsoluteTop <= scrollViewHeight)
-
{
-
-
表示当上滑屏幕时,VIEWGROUP从屏幕底部探出的高度visibleGap
-
int visibleGap = scrollViewHeight - discrollvableAbsoluteTop;
-
-
//确保ratio是在0~1,超过了1 也设置为1,visibleGap / VIWGROUP控件的总高度就是ratio,执行动画的进度比例
-
discrollvableInterface.onDiscrollve(clamp(visibleGap/(float)discrollvableHeight, 1f,0f));
-
}else{//否则,就恢复到原来的位置
-
discrollvableInterface.onResetDiscrollve();
-
}
-
}
-
}
-
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
- 点赞
- 收藏
- 关注作者
评论(0)