此博客就是为了记录代码
目标:
1. 点击view,盖住半透明浮层,浮层根据手势缩放和移动,四边任意缩放、四角等比缩放、中间移动;
2. 松开的时候,底层view执行缩放动画变成浮层的大小,,如果是移动,就执行移动动画;
实现:
MainMainActivity.java
public class MainMainActivity extends Activity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏状态栏
RelativeLayout relativeLayout = findViewById(R.id.relativeLayout);
int[] size = UIUtil.getWidthAndHeightToSize(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(size[0], size[1]);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
relativeLayout.setLayoutParams(params);
}
}
activity_main_main.xml
TopDrawView.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
public class TopDrawView extends View {
public static final String ACTION_VIEW_DOWN = "action_view_down";//view的点击事件
public static final String ACTION_VIEW_MOVE = "action_view_move";//view的移动事件
public static final String ACTION_VIEW_UP = "action_view_up";//view的离开事件
public static final String VIEW_MOVE = "view_move";//view的移动
public static final String VIEW_ZOOM = "view_zoom";//view的缩放
private Paint paint;
private Paint paintLine;
private Rect rect;
private Rect rectLine;
private int lineWidth = 2;//黑色边框线的宽度
private float left, top, right, bottom;
public TopDrawView(Context context) {
super(context);
init();
}
public TopDrawView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TopDrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.argb(99, 0, 0, 0));
paint.setStyle(Paint.Style.FILL);
paintLine = new Paint();
paintLine.setColor(Color.YELLOW);
paintLine.setStrokeWidth(lineWidth);
paintLine.setStyle(Paint.Style.STROKE);
rect = new Rect(0, 0, 0, 0);
rectLine = new Rect(0, 0, 0, 0);
registerBoradcastReceiver();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mBroadcastReceiver != null) {
getContext().unregisterReceiver(mBroadcastReceiver);
mBroadcastReceiver = null;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(rect, paint);
canvas.drawRect(rectLine, paintLine);
}
public void registerBoradcastReceiver() {
IntentFilter myIntentFilter = new IntentFilter();
myIntentFilter.addAction(ACTION_VIEW_DOWN);
myIntentFilter.addAction(ACTION_VIEW_MOVE);
myIntentFilter.addAction(ACTION_VIEW_UP);
getContext().registerReceiver(mBroadcastReceiver, myIntentFilter);
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_VIEW_DOWN)) {
left = intent.getFloatExtra("oriLeft", 0);
top = intent.getFloatExtra("oriTop", 0);
right = intent.getFloatExtra("oriRight", 0);
bottom = intent.getFloatExtra("oriBottom", 0);
} else if (action.equals(ACTION_VIEW_MOVE)) {
left = intent.getFloatExtra("oriLeft", 0);
top = intent.getFloatExtra("oriTop", 0);
right = intent.getFloatExtra("oriRight", 0);
bottom = intent.getFloatExtra("oriBottom", 0);
} else if (action.equals(ACTION_VIEW_UP)) {
left = 0;
top = 0;
right = 0;
bottom = 0;
}
rect.set((int) left, (int) top, (int) right, (int) bottom);
rectLine.set((int) left + lineWidth / 2, (int) top + lineWidth / 2,
(int) right - lineWidth / 2, (int) bottom - lineWidth / 2);
invalidate();
}
};
}
CustomView.java
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class CustomView extends HwkDragScaleView {
@Override
protected void onLayoutSingleClick() {
Log.e("hwk", "onLayoutSingleClick----单击");
}
@Override
protected void onLayoutDoubleClick() {
Log.e("hwk", "onLayoutDoubleClick----双击");
}
@Override
protected void onLayoutLongClick() {
Log.e("hwk", "onLayoutLongClick----长按");
}
@Override
protected void onLayoutMove(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom) {
Log.e("hwk", "onLayoutMove----移动 原始大小 left=" + oldLeft + " top=" + oldTop + " right=" + oldRight + " bottom=" + oldBottom);
Log.e("hwk", "onLayoutMove----移动 left=" + left + " top=" + top + " right=" + right + " bottom=" + bottom);
}
@Override
protected void onLayoutZoom(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom) {
Log.e("hwk", "onLayoutZoom----缩放 原始大小 left=" + oldLeft + " top=" + oldTop + " right=" + oldRight + " bottom=" + oldBottom);
Log.e("hwk", "onLayoutZoom---- 缩放=" + left + " top=" + top + " right=" + right + " bottom=" + bottom);
}
@Override
protected void onLayoutReset() {
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context) {
super(context);
init();
}
private void init() {
View.inflate(getContext(), R.layout.testview, this);
}
}
HwkDragScaleView.java
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;
public abstract class HwkDragScaleView extends RelativeLayout implements View.OnTouchListener {
private String TAG = HwkDragScaleView.class.getName();
private int screenWidth, screenHeight;
private float lastX, lastY;
private float oriLeft, oriRight, oriTop, oriBottom;
private boolean isLeft, isRight, isTop, isBottom;//四边是否到达边距,如果到达边距,则不再继续缩放
public static final int TOP = 0x15;
public static final int LEFT = 0x16;
public static final int BOTTOM = 0x17;
public static final int RIGHT = 0x18;
public static final int LEFT_TOP = 0x11;
public static final int RIGHT_TOP = 0x12;
public static final int LEFT_BOTTOM = 0x13;
public static final int RIGHT_BOTTOM = 0x14;
public static final int CENTER = 0x19;
private int minWidth = 320, minHeight = 180;//最小矩形
private int Control_Distance = 55;//手势控制边距
private static final int MAX_LONG_PRESS_TIME = 400;// 长按/双击最长等待时间
private static final int MAX_SINGLE_CLICK_TIME = 220;// 单击后等待的时间
private static final int MIN_DISTANCE = 5; //最小滑动距离
private int mClickCount;// 点击次数
private float mDownX;
private float mDownY;
private long mLastDownTime;
private long mFirstClick;
private long mSecondClick;
private boolean isDoubleClick = false;
private final Handler mBaseHandler = new Handler();
private int dragDirection;
private float dxNum, dyNum = 0;//xy方向移动的累计距离
private boolean isCanHandleEdgu = true;//是否可以操作边界,如果不可操作边界,则认为是等比例缩放,16/9
private static final float defaultScale = (float) 16 / 9;
protected abstract void onLayoutSingleClick();
protected abstract void onLayoutDoubleClick();
protected abstract void onLayoutLongClick();
protected abstract void onLayoutMove(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom);
protected abstract void onLayoutZoom(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom);
protected abstract void onLayoutReset();
public HwkDragScaleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public HwkDragScaleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HwkDragScaleView(Context context) {
super(context);
init();
}
private void init() {
int[] size = UIUtil.getWidthAndHeightToSize(getContext());
screenWidth = size[0];
screenHeight = size[1];
setOnTouchListener(this);
setWillNotDraw(false);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
isLeft = false;
isTop = false;
isRight = false;
isBottom = false;
oriLeft = v.getLeft();
oriTop = v.getTop();
oriRight = v.getRight();
oriBottom = v.getBottom();
lastY = (int) event.getRawY();
lastX = (int) event.getRawX();
dragDirection = getDirection(v, event.getX(), event.getY());
mLastDownTime = System.currentTimeMillis();
mDownX = event.getX();
mDownY = event.getY();
mClickCount++;
if (mSingleClickTask != null) {
mBaseHandler.removeCallbacks(mSingleClickTask);
}
if (!isDoubleClick) {
mBaseHandler.postDelayed(mLongPressTask, MAX_LONG_PRESS_TIME);
}
if (1 == mClickCount) {
mFirstClick = System.currentTimeMillis();
} else if (mClickCount == 2) {// 双击
mSecondClick = System.currentTimeMillis();
if (mSecondClick - mFirstClick <= MAX_LONG_PRESS_TIME) {
//处理双击
mDoubleClickTask();
}
}
Intent intent = new Intent(TopDrawView.ACTION_VIEW_DOWN);
intent.putExtra("oriLeft", oriLeft);
intent.putExtra("oriTop", oriTop);
intent.putExtra("oriRight", oriRight);
intent.putExtra("oriBottom", oriBottom);
getContext().sendBroadcast(intent);
}
// 处理拖动事件
delDrag(v, event, action);
invalidate();
return true;
}
protected void delDrag(final View v, MotionEvent event, int action) {
switch (action) {
case MotionEvent.ACTION_MOVE:
if (isTop || isRight || isBottom || isLeft) {
return;
}
float mMoveX = event.getX();
float mMoveY = event.getY();
if (Math.abs(mMoveX - mDownX) > MIN_DISTANCE || Math.abs(mMoveY - mDownY) > MIN_DISTANCE) {
//移动了
mBaseHandler.removeCallbacks(mLongPressTask);
mBaseHandler.removeCallbacks(mSingleClickTask);
isDoubleClick = false;
mClickCount = 0;
}
float dx = event.getRawX() - lastX;
float dy = event.getRawY() - lastY;
//是不是XY轴都移动了,四角移动缩放的时候判断条件
boolean isXYMove = Math.abs(dx) > 0 && Math.abs(dy) > 0;
float[] ints = new float[2];
if (isXYMove) {
ints = defaultScaleCalculate(dx, dy);
}
switch (dragDirection) {
case LEFT: // 左边缘
if (isCanHandleEdgu)
left(v, dx);
break;
case RIGHT: // 右边缘
if (isCanHandleEdgu)
right(v, dx);
break;
case BOTTOM: // 下边缘
if (isCanHandleEdgu)
bottom(v, dy);
break;
case TOP: // 上边缘
if (isCanHandleEdgu)
top(v, dy);
break;
case CENTER: // 点击中心-->>移动
center(v, dx, dy);
break;
case LEFT_BOTTOM: // 左下
if (isXYMove) {
left(v, ints[0]);
bottom(v, ints[1]);
}
break;
case LEFT_TOP: // 左上
if (isXYMove) {
left(v, ints[0]);
top(v, ints[1]);
}
break;
case RIGHT_BOTTOM: // 右下
if (isXYMove) {
right(v, ints[0]);
bottom(v, ints[1]);
}
break;
case RIGHT_TOP: // 右上
if (isXYMove) {
right(v, ints[0]);
top(v, ints[1]);
}
break;
}
Intent intent = new Intent(TopDrawView.ACTION_VIEW_MOVE);
if (dragDirection != CENTER) {
intent.putExtra("type", TopDrawView.VIEW_ZOOM);
} else {
intent.putExtra("type", TopDrawView.VIEW_MOVE);
}
intent.putExtra("oriLeft", oriLeft);
intent.putExtra("oriTop", oriTop);
intent.putExtra("oriRight", oriRight);
intent.putExtra("oriBottom", oriBottom);
getContext().sendBroadcast(intent);
lastX = event.getRawX();
lastY = event.getRawY();
break;
case MotionEvent.ACTION_UP:
long mLastUpTime = System.currentTimeMillis();
float mUpX = event.getX();
float mUpY = event.getY();
if (Math.abs(mUpX - mDownX) <= MIN_DISTANCE && Math.abs(mUpY - mDownY) <= MIN_DISTANCE) {
if ((mLastUpTime - mLastDownTime) <= MAX_LONG_PRESS_TIME) {
mBaseHandler.removeCallbacks(mLongPressTask);
if (!isDoubleClick) {
mBaseHandler.postDelayed(mSingleClickTask, MAX_SINGLE_CLICK_TIME);
}
} else {
//超出了双击间隔时间
mClickCount = 0;
}
} else {
//移动了
mBaseHandler.removeCallbacks(mLongPressTask);
mBaseHandler.removeCallbacks(mSingleClickTask);
isDoubleClick = false;
mClickCount = 0;//移动了
if (dragDirection == CENTER) {
onLayoutMove(getLeft(), getTop(), getRight(), getBottom(), oriLeft, oriTop, oriRight, oriBottom);
} else {
if (isCanHandleEdgu) {
//允许操控边界,任意位置都可触发缩放事件
onLayoutZoom(getLeft(), getTop(), getRight(), getBottom(), oriLeft, oriTop, oriRight, oriBottom);
} else {
//不允许操控边界的时候,只有四个角才能触发缩放事件
if (dragDirection == LEFT_TOP || dragDirection == RIGHT_TOP || dragDirection == RIGHT_BOTTOM || dragDirection == LEFT_BOTTOM) {
onLayoutZoom(getLeft(), getTop(), getRight(), getBottom(), oriLeft, oriTop, oriRight, oriBottom);
}
}
}
}
if (isDoubleClick) {
isDoubleClick = false;
}
getViewHandleAnimation();
dragDirection = 0;
dxNum = 0;
dyNum = 0;
getContext().sendBroadcast(new Intent(TopDrawView.ACTION_VIEW_UP));
break;
}
}
private float[] defaultScaleCalculate(float dx, float dy) {
float[] result = new float[2];//0标识dx,1标识dy
result[0] = dx;
result[1] = dy;
//X方向移动较多,以X轴移动为基准,计算出Y轴移动距离
if (Math.abs(dx) > defaultScale * Math.abs(dy)) {
result[1] = dx / defaultScale;
if (dragDirection == RIGHT_BOTTOM || dragDirection == LEFT_TOP) {
if (dx > 0) {
result[1] = Math.abs(result[1]);
} else if (dx < 0) {
result[1] = -Math.abs(result[1]);
}
} else if (dragDirection == RIGHT_TOP || dragDirection == LEFT_BOTTOM) {
if (dx > 0) {
result[1] = -Math.abs(result[1]);
} else if (dx < 0) {
result[1] = Math.abs(result[1]);
}
}
//Y方向移动较多,以Y轴移动为基准,计算出Y轴移动距离
} else if (Math.abs(dx) < defaultScale * Math.abs(dy)) {
result[0] = dy * defaultScale;
if (dragDirection == RIGHT_BOTTOM || dragDirection == LEFT_TOP) {
if (dy > 0) {
result[0] = Math.abs(result[0]);
} else if (dy < 0) {
result[0] = -Math.abs(result[0]);
}
} else if (dragDirection == RIGHT_TOP || dragDirection == LEFT_BOTTOM) {
if (dy > 0) {
result[0] = -Math.abs(result[0]);
} else if (dy < 0) {
result[0] = Math.abs(result[0]);
}
}
}
return result;
}
private void center(View v, float dx, float dy) {
dxNum += dx;
dyNum += dy;
oriLeft = v.getLeft() + dxNum;
oriTop = v.getTop() + dyNum;
oriRight = v.getRight() + dxNum;
oriBottom = v.getBottom() + dyNum;
if (oriLeft < 0) {
oriLeft = 0;
oriRight = oriLeft + v.getWidth();
}
if (oriRight > screenWidth) {
oriRight = screenWidth;
oriLeft = oriRight - v.getWidth();
}
if (oriTop < 0) {
oriTop = 0;
oriBottom = oriTop + v.getHeight();
}
if (oriBottom > screenHeight) {
oriBottom = screenHeight;
oriTop = oriBottom - v.getHeight();
}
}
private void top(View v, float dy) {
if (isTop && dy < 0) {
return;
}
oriTop += dy;
if (oriTop < 0) {
oriTop = 0;
isTop = true;
} else {
isTop = false;
}
if (oriBottom - oriTop < minHeight) {
oriTop = oriBottom - minHeight;
}
}
private void bottom(View v, float dy) {
if (isBottom && dy > 0) {
return;
}
oriBottom += dy;
if (oriBottom > screenHeight) {
oriBottom = screenHeight;
isBottom = true;
} else {
isBottom = false;
}
if (oriBottom - oriTop < minHeight) {
oriBottom = minHeight + oriTop;
}
}
private void right(View v, float dx) {
if (isRight && dx > 0) {
return;
}
oriRight += dx;
if (oriRight > screenWidth) {
oriRight = screenWidth;
isRight = true;
} else {
isRight = false;
}
if (oriRight - oriLeft < minWidth) {
oriRight = oriLeft + minWidth;
}
}
private void left(View v, float dx) {
if (isLeft && dx < 0) {
return;
}
oriLeft += dx;
if (oriLeft < 0) {
oriLeft = 0;
isLeft = true;
} else {
isLeft = false;
}
if (oriRight - oriLeft < minWidth) {
oriLeft = oriRight - minWidth;
}
}
protected int getDirection(View v, float x, float y) {
int left = v.getLeft();
int right = v.getRight();
int bottom = v.getBottom();
int top = v.getTop();
if (x < Control_Distance && y < Control_Distance) {
return LEFT_TOP;
}
if (y < Control_Distance && right - left - x < Control_Distance) {
return RIGHT_TOP;
}
if (x < Control_Distance && bottom - top - y < Control_Distance) {
return LEFT_BOTTOM;
}
if (right - left - x < Control_Distance && bottom - top - y < Control_Distance) {
return RIGHT_BOTTOM;
}
if (x < Control_Distance) {
return LEFT;
}
if (y < Control_Distance) {
return TOP;
}
if (right - left - x < Control_Distance) {
return RIGHT;
}
if (bottom - top - y < Control_Distance) {
return BOTTOM;
}
return CENTER;
}
private Animation getViewHandleAnimation() {
Animation mAnimation;
if (dragDirection == CENTER) {//平移
mAnimation = new TranslateAnimation(0, oriLeft - getLeft(), 0, oriTop - getTop());
} else {//缩放
float scaleX = (float) (Math.abs(oriRight - oriLeft)) / getWidth();
float scaleY = (float) (Math.abs(oriBottom - oriTop)) / getHeight();
float pivotX = 0;
float pivotY = 0;
if (dragDirection == LEFT_TOP) {
pivotX = 1f;
pivotY = 1f;
} else if (dragDirection == RIGHT_TOP) {
pivotX = 0f;
pivotY = 1f;
} else if (dragDirection == RIGHT_BOTTOM) {
pivotX = 0f;
pivotY = 0f;
} else if (dragDirection == LEFT_BOTTOM) {
pivotX = 1f;
pivotY = 0f;
} else if (dragDirection == LEFT) {
pivotX = 1f;
} else if (dragDirection == TOP) {
pivotY = 1f;
} else if (dragDirection == RIGHT) {
pivotX = 0f;
} else if (dragDirection == BOTTOM) {
pivotY = 0f;
}
mAnimation = new ScaleAnimation(1f, scaleX, 1f, scaleY, Animation.RELATIVE_TO_SELF, pivotX, Animation.RELATIVE_TO_SELF, pivotY);
}
mAnimation.setDuration(400);//时长
mAnimation.setFillAfter(true);
mAnimation.setFillEnabled(true);//填充效果不回到原地
setAnimation(mAnimation);//为控件绑定动画
startAnimation(mAnimation);
mAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
clearAnimation();
postInvalidate();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) (oriRight - oriLeft), (int) (oriBottom - oriTop));
params.leftMargin = (int) oriLeft;
params.topMargin = (int) oriTop;
setLayoutParams(params);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
return mAnimation;
}
private final Runnable mSingleClickTask = new Runnable() {
@Override
public void run() {
// 处理单击
mClickCount = 0;
onLayoutSingleClick();
}
};
private final Runnable mLongPressTask = new Runnable() {
@Override
public void run() {
//处理长按
mClickCount = 0;
onLayoutLongClick();
}
};
private void mDoubleClickTask() {
//处理双击
isDoubleClick = true;
mClickCount = 0;
mFirstClick = 0;
mSecondClick = 0;
mBaseHandler.removeCallbacks(mSingleClickTask);
mBaseHandler.removeCallbacks(mLongPressTask);
//双击
onLayoutDoubleClick();
}
}



