zoukankan      html  css  js  c++  java
  • Android 自定义View可拖动移动位置及边缘拉伸放大缩小

      一.首先说一下定义这样一个View有什么用?在一些app中,需要设置头像,而用户选择的图片可能是使用摄像头拍摄,也可能是选择的相册里面的图片,总之,这样的图片大小不一,就比如在使用某个聊天软件的时候,设置头像,需要对图片进行截取.

      要实现这样一个功能,首先,需要分析用户的操作,即用户所点击的View的位置,如下图,我把View分为9个区域,

    • 当ACTION_DOWN时如果坐标为1.2.3.4四个区域,则对View进行相应的左上/右上/左下/右下拉伸;
    • 当ACTION_DOWN时如果坐标为5.6.7.8四个区域,则分别对上/右/下/左四个方向进行拉伸; 
    • 当ACTION_DOWN时如果坐标为9这个区域,则对View进行移动;

     

      理论分析完成,下面来看具体实现;

      在下面的类中,有五个方法center/left/top/bottom/right分别对应移动/向左拉伸/向上拉伸/向下拉伸/向右拉伸,当Action_down为1-4所在的区域时,组合前面的对应的两个拉伸方法即可,如左上角拉伸则对应执行left+top方法,这也是把四个单独一条边的边缘拉伸独立出来的原因;

      在View中,我设定了View的最小宽度和高度,都是200,所以当用户点击边缘进行缩小操作时,能缩小的最小值也就是200;分别在left/top/bottom/right中体现;

    /**
     * @see http://www.cnblogs.com/a284628487/
     * @author Cj
     * 
     */
    public class DragScaleView extends View implements OnTouchListener {
        protected int screenWidth;
        protected int screenHeight;
        protected int lastX;
        protected int lastY;
        private int oriLeft;
        private int oriRight;
        private int oriTop;
        private int oriBottom;
        private int dragDirection;
        private static final int TOP = 0x15;
        private static final int LEFT = 0x16;
        private static final int BOTTOM = 0x17;
        private static final int RIGHT = 0x18;
        private static final int LEFT_TOP = 0x11;
        private static final int RIGHT_TOP = 0x12;
        private static final int LEFT_BOTTOM = 0x13;
        private static final int RIGHT_BOTTOM = 0x14;
        private static final int CENTER = 0x19;
        private int offset = 20;
        protected Paint paint = new Paint();
    
        /**
         * 初始化获取屏幕宽高
         */
        protected void initScreenW_H() {
            screenHeight = getResources().getDisplayMetrics().heightPixels - 40;
            screenWidth = getResources().getDisplayMetrics().widthPixels;
        }
    
        public DragScaleView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            setOnTouchListener(this);
            initScreenW_H();
        }
    
        public DragScaleView(Context context, AttributeSet attrs) {
            super(context, attrs);
            setOnTouchListener(this);
            initScreenW_H();
        }
    
        public DragScaleView(Context context) {
            super(context);
            setOnTouchListener(this);
            initScreenW_H();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            paint.setColor(Color.RED);
            paint.setStrokeWidth(4.0f);
            paint.setStyle(Style.STROKE);
            canvas.drawRect(offset, offset, getWidth() - offset, getHeight()
                    - offset, paint);
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int action = event.getAction();
            if (action == MotionEvent.ACTION_DOWN) {
                oriLeft = v.getLeft();
                oriRight = v.getRight();
                oriTop = v.getTop();
                oriBottom = v.getBottom();
                lastY = (int) event.getRawY();
                lastX = (int) event.getRawX();
                dragDirection = getDirection(v, (int) event.getX(),
                        (int) event.getY());
            }
            // 处理拖动事件
            delDrag(v, event, action);
            invalidate();
            return false;
        }
    
        /**
         * 处理拖动事件
         * 
         * @param v
         * @param event
         * @param action
         */
        protected void delDrag(View v, MotionEvent event, int action) {
            switch (action) {
            case MotionEvent.ACTION_MOVE:
                int dx = (int) event.getRawX() - lastX;
                int dy = (int) event.getRawY() - lastY;
                switch (dragDirection) {
                case LEFT: // 左边缘
                    left(v, dx);
                    break;
                case RIGHT: // 右边缘
                    right(v, dx);
                    break;
                case BOTTOM: // 下边缘
                    bottom(v, dy);
                    break;
                case TOP: // 上边缘
                    top(v, dy);
                    break;
                case CENTER: // 点击中心-->>移动
                    center(v, dx, dy);
                    break;
                case LEFT_BOTTOM: // 左下
                    left(v, dx);
                    bottom(v, dy);
                    break;
                case LEFT_TOP: // 左上
                    left(v, dx);
                    top(v, dy);
                    break;
                case RIGHT_BOTTOM: // 右下
                    right(v, dx);
                    bottom(v, dy);
                    break;
                case RIGHT_TOP: // 右上
                    right(v, dx);
                    top(v, dy);
                    break;
                }
                if (dragDirection != CENTER) {
                    v.layout(oriLeft, oriTop, oriRight, oriBottom);
                }
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                dragDirection = 0;
                break;
            }
        }
    
        /**
         * 触摸点为中心->>移动
         * 
         * @param v
         * @param dx
         * @param dy
         */
        private void center(View v, int dx, int dy) {
            int left = v.getLeft() + dx;
            int top = v.getTop() + dy;
            int right = v.getRight() + dx;
            int bottom = v.getBottom() + dy;
            if (left < -offset) {
                left = -offset;
                right = left + v.getWidth();
            }
            if (right > screenWidth + offset) {
                right = screenWidth + offset;
                left = right - v.getWidth();
            }
            if (top < -offset) {
                top = -offset;
                bottom = top + v.getHeight();
            }
            if (bottom > screenHeight + offset) {
                bottom = screenHeight + offset;
                top = bottom - v.getHeight();
            }
            v.layout(left, top, right, bottom);
        }
    
        /**
         * 触摸点为上边缘
         * 
         * @param v
         * @param dy
         */
        private void top(View v, int dy) {
            oriTop += dy;
            if (oriTop < -offset) {
                oriTop = -offset;
            }
            if (oriBottom - oriTop - 2 * offset < 200) {
                oriTop = oriBottom - 2 * offset - 200;
            }
        }
    
        /**
         * 触摸点为下边缘
         * 
         * @param v
         * @param dy
         */
        private void bottom(View v, int dy) {
            oriBottom += dy;
            if (oriBottom > screenHeight + offset) {
                oriBottom = screenHeight + offset;
            }
            if (oriBottom - oriTop - 2 * offset < 200) {
                oriBottom = 200 + oriTop + 2 * offset;
            }
        }
    
        /**
         * 触摸点为右边缘
         * 
         * @param v
         * @param dx
         */
        private void right(View v, int dx) {
            oriRight += dx;
            if (oriRight > screenWidth + offset) {
                oriRight = screenWidth + offset;
            }
            if (oriRight - oriLeft - 2 * offset < 200) {
                oriRight = oriLeft + 2 * offset + 200;
            }
        }
    
        /**
         * 触摸点为左边缘
         * 
         * @param v
         * @param dx
         */
        private void left(View v, int dx) {
            oriLeft += dx;
            if (oriLeft < -offset) {
                oriLeft = -offset;
            }
            if (oriRight - oriLeft - 2 * offset < 200) {
                oriLeft = oriRight - 2 * offset - 200;
            }
        }
    
        /**
         * 获取触摸点flag
         * 
         * @param v
         * @param x
         * @param y
         * @return
         */
        protected int getDirection(View v, int x, int y) {
            int left = v.getLeft();
            int right = v.getRight();
            int bottom = v.getBottom();
            int top = v.getTop();
            if (x < 40 && y < 40) {
                return LEFT_TOP;
            }
            if (y < 40 && right - left - x < 40) {
                return RIGHT_TOP;
            }
            if (x < 40 && bottom - top - y < 40) {
                return LEFT_BOTTOM;
            }
            if (right - left - x < 40 && bottom - top - y < 40) {
                return RIGHT_BOTTOM;
            }
            if (x < 40) {
                return LEFT;
            }
            if (y < 40) {
                return TOP;
            }
            if (right - left - x < 40) {
                return RIGHT;
            }
            if (bottom - top - y < 40) {
                return BOTTOM;
            }
            return CENTER;
        }
    
        /**
         * 获取截取宽度
         * 
         * @return
         */
        public int getCutWidth() {
            return getWidth() - 2 * offset;
        }
    
        /**
         * 获取截取高度
         * 
         * @return
         */
        public int getCutHeight() {
            return getHeight() - 2 * offset;
        }
    }

      二.使用View,如果想要对View进行移动,需要在xml中配置android:clickable="true"属性;

        <xxx.DragScaleView
            android:id="@+id/ds"
            android:layout_width="180dip"
            android:layout_height="180dip"
            android:clickable="true" />

      三.效果图,右图是拉伸后的效果
      

      四.关于MotionEvent.getX()和MotionEvent.getRawX()的区别

      getX表示触摸点距离View的左边缘的距离,而getRawX表示触摸点距离手机屏幕左侧的距离;

  • 相关阅读:
    [转帖]VI使用手册
    hadoop安装配置
    永远的beyond!(4 days left to get back touch)
    求比较+围观(3 days left to get back touch)
    Windows及其他软件开发过程中一般都有哪些版本?
    程序员的7个坏习惯
    回来真好,,,
    Windows8 consumer preview的第一次
    那些年,备胎一起追的女神
    准备开始CP之旅。。。。(DP is Over!)
  • 原文地址:https://www.cnblogs.com/a284628487/p/3367228.html
Copyright © 2011-2022 走看看