(1):可拖拽的view 的实现:(实现一)
package com.mishou.health.widget;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.mishou.common.utils.PhoneUtils;
public class DragImageView extends View {
private int x, y;
private int mTabHeight;
private int mScreenWidth, mScreenHeight;
private Context mContext;
public DragImageView(Context context) {
super(context);
this.mContext = context;
initScreenParams();
}
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initScreenParams();
}
public DragImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initScreenParams();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 记录触摸点坐标
x = (int) event.getRawX();// 获取触摸事件触摸位置的原始X坐标
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
mTabHeight = getTabHeight();
//计算偏移量
int dx = (int) event.getRawX() - x;
int dy = (int) event.getRawY() - y;
int l = getLeft() + dx;
int b = getBottom() + dy;
int r = getRight() + dx;
int t = getTop() + dy;
// 下面判断移动是否超出屏幕
if (l < 0) {
l = 0;
r = l + getWidth();
}
if (t < 0) {
t = 0;
b = t + getHeight();
}
if (r > mScreenWidth) {
r = mScreenWidth;
l = r - getWidth();
}
if (b > mScreenHeight - mTabHeight) {
b = mScreenHeight - mTabHeight;
t = b - getHeight();
}
layout(l, t, r, b);
x = (int) event.getRawX();
y = (int) event.getRawY();
postInvalidate();
break;
}
return true;
}
private void initScreenParams() {
mScreenWidth = PhoneUtils.getScreenWidth(mContext);
mScreenHeight = PhoneUtils.getScreenHeight(mContext);
}
private int getTabHeight() {
return 90;
}}
问题:点击事件就无法触发
(2):可拖拽view 的实现二
package com.mishou.health.widget;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import com.mishou.common.utils.PhoneUtils;
public class DragImageView extends View {
private static final String TAG = "DragImageView";
private int mTabHeight;
private boolean mMove = false;
private int mSlop;
private int mScreenWidth, mScreenHeight;
private Context mContext;
public DragImageView(Context context) {
super(context);
this.mContext = context;
initScreenParams();
}
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initScreenParams();
}
public DragImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initScreenParams();
}
private void initScreenParams() {
mSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mScreenWidth = PhoneUtils.getScreenWidth(mContext);
mScreenHeight = PhoneUtils.getScreenHeight(mContext);
}
private boolean hasTouchFloatBall = false;
private float mLastX;
private float mLastY;
private boolean isIntercepted = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getRawX();
mLastY = event.getRawY();
if (onTouchEvent(event)) {
hasTouchFloatBall = true;
}
break;
case MotionEvent.ACTION_MOVE:
int deltaX = (int) ((int) event.getRawX() - mLastX);
int deltaY = (int) ((int) event.getRawY() - mLastY);
if (!isIntercepted) {
if (Math.abs(deltaX) > mSlop || Math.abs(deltaY) > mSlop) {
sendCancelEvent(event);
isIntercepted = true;
} else {
return super.dispatchTouchEvent(event);
}
}
if (hasTouchFloatBall) {
mTabHeight = getTabHeight();
//计算偏移量
int l = getLeft() + deltaX;
int b = getBottom() + deltaY;
int r = getRight() + deltaX;
int t = getTop() + deltaY;
// 下面判断移动是否超出屏幕
if (l < 0) {
l = 0;
r = l + getWidth();
}
if (t < 0) {
t = 0;
b = t + getHeight();
}
if (r > mScreenWidth) {
r = mScreenWidth;
l = r - getWidth();
}
if (b > mScreenHeight - 2 * mTabHeight) {
b = mScreenHeight - 2 * mTabHeight;
t = b - getHeight();
}
layout(l, t, r, b);
mLastX = (int) event.getRawX();
mLastY = (int) event.getRawY();
postInvalidate();
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
hasTouchFloatBall = false;
isIntercepted = false;
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
private void sendCancelEvent(MotionEvent lastEvent) {
MotionEvent last = lastEvent;
MotionEvent e = MotionEvent.obtain(
last.getDownTime(),
last.getEventTime()
+ ViewConfiguration.getLongPressTimeout(),
MotionEvent.ACTION_CANCEL, last.getX(), last.getY(),
last.getMetaState());
super.dispatchTouchEvent(e);
}
private int getTabHeight() {
return 90;
}}
问题:可拖拽,可点击,但是,在viewpager 切换页面的时候,会调用requestlayout,导致view回到了初始的view 位置,熟悉的朋友会知道,这个方法强制刷新UI 的经过,这里不多做说明。
(3):可拖拽view 的实现三:既然知道了重置到初始位置的问题,如果去更改viewpager 的实现,不仅困难,而是非常困难,有可能会多出更多的问题,为此,可拖拽的view 的实现,我们可以换种方法,利用属性动画,这里就是属性动画的特点,使得它可以解决这里的问题,实现如下:
package com.mishou.health.widget;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import com.mishou.common.utils.PhoneUtils;
public class DragImageView extends View {
private static final String TAG = "DragImageView";
private int mTabHeight;
private boolean mMove = false;
private int mSlop;
private int mScreenWidth, mScreenHeight;
private Context mContext;
public DragImageView(Context context) {
super(context);
this.mContext = context;
initScreenParams();
}
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initScreenParams();
}
public DragImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initScreenParams();
}
private void initScreenParams() {
mSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mScreenWidth = PhoneUtils.getScreenWidth(mContext);
mScreenHeight = PhoneUtils.getScreenHeight(mContext);
}
private boolean hasTouchFloatBall = false;
private float mLastX;
private float mLastY;
private boolean isIntercepted = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getRawX();
mLastY = event.getRawY();
if (onTouchEvent(event)) {
hasTouchFloatBall = true;
}
break;
case MotionEvent.ACTION_MOVE:
int deltaX = (int) ((int) event.getRawX() - mLastX);
int deltaY = (int) ((int) event.getRawY() - mLastY);
if (!isIntercepted) {
if (Math.abs(deltaX) > mSlop || Math.abs(deltaY) > mSlop) {
sendCancelEvent(event);
isIntercepted = true;
} else {
return super.dispatchTouchEvent(event);
}
}
if (hasTouchFloatBall) {
mTabHeight = getTabHeight();
//计算偏移量
int l = getLeft() + deltaX;
int b = getBottom() + deltaY;
int r = getRight() + deltaX;
int t = getTop() + deltaY;
// 下面判断移动是否超出屏幕
if (l < 0) {
l = 0;
r = l + getWidth();
}
if (t < 0) {
t = 0;
b = t + getHeight();
}
if (r > mScreenWidth) {
r = mScreenWidth;
l = r - getWidth();
}
if (b > mScreenHeight - 2 * mTabHeight) {
b = mScreenHeight - 2 * mTabHeight;
t = b - getHeight();
}
layout(l, t, r, b);
mLastX = (int) event.getRawX();
mLastY = (int) event.getRawY();
postInvalidate();
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
hasTouchFloatBall = false;
isIntercepted = false;
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
private void sendCancelEvent(MotionEvent lastEvent) {
MotionEvent last = lastEvent;
MotionEvent e = MotionEvent.obtain(
last.getDownTime(),
last.getEventTime()
+ ViewConfiguration.getLongPressTimeout(),
MotionEvent.ACTION_CANCEL, last.getX(), last.getY(),
last.getMetaState());
super.dispatchTouchEvent(e);
}
private int getTabHeight() {
return 90;
}}
总结:这样就完美的实现当前页面即有viewpager ,也有拖拽的view 的控件。
网友评论