home-school-contact-app/文档/Android/app/src/main/java/com/example/nanchen/aiyaschoolpush/behavior/SimpleViewBehavior.java

283 lines
13 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.example.nanchen.aiyaschoolpush.behavior;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import com.example.nanchen.aiyaschoolpush.R;
/**
* @author nanchen
* @fileName AiYaSchoolPush
* @packageName com.example.nanchen.aiyaschoolpush.behavior
* @date 2016/12/20 14:00
*/
public class SimpleViewBehavior extends CoordinatorLayout.Behavior<View> {
private static final int UNSPECIFIED_INT = Integer.MAX_VALUE;
private static final float UNSPECIFIED_FLOAT = Float.MAX_VALUE;
private static final int DEPEND_TYPE_HEIGHT = 0;
private static final int DEPEND_TYPE_WIDTH = 1;
private static final int DEPEND_TYPE_X = 2;
private static final int DEPEND_TYPE_Y = 3;
private int mDependViewId = 0; //默认没有依赖对象
private int mDependType = DEPEND_TYPE_Y; //默认按照y方向变化
private int mDependTargetX; //X方向的允许最大距离(影响动画percent)
private int mDependTargetY; //Y方向的允许最大距离(影响动画percent)
private int mDependTargetWidth; //依赖控件起始最大宽度(影响动画percent)
private int mDependTargetHeight; //依赖控件起始最大高度(影响动画percent)
private int targetX;
private int targetY;
private int targetWidth;
private int targetHeight;
private int targetBackgroundColor;
private float targetAlpha;
private float targetRotateX;
private float targetRotateY;
private int mAnimationId = 0; //自定义动画id(xml文件定义动画)
private int mDependStartX;
private int mDependStartY;
private int mDependStartWidth;
private int mDependStartHeight;
private int mStartX;
private int mStartY;
private int mStartWidth;
private int mStartHeight;
private int mStartBackgroundColor;
private float mStartAlpha;
private float mStartRotateX;
private float mStartRotateY;
private Animation mAnimation;
private boolean isPrepared;
public SimpleViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SimpleViewBehavior);
mDependViewId = a.getResourceId(R.styleable.SimpleViewBehavior_svb_dependOn, mDependViewId);
mDependType = a.getInt(R.styleable.SimpleViewBehavior_svb_dependType, mDependType);
mDependTargetX = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetX, UNSPECIFIED_INT);
mDependTargetY = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetY, UNSPECIFIED_INT);
mDependTargetWidth = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetWidth, UNSPECIFIED_INT);
mDependTargetHeight = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetHeight, UNSPECIFIED_INT);
targetX = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetX, UNSPECIFIED_INT);
targetY = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetY, UNSPECIFIED_INT);
targetWidth = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetWidth, UNSPECIFIED_INT);
targetHeight = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetHeight, UNSPECIFIED_INT);
targetBackgroundColor = a.getColor(R.styleable.SimpleViewBehavior_svb_targetBackgroundColor, UNSPECIFIED_INT);
targetAlpha = a.getFloat(R.styleable.SimpleViewBehavior_svb_targetAlpha, UNSPECIFIED_FLOAT);
targetRotateX = a.getFloat(R.styleable.SimpleViewBehavior_svb_targetRotateX, UNSPECIFIED_FLOAT);
targetRotateY = a.getFloat(R.styleable.SimpleViewBehavior_svb_targetRotateY, UNSPECIFIED_FLOAT);
mAnimationId = a.getResourceId(R.styleable.SimpleViewBehavior_svb_animation, mAnimationId);
a.recycle();
}
/** 初始化数据 */
private void prepare(CoordinatorLayout parent, View child, View dependency) {
mDependStartX = (int) dependency.getX();
mDependStartY = (int) dependency.getY();
mDependStartWidth = dependency.getWidth();
mDependStartHeight = dependency.getHeight();
mStartX = (int) child.getX();
mStartY = (int) child.getY();
mStartWidth = child.getWidth();
mStartHeight = child.getHeight();
mStartAlpha = child.getAlpha();
mStartRotateX = child.getRotationX();
mStartRotateY = child.getRotationY();
//特殊处理y方向变化
if (mDependTargetY == UNSPECIFIED_INT && dependency instanceof AppBarLayout) {
mDependTargetY = ((AppBarLayout) dependency).getTotalScrollRange();
}
// 背景颜色渐变
if (child.getBackground() instanceof ColorDrawable) mStartBackgroundColor = ((ColorDrawable) child.getBackground()).getColor();
// 自定义动画
if (mAnimationId != 0) {
mAnimation = AnimationUtils.loadAnimation(child.getContext(), mAnimationId);
mAnimation.initialize(child.getWidth(), child.getHeight(), parent.getWidth(), parent.getHeight());
}
// 兼容5.0以上的沉浸模式
if (Build.VERSION.SDK_INT > 16 && parent.getFitsSystemWindows() && targetY != UNSPECIFIED_INT) {
targetY += getStatusBarHeight(parent.getContext());
}
isPrepared = true;
}
/**
* child 是指应用behavior的View dependency 担任触发behavior的角色并与child进行互动。
* layoutDependsOn方法在每次layout发生变化时都会调用我们需要在dependency控件发生变化时返回True
* 在我们的例子中是用户在屏幕上滑动时因为AppBarLayout发生了移动然后我们需要让child做出相应的反应。
*/
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency.getId() == mDependViewId;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
// 该方法会在滑动的时候一直回调,但只需要初始化一次
if (!isPrepared) prepare(parent, child, dependency);
updateView(child, dependency);
return false;
}
/**
* 这个是CoordinatorLayout在进行measure的过程中利用Behavior对象对子view进行大小测量的一个方法。
* 在这个方法内我们可以通过parent.getDependencies(child);这个方法获取到这个child依赖的view然后通过获取这个child依赖的view的大小来决定自身的大小。
*/
@Override
public boolean onMeasureChild(CoordinatorLayout parent, View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
}
/**
* 这个方法是用来子view用来布局自身使用如果依赖其他view那么系统会首先调用
* public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency)
* 这个方法可以在这个回调中记录dependency的一些位置信息在onLayoutChild中利用保存下来的信息进行计算然后得到自身的具体位置。
*/
@Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
boolean bool = super.onLayoutChild(parent, child, layoutDirection);
if (isPrepared) updateView(child, parent.getDependencies(child).get(0));
return bool;
}
public void updateView(View child, View dependency) {
float percent = 0;
float start = 0;
float current = 0;
float end = UNSPECIFIED_INT;
switch (mDependType) {
case DEPEND_TYPE_WIDTH:
start = mDependStartWidth;
current = dependency.getWidth();
end = mDependTargetWidth;
break;
case DEPEND_TYPE_HEIGHT:
start = mDependStartHeight;
current = dependency.getHeight();
end = mDependTargetHeight;
break;
case DEPEND_TYPE_X:
start = mDependStartX;
current = dependency.getX();
end = mDependTargetX;
break;
case DEPEND_TYPE_Y:
start = mDependStartY;
current = dependency.getY();
end = mDependTargetY;
break;
}
if (end != UNSPECIFIED_INT) {
percent = Math.abs(current - start) / Math.abs(end - start);
}
updateViewWithPercent(child, percent > 1 ? 1 : percent);
}
/** 更新View */
@SuppressWarnings("ResourceType")
public void updateViewWithPercent(View child, float percent) {
if (mAnimation == null) {
//如果没有自定义动画,那么使用属性动画
float newX = targetX == UNSPECIFIED_INT ? 0 : (targetX - mStartX) * percent;
float newY = targetY == UNSPECIFIED_INT ? 0 : (targetY - mStartY) * percent;
//缩放动画
if (targetWidth != UNSPECIFIED_INT || targetHeight != UNSPECIFIED_INT) {
child.setScaleX(scaleEvaluator(mStartWidth, targetWidth, percent));
child.setScaleY(scaleEvaluator(mStartHeight, targetHeight, percent));
float newWidth = floatEvaluator(mStartWidth, targetWidth, percent);
float newHeight = floatEvaluator(mStartWidth, targetWidth, percent);
newX -= (mStartWidth - newWidth) / 2;
newY -= (mStartHeight - newHeight) / 2;
}
//平移动画
child.setTranslationX(newX);
child.setTranslationY(newY);
//透明度变化
if (targetAlpha != UNSPECIFIED_FLOAT) child.setAlpha(floatEvaluator(mStartAlpha, targetAlpha, percent));
//背景渐变
if (targetBackgroundColor != UNSPECIFIED_INT && mStartBackgroundColor != 0) {
child.setBackgroundColor(argbEvaluator(mStartBackgroundColor, targetBackgroundColor, percent));
}
//旋转动画
if (targetRotateX != UNSPECIFIED_FLOAT) child.setRotationX(floatEvaluator(mStartRotateX, targetRotateX, percent));
if (targetRotateY != UNSPECIFIED_FLOAT) child.setRotationY(floatEvaluator(mStartRotateY, targetRotateY, percent));
} else {
mAnimation.setStartTime(0);
mAnimation.restrictDuration(100);
Transformation transformation = new Transformation();
mAnimation.getTransformation((long) (percent * 100), transformation);
BehaviorAnimation animation = new BehaviorAnimation(transformation);
child.startAnimation(animation);
}
child.requestLayout();
}
private static class BehaviorAnimation extends Animation {
private Transformation mTransformation;
public BehaviorAnimation(Transformation transformation) {
mTransformation = transformation;
setDuration(0);
setFillAfter(true);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
t.compose(mTransformation);
super.applyTransformation(interpolatedTime, t);
}
}
public static float floatEvaluator(float originalSize, float finalSize, float percent) {
return (finalSize - originalSize) * percent + originalSize;
}
public static float scaleEvaluator(float originalSize, float finalSize, float percent) {
float calcSize = (finalSize - originalSize) * percent + originalSize;
return calcSize / originalSize;
}
public static int argbEvaluator(int startColor, int endColor, float percent) {
int startA = (startColor >> 24) & 0xff;
int startR = (startColor >> 16) & 0xff;
int startG = (startColor >> 8) & 0xff;
int startB = startColor & 0xff;
int endA = (endColor >> 24) & 0xff;
int endR = (endColor >> 16) & 0xff;
int endG = (endColor >> 8) & 0xff;
int endB = endColor & 0xff;
return ((startA + (int) (percent * (endA - startA))) << 24) |
((startR + (int) (percent * (endR - startR))) << 16) |
((startG + (int) (percent * (endG - startG))) << 8) |
((startB + (int) (percent * (endB - startB))));
}
/** 获取状态栏的高度 */
private static int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}