一.首先说一下定义这样一个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();}@Overrideprotected 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);}@Overridepublic 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.DragScaleViewandroid:id="@+id/ds"android:layout_width="180dip"android:layout_height="180dip"android:clickable="true" />

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

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

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

转载于:https://www.cnblogs.com/a284628487/p/3367228.html

Android 自定义View可拖动移动位置及边缘拉伸放大缩小相关推荐

  1. android 自定义view实现拖动放大缩小_自定义itemClickView

    和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.自定义View类实现 二.自定义View标签 三.自定义View 布局 四.自定义View 选择器 ...

  2. android 自定义view实现拖动放大缩小_自定义itemCheckView

    阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 自定义View类实现 自定义View标签 ...

  3. android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果

    首先呢,还是一贯作风,我们先来看看众多应用中的示例:(这种效果是很常见的,可以说应用的必须品.)                搜狐客户端                               ...

  4. android 自定义view滚动条,Android自定义View实现等级滑动条的实例

    Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候 ...

  5. android 自定义View 视差动画

    本系列自定义View全部采用kt **系统: **mac android studio: 4.1.3 **kotlin version:**1.5.0 gradle: gradle-6.5-bin.z ...

  6. Android自定义View之七色环颜色采集器: 续我未完的大学梦 !

    Android自定义View之七色环颜色采集器:续我未完的大学梦!! 一.前言. 在大学期间,看到机智云开源的这个rgb灯,蛮好奇的,这么漂亮的颜色采集,并且可以同步到设备rbg灯颜色,甚是不解!这个 ...

  7. android自定义View: 九宫格解锁

    本系列自定义View全部采用kt 系统:mac android studio: 4.1.3 kotlin version1.5.0 gradle: gradle-6.5-bin.zip 废话不多说,先 ...

  8. Android自定义View —— TypedArray

    在上一篇中Android 自定义View Canvas -- Bitmap写到了TypedArray 这个属性 下面也简单的说一下TypedArray的使用 TypedArray 的作用: 用于从该结 ...

  9. android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...

    转载:http://blog.csdn.net/xiabing082/article/details/48781489 1.  大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...

  10. Android自定义View:ViewGroup(三)

    自定义ViewGroup本质是什么? 自定义ViewGroup本质上就干一件事--layout. layout 我们知道ViewGroup是一个组合View,它与普通的基本View(只要不是ViewG ...

最新文章

  1. DIV+CSS规范命名大全集合
  2. 高斯混合模型GMM、核心参数、高斯混合模型GMM的数学形式
  3. spring boot中SpringBootCondition框架
  4. 如何成为一个合格的 Java程序员
  5. tomcat 显示访问的ip白名单
  6. python 速度 memmap_使用python测量文件的读写速度
  7. Jquery中$(document).ready(function(){ })函数的使用详解
  8. 2912: 奇怪的加法问题(XOR的加法写法)
  9. 图:智能手机Android系统的评委专用的比赛打分客户端,开发进行中...
  10. 92套AE抖音快闪模板(精品)
  11. word使用技巧---插入图片显示不全的解决方案
  12. 《算法基础》线性枚举(一)——最值算法
  13. NLPCC-2019 依存句法分析领域移植评测技术分享(封闭情况下双第一)
  14. 【赚钱应跟Apple,做大不忘Google】移动开发时代的开发者选择
  15. openoffice相关命令
  16. vue 点击打开pdf
  17. 如何批量压缩pdf文件到最小
  18. 网易WEB白帽子-WEB安全体系建设
  19. 找不到 cl.exe 解决办法
  20. RecyclerView布局中解决edittext监听错乱

热门文章

  1. 16 数值的整数次方 (第3章 高质量的代码-代码的完整性)
  2. docker tar 镜像 容器相互转换
  3. easyui ---- jEasyUI-定制提示信息面板组件
  4. ChipScope用法总结
  5. 今天起改用mac的marsedit写博
  6. eclipse jre 参数
  7. Oracle Database Documentary Library
  8. 你不主动去要世界也不会给你 漫话开源项目的可持续发展之路
  9. [转]如何使用消息系统避免分布式事务?
  10. 《软件设计师》考点分布