安卓开发博客

可拖拽的view 与 viewpager 一起使用时的尴尬

2018-06-28  本文已影响43人  靛蓝小孩

(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 的控件。

上一篇下一篇

猜你喜欢

热点阅读