我是看的大佬的 Demo
https://me.csdn.net/qq_30447263
这个的应用场景很多,除了动画 自己需要摸索 就是这个Behavior延伸了
此处为动画
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.BaseOnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//下降分度
float fraction = -verticalOffset * 1.f / (mIdTvMoving.getHeight() - mIdTvMoving.getMinHeight());
int color = ColUtils.evaluateColor(fraction, 0xffF07054, 0xff3F51B5);
mIdTvMoving.setBackgroundColor(color);//颜色过渡
mIdTvMoving.setTextSize(40 * (1 - fraction));//字号缩小
mIdTvMoving.setTranslationX(-fraction * mIdTvMoving.getWidth());//X平移
}
});
public class ColUtils {
/**
* 改变一个颜色的透明度
*
* @param color
* @param alpha
*/
public static int changeColorAlpha(int color, int alpha) {
int a = (color >> 24) & 0xFF;
a = (int) (a * (alpha / 255f));
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = color & 0xFF;
return (a << 24) | (r << 16) | (g << 8) | b;
}
/**
* 返回随机颜色
*
* @return 随机颜色
*/
public static int randomColor() {
Random random = new Random();
int a = 250 + random.nextInt(255);
int r = 30 + random.nextInt(200);
int g = 30 + random.nextInt(200);
int b = 30 + random.nextInt(200);
int randomColor = Color.argb(a, r, g, b);
return randomColor;
}
/**
* 返回随机颜色
*
* @return 随机颜色
*/
public static int randomRGB() {
Random random = new Random();
int r = 30 + random.nextInt(200);
int g = 30 + random.nextInt(200);
int b = 30 + random.nextInt(200);
return Color.rgb(r, g, b);
}
/**
* 颜色变换
*
* @param fraction 分度值
* @param startValue 开始色
* @param endValue 结束色
* @return 分度值处颜色
*/
public static int evaluateColor(float fraction, int startValue,
int endValue) {
int startA = (startValue >> 24) & 0xff;
int startR = (startValue >> 16) & 0xff;
int startG = (startValue >> 8) & 0xff;
int startB = startValue & 0xff;
int endA = (endValue >> 24) & 0xff;
int endR = (endValue >> 16) & 0xff;
int endG = (endValue >> 8) & 0xff;
int endB = endValue & 0xff;
return (startA + (int) (fraction * (endA - startA)) << 24)
| (startR + (int) (fraction * (endR - startR)) << 16)
| (startG + (int) (fraction * (endG - startG)) << 8)
| startB + (int) (fraction * (endB - startB));
}
private static final int ENABLE_ATTR = android.R.attr.state_enabled;
private static final int CHECKED_ATTR = android.R.attr.state_checked;
private static final int PRESSED_ATTR = android.R.attr.state_pressed;
/**
* @param tintColor
* @return
*/
public static ColorStateList generateThumbColorWithTintColor(final int tintColor) {
int[][] states = new int[][]{
{-ENABLE_ATTR, CHECKED_ATTR},
{-ENABLE_ATTR},
{PRESSED_ATTR, -CHECKED_ATTR},
{PRESSED_ATTR, CHECKED_ATTR},
{CHECKED_ATTR},
{-CHECKED_ATTR}
};
int[] colors = new int[]{
tintColor - 0xAA000000,
0xFFBABABA,
tintColor - 0x99000000,
tintColor - 0x99000000,
tintColor | 0xFF000000,
0xFFEEEEEE
};
return new ColorStateList(states, colors);
}
/**
* @param tintColor
* @return
*/
public static ColorStateList generateBackColorWithTintColor(final int tintColor) {
int[][] states = new int[][]{
{-ENABLE_ATTR, CHECKED_ATTR},
{-ENABLE_ATTR},
{CHECKED_ATTR, PRESSED_ATTR},
{-CHECKED_ATTR, PRESSED_ATTR},
{CHECKED_ATTR},
{-CHECKED_ATTR}
};
int[] colors = new int[]{
tintColor - 0xE1000000,
0x10000000,
tintColor - 0xD0000000,
0x20000000,
tintColor - 0xD0000000,
0x20000000
};
return new ColorStateList(states, colors);
}
/**
* 颜色加深处理
*
* @param RGBValues RGB的值,由alpha(透明度)、red(红)、green(绿)、blue(蓝)构成,
* Android中我们一般使用它的16进制,
* 例如:"#FFAABBCC",最左边到最右每两个字母就是代表alpha(透明度)、
* red(红)、green(绿)、blue(蓝)。每种颜色值占一个字节(8位),值域0~255
* 所以下面使用移位的方法可以得到每种颜色的值,然后每种颜色值减小一下,在合成RGB颜色,颜色就会看起来深一些了
* @return
*/
public static int colorBurn(int RGBValues) {
int red = RGBValues >> 16 & 0xFF;
int green = RGBValues >> 8 & 0xFF;
int blue = RGBValues & 0xFF;
red = (int) Math.floor(red * (1 - 0.1));
green = (int) Math.floor(green * (1 - 0.1));
blue = (int) Math.floor(blue * (1 - 0.1));
return Color.rgb(red, green, blue);
}
}
可以设置 开始的颜色 ---> 结束的颜色
没多少代码 ~ 几乎都是粘的
然后是Behavior
这个效果可以应用在 底部导航栏 当然要求
这个效果写在一些小界面 可以 ,完全体的导航栏还是去=>>github
public abstract class VerticalScrollingBehavior extends CoordinatorLayout.Behavior {
private int mTotalDyUnconsumed = 0;
private int mTotalDyConsumed = 0;
private int mTotalDy = 0;
@ScrollDirection
private int mScrollDirection = ScrollDirection.SCROLL_NONE;
@ScrollDirection
private int mPreScrollDirection = ScrollDirection.SCROLL_NONE;
@ScrollDirection
private int mConsumedScrollDirection = ScrollDirection.SCROLL_NONE;
public VerticalScrollingBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollingBehavior() {
super();
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({ScrollDirection.SCROLL_DIRECTION_UP, ScrollDirection.SCROLL_DIRECTION_DOWN})
public @interface ScrollDirection {
int SCROLL_DIRECTION_UP = 1;
int SCROLL_DIRECTION_DOWN = -1;
int SCROLL_NONE = 0;
}
/**
* @return Scroll direction: SCROLL_DIRECTION_UP, CROLL_DIRECTION_DOWN, SCROLL_NONE
*/
@ScrollDirection
public int getScrollDirection() {
return mScrollDirection;
}
/**
* @return ConsumedScroll direction: SCROLL_DIRECTION_UP, CROLL_DIRECTION_DOWN, SCROLL_NONE
*/
@ScrollDirection
public int getConsumedScrollDirection() {
return mConsumedScrollDirection;
}
/**
* @return PreScroll direction: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN, SCROLL_NONE
*/
@ScrollDirection
public int getPreScrollDirection() {
return mPreScrollDirection;
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
return (nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0;
}
// @Override
// public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
// super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
// }
//
// @Override
// public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
// super.onStopNestedScroll(coordinatorLayout, child, target);
// }
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
if (dyUnconsumed > 0 && mTotalDyUnconsumed < 0) {
mTotalDyUnconsumed = 0;
mScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP;
onNestedVerticalScrollUnconsumed(coordinatorLayout, child, mScrollDirection, dyConsumed, mTotalDyUnconsumed);
} else if (dyUnconsumed < 0 && mTotalDyUnconsumed > 0) {
mTotalDyUnconsumed = 0;
mScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN;
onNestedVerticalScrollUnconsumed(coordinatorLayout, child, mScrollDirection, dyConsumed, mTotalDyUnconsumed);
}
mTotalDyUnconsumed += dyUnconsumed;
if (dyConsumed > 0 && mTotalDyConsumed < 0) {
mTotalDyConsumed = 0;
mConsumedScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP;
onNestedVerticalScrollConsumed(coordinatorLayout, child, mConsumedScrollDirection, dyConsumed, mTotalDyConsumed);
} else if (dyConsumed < 0 && mTotalDyConsumed > 0) {
mTotalDyConsumed = 0;
mConsumedScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN;
onNestedVerticalScrollConsumed(coordinatorLayout, child, mConsumedScrollDirection, dyConsumed, mTotalDyConsumed);
}
mTotalDyConsumed += dyConsumed;
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
if (dy > 0 && mTotalDy < 0) {
mTotalDy = 0;
mPreScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP;
onNestedVerticalPreScroll(coordinatorLayout, child, target, dx, dy, consumed, mPreScrollDirection);
} else if (dy < 0 && mTotalDy > 0) {
mTotalDy = 0;
mPreScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN;
onNestedVerticalPreScroll(coordinatorLayout, child, target, dx, dy, consumed, mPreScrollDirection);
}
mTotalDy += dy;
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed) {
super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
return onNestedDirectionFling(coordinatorLayout, child, target, velocityX, velocityY, consumed
, velocityY > 0 ? ScrollDirection.SCROLL_DIRECTION_UP : ScrollDirection.SCROLL_DIRECTION_DOWN);
}
/**
* @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
* associated with
* @param child the child view of the CoordinatorLayout this Behavior is associated with
* @param scrollDirection Direction of the scroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN
* @param currentOverScroll Unconsumed value, negative or positive based on the direction;
* @param totalScroll Cumulative value for current direction (Unconsumed)
*/
public abstract void onNestedVerticalScrollUnconsumed(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int scrollDirection, int currentOverScroll, int totalScroll);
/**
* @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
* associated with
* @param child the child view of the CoordinatorLayout this Behavior is associated with
* @param scrollDirection Direction of the scroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN
* @param currentOverScroll Unconsumed value, negative or positive based on the direction;
* @param totalConsumedScroll Cumulative value for current direction (Unconsumed)
*/
public abstract void onNestedVerticalScrollConsumed(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int scrollDirection, int currentOverScroll, int totalConsumedScroll);
/**
* @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
* associated with
* @param child the child view of the CoordinatorLayout this Behavior is associated with
* @param target the descendant view of the CoordinatorLayout performing the nested scroll
* @param dx the raw horizontal number of pixels that the user attempted to scroll
* @param dy the raw vertical number of pixels that the user attempted to scroll
* @param consumed out parameter. consumed[0] should be set to the distance of dx that
* was consumed, consumed[1] should be set to the distance of dy that
* was consumed
* @param scrollDirection Direction of the scroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN
*/
public abstract void onNestedVerticalPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection);
/**
* @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
* associated with
* @param child the child view of the CoordinatorLayout this Behavior is associated with
* @param target the descendant view of the CoordinatorLayout performing the nested scroll
* @param velocityX horizontal velocity of the attempted fling
* @param velocityY vertical velocity of the attempted fling
* @param consumed true if the nested child view consumed the fling
* @param scrollDirection Direction of the scroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN
* @return true if the Behavior consumed the fling
*/
protected abstract boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed, @ScrollDirection int scrollDirection);
// @Override
// public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) {
// return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
// }
//
// @Override
// public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout, V child, WindowInsetsCompat insets) {
//
// return super.onApplyWindowInsets(coordinatorLayout, child, insets);
// }
//
// @Override
// public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
// return super.onSaveInstanceState(parent, child);
// }
}
public class BottomVerticalScrollBehavior extends VerticalScrollingBehavior {
private static final Interpolator INTERPOLATOR = new LinearOutSlowInInterpolator();
private int mBottomNavHeight;
private int mDefaultOffset;
// private WeakReference mViewRef;
private ViewPropertyAnimatorCompat mTranslationAnimator;
private boolean hidden = false;
@Override
public boolean onLayoutChild(CoordinatorLayout parent, final V child, int layoutDirection) {
// First let the parent lay it out
parent.onLayoutChild(child, layoutDirection);
// mViewRef = new WeakReference<>(child);
child.post(new Runnable() {
@Override
public void run() {
mBottomNavHeight = child.getHeight();
}
});
mDefaultOffset = 0;
return super.onLayoutChild(parent, child, layoutDirection);
}
@Override
public void onNestedVerticalScrollUnconsumed(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int scrollDirection, int currentOverScroll, int totalScroll) {
// Empty body
}
@Override
public void onNestedVerticalPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection) {
// handleDirection(child, scrollDirection);
}
@Override
public void onNestedVerticalScrollConsumed(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int scrollDirection, int currentOverScroll, int totalConsumedScroll) {
handleDirection(child, scrollDirection);
}
private void handleDirection(V child, int scrollDirection) {
if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_DOWN && hidden) {
hidden = false;
animateOffset(child, mDefaultOffset);
} else if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_UP && !hidden) {
hidden = true;
animateOffset(child, mBottomNavHeight + mDefaultOffset);
}
}
@Override
protected boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed, @ScrollDirection int scrollDirection) {
if (consumed) {
handleDirection(child, scrollDirection);
}
return consumed;
}
private void animateOffset(final V child, final int offset) {
ensureOrCancelAnimator(child);
mTranslationAnimator.translationY(offset).start();
}
private void ensureOrCancelAnimator(V child) {
if (mTranslationAnimator == null) {
mTranslationAnimator = ViewCompat.animate(child);
mTranslationAnimator.setDuration(400);
mTranslationAnimator.setInterpolator(INTERPOLATOR);
} else {
mTranslationAnimator.cancel();
}
}
}
public class BnbFollowListBehavior extends BottomVerticalScrollBehavior {
public BnbFollowListBehavior(Context context, AttributeSet attributeSet) {
super();
}
}
和上面一样效果 代码少了很多
public class FabFollowListBehavior extends CoordinatorLayout.Behavior {
private static final int MIN_DY = 30;
private static final String TAG = "FabFollowListBehavior";
public FabFollowListBehavior(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
/**
* 初始时不调用,滑动时调用---一次滑动过程,之调用一次
*/
@Override
public boolean onStartNestedScroll(
@NonNull CoordinatorLayout coordinatorLayout,
@NonNull FloatingActionButton child,
@NonNull View directTargetChild,
@NonNull View target, int axes, int type) {
return true;
}
/**
* @param dyConsumed 每次回调前后的Y差值
*/
@Override
public void onNestedScroll(
@NonNull CoordinatorLayout coordinatorLayout,
@NonNull FloatingActionButton child,
@NonNull View target, int dxConsumed,
int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
//平移隐现
if (dyConsumed > MIN_DY) {//上滑:消失
showOrNot(coordinatorLayout, child, false).start();
} else if (dyConsumed < -MIN_DY) {//下滑滑:显示
showOrNot(coordinatorLayout, child, true).start();
}
//仅滑动时消失
// if (dyConsumed > MIN_DY || dyConsumed < -MIN_DY) {//上滑:消失
// showOrNot(child).start();
// }
}
private Animator showOrNot(CoordinatorLayout coordinatorLayout, final View fab, boolean show) {
//获取fab头顶的高度
int hatHeight = coordinatorLayout.getBottom() - fab.getBottom() + fab.getHeight();
int end = show ? 0 : hatHeight;
float start = fab.getTranslationY();
ValueAnimator animator = ValueAnimator.ofFloat(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
fab.setTranslationY((Float) animation.getAnimatedValue());
}
});
return animator;
}
private Animator showOrNot(final View fab) {
//获取fab头顶的高度
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
fab.setScaleX((Float) animation.getAnimatedValue());
fab.setScaleY((Float) animation.getAnimatedValue());
}
});
return animator;
}
}
仔细看大佬给个 注释的....滑动时再隐藏