package com.jiayiworld.baselibrary.widgets;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import static android.animation.ObjectAnimator.ofFloat;
/**
* 仿今日头条图片浏览上下滑动退出界面
*/
public class UpDownHideLayout extends FrameLayout {
private ScrollListener mScrollListener;
// 最小缩放比例
private final float MIN_SCALE = 0.2f;
// 完全不透明的透明度值
private final int FULL_ALPHA = 255;
public interface ScrollListener {
void onScrolling(float percent, float pixDistance);
}
public void setScrollListener(ScrollListener scrollListener) {
mScrollListener = scrollListener;
}
public interface OnLayoutCloseListener {
void OnLayoutClosed();
}
enum Direction {
UP_DOWN,
LEFT_RIGHT,
NONE
}
private Direction direction = Direction.NONE;
private int previousFingerPositionY;
private int previousFingerPositionX;
private int baseLayoutPosition;
private boolean isScrollingUp; //上滑 true 下滑false
private boolean isLocked = false;//是否拦截事件
private OnLayoutCloseListener listener;
private int RootViewHeight = 0;
public UpDownHideLayout(Context context) {
super(context);
}
public UpDownHideLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UpDownHideLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public UpDownHideLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isLocked) {
return false;
} else {
final int y = (int) ev.getRawY();
final int x = (int) ev.getRawX();
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
previousFingerPositionX = x;
previousFingerPositionY = y;
} else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
int diffY = y - previousFingerPositionY;
int diffX = x - previousFingerPositionX;
if (Math.abs(diffX) + 50 < Math.abs(diffY))
return true;
{
}
}
return false;
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// 初始化界面的高度
RootViewHeight = getMeasuredHeight() + 24;//有状态栏和虚拟键
super.onLayout(changed, left, top, right, bottom);
}
/**
* 灵巧模式拖拽(类似微信朋友圈)
*/
private void dragByAgile(float lastX, float lastY, MotionEvent event, View view) {
// 手指的移动距离
final float disX = event.getX() - lastX;
final float disY = event.getY() - lastY;
// imageView 被拖拽后的坐标
final float nextX = view.getTranslationX() + disX;
final float nextY = view.getTranslationY() + disY;
// 计算缩放比例
final float scale = Math.min(Math.max(1f - Math.abs(nextY) / getHeight(), MIN_SCALE), 1f);
view.getLayoutParams().width = (int) (getWidth() * scale);
view.getLayoutParams().height = (int) (getHeight() * scale);
view.requestLayout();
// 变换背景透明度
transformBgAlpha((int) (scale * FULL_ALPHA));
// // 向上移动
// if (nextY <= 0) {
// if (imageView.getLayoutParams().width != mIfWidth ||
// imageView.getLayoutParams().height != mIfHeight) {
// imageView.getLayoutParams().width = mIfWidth;
// imageView.getLayoutParams().height = mIfHeight;
// imageView.requestLayout();
// }
// transformBgAlpha(FULL_ALPHA);
//
// }
// // 向下移动
// else {
// // 计算缩放比例
// final float scale = Math.min(Math.max(1f - nextY / mIfHeight, MIN_SCALE), 1f);
// imageView.getLayoutParams().width = (int) (mIfWidth * scale);
// imageView.getLayoutParams().height = (int) (mIfHeight * scale);
// imageView.requestLayout();
// // 变换背景透明度
// transformBgAlpha((int) (scale * FULL_ALPHA));
// }
view.setTranslationX(nextX);
view.setTranslationY(nextY);
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent ev) {
if (!isLocked) {
final int y = (int) ev.getRawY();
final int x = (int) ev.getRawX();
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
previousFingerPositionX = x;
previousFingerPositionY = y;
baseLayoutPosition = (int) this.getY();
} else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
int diffY = y - previousFingerPositionY;
int diffX = x - previousFingerPositionX;
if (direction == Direction.NONE) {
if (Math.abs(diffX) > Math.abs(diffY)) {
direction = Direction.LEFT_RIGHT;
} else if (Math.abs(diffX) < Math.abs(diffY)) {
direction = Direction.UP_DOWN;
} else {
direction = Direction.NONE;
}
}
if (direction == Direction.UP_DOWN) {
isScrollingUp = diffY <= 0;
this.setY(baseLayoutPosition + diffY);
requestLayout();
if (mScrollListener != null) {
diffY = Math.abs(diffY);
float percent = ((float) diffY / (float) RootViewHeight) > 0.99 ? 1 : ((float) diffY / (float) RootViewHeight);
mScrollListener.onScrolling(percent, diffY);
}
return true;
}
} else if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
if (direction == Direction.UP_DOWN) {
if (isScrollingUp) {
int height = this.getHeight();
if (Math.abs(this.getY()) > (height / 5)) {
// 上滑退出
scrollToHide(true);
// dragByAgile()
} else {
// scrollToBack();
downToFinish(mScrollListener);
}
} else {
int height = this.getHeight();
if (Math.abs(this.getY()) > (height / 5)) {
//下滑退出
scrollToHide(false);
} else {
scrollToBack();
}
}
direction = Direction.NONE;
return true;
}
direction = Direction.NONE;
}
return true;
}
return false;
}
public void scrollToHide(boolean isScrollingUp) {
ObjectAnimator positionAnimator = null;
if (isScrollingUp) {
positionAnimator = ObjectAnimator.ofFloat(this, "y", this.getY(), -RootViewHeight);
} else {
positionAnimator = ofFloat(this, "y", this.getY(), RootViewHeight);
}
positionAnimator.addUpdateListener(new ObjectAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
notiyListener(animation);
}
});
positionAnimator.setDuration(100);
positionAnimator.start();
}
public void scrollToBack() {
ObjectAnimator positionAnimator = ofFloat(this, "y", this.getY(), 0);
positionAnimator.addUpdateListener(new ObjectAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
notiyListener(animation);
}
});
positionAnimator.setDuration(300);
positionAnimator.start();
}
public void notiyListener(ValueAnimator animation) {
if (mScrollListener != null) {
float diffY = Math.abs((float) animation.getAnimatedValue());
float percent = (diffY / (float) RootViewHeight) > 0.99 ? 1 : (diffY / (float) RootViewHeight);
mScrollListener.onScrolling(percent, diffY);
}
}
public void setOnLayoutCloseListener(OnLayoutCloseListener closeListener) {
this.listener = closeListener;
}
public void lock() {
isLocked = true;
}
public void unLock() {
isLocked = false;
}
public void downToFinish(final ScrollListener scrollListener) {
ObjectAnimator positionAnimator = null;
positionAnimator = ofFloat(this, "y", this.getY(), RootViewHeight);
positionAnimator.addUpdateListener(new ObjectAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (scrollListener != null) {
float diffY = Math.abs((float) animation.getAnimatedValue());
float percent = (diffY / (float) RootViewHeight) > 0.99 ? 1 : (diffY / (float) RootViewHeight);
scrollListener.onScrolling(percent, diffY);
}
}
});
positionAnimator.setDuration(260);
positionAnimator.start();
}
/**
* 变换背景透明度
*/
private void transformBgAlpha(int alpha) {
if (getBackground() != null && getBackground().getAlpha() != alpha) {
getBackground().setAlpha(alpha);
}
}
}
来源:https://blog.csdn.net/a1003434346/article/details/102737335