我是靠谱客的博主 淡淡歌曲,最近开发中收集的这篇文章主要介绍Android手势控制---双指缩放和单指移动,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

作为一个非科班程序员在Android行业已经摸爬滚打5年多了,一直待在小公司,自我感觉能力应该在中上甚至可以达到初高的水平了.前段时间的一次面试彻底给我打回了原形.面试官当时问我觉得自己对那块最熟悉,然后讲解一下.当时脑袋突然就一片空白,这些年大部分时间都是在独立开发,所有的东西都有涉及,但是没有哪块是自己真正深入了解的.反思自己的经历,所有的东西似乎都还停留在会用阶段.向下深入发现自己基础不够牢靠.重新深入学习Android和我个人规划又不相符,所以只能将日后的遇到的问题在此记录下来,主要记录思路,拒绝代码复制粘贴.

起因

公司最近在做一套智能监控系统,需要用到远程实时预览和摄像头控制功能.领导希望在实时预览的同时可以对视频进行双指缩放单指移动,类似米家的摄像头查看功能.大概在网上搜索了一遍,支持直播/缩放/手势的播放器没找到.手势控制绝大多数都是基于图片的.所以决定自己写一个ViewGroup将视频播放器包裹,拦截手势去处理.

实现思路

首先我们确定需要实现的功能有 双指缩放/放大后单指的拖动/原始比例下单指方向控制

实现这个功能我先自定义了ViewGroup,重写了onTouchEvent方法,返回true,对触摸事件进行了消费处理.如果子view有事件冲突可以在ViewGroup中拦截事件分发.
主要代码集中在onTouchEvent中,用到回调有:

  • MotionEvent.ACTION_DOWN (第一个触摸点按下)
  • MotionEvent.ACTION_UP (最后一个触摸点离开)
  • MotionEvent.ACTION_POINTER_DOWN / MotionEvent.ACTION_POINTER_2_DOWN (其他触摸点按下.注:ACTION_POINTER_2_DOWN方法已经废弃,使用ACTION_POINTER_DOWN代替,但是我在小米手机上测试还是回调ACTION_POINTER_2_DOWN,如果有其他触摸点可以使用ACTION_POINTER_3_DOWN等)
  • MotionEvent.ACTION_POINTER_UP (其他触摸点离开)
  • MotionEvent.ACTION_MOVE (触摸点移动)

通过getX() getY()记录原始触摸点坐标

 case MotionEvent.ACTION_DOWN:
point_num = 1;
x_position = event.getX();
y_position = event.getY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_POINTER_2_DOWN:
point_num += 1;
oldDis = (float) spacing(event);
if (point_num == 2) {
x1_position = event.getX();
y1_position = event.getY();
}

在MotionEvent.ACTION_MOVE方法中判断是单指还是双指

 case MotionEvent.ACTION_MOVE:
if (point_num == 1) {
//单指滑动
moveView(event);
} else if (point_num == 2) {
//双指缩放
scaleView(event);
}
break;

也可以使用getPointerCount()方法判断触摸点个数

因为单指移动涉及到放大后的拖动,所以先处理双指缩放问题,原理是通过双指的距离变化不断修改子view的LayoutParams,通过invalidate()方法重绘UI.
事件在ACTION_MOVE回调中处理,所以我们可以实时获取到双指的位置,通过getX(int pointerIndex)方法取到两个触摸点的位置,然后通过勾股定理计算出双指的距离

float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return Math.sqrt(x * x + y * y);

因为手指滑动后不离开屏幕ACTION_MOVE方法一直在回调,所以我们不能直接使用计算出来的双指距离,需要定义一个临时变量记录上一次的双指距离,每次的缩放都是相对于上一次回调而不是触摸时候的回调.
每次回调我们都修改子view的宽高为 原始值+将相对缩放值,为了保证缩放中心位置,同时修改leftMargin和topMargin

if (event.getPointerCount() == 2) {
float scale = (float) ((spacing(event) - oldDis));
float xScale = scale;
float yScale = scale;
params = (LinearLayout.LayoutParams) childView.getLayoutParams();
if (widht + scale <= ScreenUtils.getScreenWidth()) {
xScale = -(widht - ScreenUtils.getScreenWidth());
params.leftMargin = 0;
}
if (height + scale <= ScreenUtils.getScreenWidth() / 16 * 9) {
yScale = -(height - ScreenUtils.getScreenWidth() / 16 * 9);
params.topMargin = 0;
}
params.height = (int) (height += yScale);
params.width = (int) (widht += xScale);
params.leftMargin = params.leftMargin == 0 && xScale < 0 ? 0 : params.leftMargin - (int) (xScale / 2);
params.topMargin = params.topMargin == 0 && yScale < 0 ? 0 : params.topMargin - (int) (yScale / 2);
childView.setLayoutParams(params);
invalidate();
oldDis = (float) spacing(event);
}

需要注意的是无限缩小的问题,我在这里限制如果缩小值+当前子view的宽高小于屏幕的宽高时,不允许继续缩小.暂时对放大没有限制.

单指拖动主要是在画面放大后对子view的位置移动,我们通过当前手指的位置-初始手指的位置来获得移动距离.

int slidLeft = (int) ((currentX_postion - x_position) * 0.03);
int slidTop = (int) ((currentY_position - y_position) * 0.03);

其中0.03是为了控制拖动速度
当子view的宽高和父view的宽高一致时,我们直接回调设备控制,不进行拖动

if ((widht <= ScreenUtils.getScreenWidth() + 5 && currentLeft == 0 && currentTop == 0) &&
height <= ScreenUtils.getScreenWidth() / 16 * 9 + 5 && currentLeft == 0 && currentTop == 0) {
return;
}

具体的逻辑由业务实现,可以通过回调告知业务处理

拖动时候需要注意view边界的问题.需要考虑上下左右各个方向

if (slidLeft > 0) {
if (slidLeft + currentLeft > 0) {
slidLeft = Math.abs(currentLeft);
}
} else if (slidLeft < 0) {
if (Math.abs(slidLeft + currentLeft) > widht - ScreenUtils.getScreenWidth()) {
slidLeft = (int) (widht - ScreenUtils.getScreenWidth() + currentLeft);
}
}
if (slidTop > 0) {
if (slidTop + currentTop > 0) {
slidTop = Math.abs(currentTop);
}
} else if (slidTop < 0) {
if (Math.abs(slidTop + currentTop) > height - ScreenUtils.getScreenWidth() / 16 * 9) {
slidTop = (int) (height - ScreenUtils.getScreenWidth() / 16 * 9 + currentTop);
}
}

在限定范围内修改滑动值以后,修改子view LayoutParams 的leftMargin和topMargin

params.leftMargin = (int) (currentLeft + slidLeft);
params.topMargin = (int) (currentTop + slidTop);
childView.setLayoutParams(params);
invalidate();

结束

只是一个简单的思路介绍,代码优化空间很大.

最后

以上就是淡淡歌曲为你收集整理的Android手势控制---双指缩放和单指移动的全部内容,希望文章能够帮你解决Android手势控制---双指缩放和单指移动所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部