android addView()的时候,如何保持已有动态控件位置不被改变

436 阅读1分钟

现象: 在FrameLayout中添加一个拖拽的View后,经过移动,该view移动到指定位置 然后再次添加一个拖拽的view,这时候发现之前被移动的view又回到了初始位置

使用addView方法时,如何保持已有动态控件位置不初始化?

经过一番尝试,终于解决这个问题,简单说就是,不能使用layout()方法,来改变位置。layout()虽然可以改变控件的位置, 但不会将位置信息保存到layoutparam中。而调用addView往布局添加新的控件时,是根据layoutparam来重新布局控件位置的。 因此另一种方法就是:先获取控件的layoutparam,改变其中相关的值后,再设置回去。 这样移动过的控件,就不会在addView时回到原来的位置了。

public class DragViewGroup extends ConstraintLayout {
    private int lastX;
    private int lastY;
    private final Rect bound;
    private OnTouchDownListener touchDownListener;

    public DragViewGroup(Context context) {
        this(context, null);
    }

    public DragViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        DisplayMetrics dm = getResources().getDisplayMetrics();
        bound = new Rect(0, 0, dm.widthPixels, dm.heightPixels);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        AbsoluteLayout.LayoutParams param = (AbsoluteLayout.LayoutParams) getLayoutParams();
        param.x = (bound.left + bound.right) / 2 - getMeasuredWidth() / 2;
        param.y = (bound.top + bound.bottom) / 2 - getMeasuredHeight() / 2;
        setLayoutParams(param);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                if (touchDownListener != null) {
                    touchDownListener.onTouchDown();
                }
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = (int) event.getRawX() - lastX;
                int dy = (int) event.getRawY() - lastY;

                int left = getLeft() + dx;
                int top = getTop() + dy;
                int right = getRight() + dx;
                int bottom = getBottom() + dy;
                if (left < bound.left) {
                    left = bound.left;
                    right = left + getWidth();
                }
                if (right > bound.right) {
                    right = bound.right;
                    left = right - getWidth();
                }
                if (top < bound.top) {
                    top = bound.top;
                    bottom = top + getHeight();
                }
                if (bottom > bound.bottom) {
                    bottom = bound.bottom;
                    top = bottom - getHeight();
                }

                layout(left, top, right, bottom);
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                //记录
                AbsoluteLayout.LayoutParams params = (AbsoluteLayout.LayoutParams) getLayoutParams();
                params.x = getLeft();
                params.y = getTop();
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
            default:
                break;
        }
        return true;
    }

    public void setBound(int left, int top, int right, int bottom) {
        this.bound.left = left;
        this.bound.right = right;
        this.bound.top = top;
        this.bound.bottom = bottom;
    }

    //添加按下的事件
    public void addTouchDownListener(OnTouchDownListener listener) {
        this.touchDownListener = listener;
    }

    public interface OnTouchDownListener {
        void onTouchDown();
    }
}