600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > android控件旋转 缩放 平移完美版方案(双指操作 单指操作都有)

android控件旋转 缩放 平移完美版方案(双指操作 单指操作都有)

时间:2021-04-23 20:22:11

相关推荐

android控件旋转 缩放 平移完美版方案(双指操作 单指操作都有)

前言

项目要求模仿时光手杖APP做一个可平移、旋转、缩放的控件,于是就开始研究了起来,网上找的方案加上自己的思考,得出了以下完美版平移、缩放、旋转控件,双指缩放旋转,单指缩放旋转都支持。

效果图

我们做出来的控件效果会比上图略好,时光手帐不支持双指的旋转,我们这个控件是支持的。

核心代码

1.单双指旋转缩放平移逻辑

switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:if (mOnTouchListener != null) {mOnTouchListener.onTouch(this);}setBorder(true);oriLeft = getLeft();oriRight = getRight();oriTop = getTop();oriBottom = getBottom();lastTrueY = event.getRawY();lastTrueX = event.getRawX();oriX = (int) event.getRawX();oriY = (int) event.getRawY();lastSpacing = getSpacingRelateMidPoint(oriX,oriY);textRotationDegree = getRotation();scale = getScaleX();if (initWidth == 0) {initWidth = oriRight - oriLeft;if (initWidth <= 0) {initWidth = minWidth;}}if (initHeight == 0) {initHeight = oriBottom - oriTop;if (initHeight <= 0) {initHeight = minHeight;}}LogUtil.d(TAG + " initWidth = " + initWidth + " ,initHeight = " + initHeight);moveType = 1;actionX = event.getRawX();actionY = event.getRawY();break;case MotionEvent.ACTION_POINTER_DOWN:moveType = 2;spacing = getSpacing(event);degree = getDegree(event);break;case MotionEvent.ACTION_MOVE:if (mOnTouchListener != null) {mOnTouchListener.onMoveEvent(this);}updateLocation();//更新图标图片可见矩形float tempRawX = event.getRawX();float tempRawY = event.getRawY();float dx = tempRawX - lastTrueX;float dy = tempRawY - lastTrueY;lastTrueX = tempRawX;lastTrueY = tempRawY;if (event.getPointerCount() == 1 && dragDirection == RIGHT_BOTTOM) {Point cen = new Point(oriLeft+(oriRight-oriLeft)/2,oriTop+(oriBottom-oriTop)/2);Point first = new Point(oriX,oriY);Point second = new Point((int) tempRawX,(int) tempRawY);//旋转textRotationDegree += angle(cen,first,second);setRotation(textRotationDegree);//缩放float tempScale = 1.0f;lastSpacing = getSpacing(cen,first);currentSpacing = getSpacing(cen,second);tempScale = currentSpacing/lastSpacing;//想增加拖动缩放的灵敏度,将0.02增大即可if (tempScale < 1) {tempScale -= 0.008;} else if (tempScale > 1) {tempScale += 0.008;}scale = scale * tempScale;if(scale >= MAX_SCALE){scale = MAX_SCALE;}else if(scale <= MIN_SCALE){scale = MIN_SCALE;}setScaleX(scale);setScaleY(scale);oriX = (int) tempRawX;oriY = (int) tempRawY;lastSpacing = currentSpacing;resetCornerSize();break;}if (moveType == 1) {translationX = getTranslationX();translationY = getTranslationY();if (isTranstX(event.getRawX()))translationX = translationX + event.getRawX() - actionX;if (isTranstY(event.getRawY()))translationY = translationY + event.getRawY() - actionY;setTranslationX(translationX);setTranslationY(translationY);actionX = event.getRawX();actionY = event.getRawY();} else if (moveType == 2) {scale = scale * getSpacing(event) / spacing;setScaleX(scale);setScaleY(scale);rotation = rotation + getDegree(event) - degree;if (rotation > 360) {rotation = rotation - 360;}if (rotation < -360) {rotation = rotation + 360;}setRotation(rotation);resetCornerSize();}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_POINTER_UP:if (mOnTouchListener != null) {mOnTouchListener.onActionUp();}moveType = 0;dragDirection = CENTER;requestLayout();}

2.相关计算(角度、距离等)

public float angle(Point cen, Point first, Point second){float dx1, dx2, dy1, dy2;dx1 = first.x - cen.x;dy1 = first.y - cen.y;dx2 = second.x - cen.x;dy2 = second.y - cen.y;// 计算三边的平方float ab2 = (second.x - first.x) * (second.x - first.x) + (second.y - first.y) * (second.y - first.y);float oa2 = dx1*dx1 + dy1*dy1;float ob2 = dx2 * dx2 + dy2 *dy2;// 根据两向量的叉乘来判断顺逆时针boolean isClockwise = ((first.x - cen.x) * (second.y - cen.y) - (first.y - cen.y) * (second.x - cen.x)) > 0;// 根据余弦定理计算旋转角的余弦值double cosDegree = (oa2 + ob2 - ab2) / (2 * Math.sqrt(oa2) * Math.sqrt(ob2));// 异常处理,因为算出来会有误差绝对值可能会超过一,所以需要处理一下if (cosDegree > 1) {cosDegree = 1;} else if (cosDegree < -1) {cosDegree = -1;}// 计算弧度double radian = Math.acos(cosDegree);// 计算旋转过的角度,顺时针为正,逆时针为负return (float) (isClockwise ? Math.toDegrees(radian) : -Math.toDegrees(radian));}private LayoutParams setLayoutParams(View view) {LayoutParams ltparams = (LayoutParams) view.getLayoutParams();currentCornerWidth = (int) (dp2px(19) / scale);currentCornerHeight = (int) (dp2px(19) / scale);ltparams.width = currentCornerWidth;ltparams.height = currentCornerHeight;return ltparams;}// 触碰两点间距离private float getSpacing(MotionEvent event) {//通过三角函数得到两点间的距离float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return (float) Math.sqrt(x * x + y * y);}// 触碰两点间距离private float getSpacing(Point start,Point end) {//通过三角函数得到两点间的距离float x = end.x - start.x;float y = end.y - start.y;return (float) Math.sqrt(x * x + y * y);}// 获得某点相对于中点的距离private float getSpacingRelateMidPoint(int pointX,int pointY) {//通过三角函数得到两点间的距离Point midPoint = new Point(oriLeft+(oriRight-oriLeft),oriTop+(oriBottom-oriTop));float x = pointX - midPoint.x;float y = pointY - midPoint.y;return (float) Math.sqrt(x * x + y * y);}// 取旋转角度private float getDegree(MotionEvent event) {//得到两个手指间的旋转角度double delta_x = event.getX(0) - event.getX(1);double delta_y = event.getY(0) - event.getY(1);double radians = Math.atan2(delta_y, delta_x);return (float) Math.toDegrees(radians);}/*** 触摸点为中心->>移动*/private void center(int dx, int dy) {// isTopLimit = false;// isBottomLimit = false;int left = getLeft() + dx;int top = getTop() + dy;int right = getRight() + dx;int bottom = getBottom() + dy;if (left < 0) {left = 0;right = left + getWidth();}if (right > screenWidth) {right = screenWidth;left = right - getWidth();}if (top < 0) {top = 0;bottom = top + getHeight();// isTopLimit = true;}if (bottom > screenHeight) {bottom = screenHeight;top = bottom - getHeight();// isBottomLimit = true;}oriLeft = left;oriTop = top;oriRight = right;oriBottom = bottom;}/*** 触摸点为上边缘*/private void top(int dy) {// isTopLimit = false;// isBottomLimit = false;int lastTop = oriTop;oriTop += dy;int newTop = oriTop;Log.e("新旧长度:", lastTop + "," + newTop);if (isImage) {oriLeft += dy / 2;oriRight -= dy / 2;if (oriLeft < 0) {oriLeft = 0;}if (oriRight - oriLeft < minWidth) {oriLeft = oriRight - minWidth;}if (oriRight > screenWidth) {oriRight = screenWidth;}if (oriRight - oriLeft < minWidth) {oriRight = oriLeft + minWidth;}}if (oriTop < 0) {oriTop = 0;// isTopLimit = true;}if (oriBottom - oriTop < minHeight) {oriTop = oriBottom - minHeight;}}/*** 触摸点为下边缘*/private void bottom(int dy) {// isTopLimit = false;// isBottomLimit = false;oriBottom += dy;if (isImage) {oriLeft -= dy / 2;oriRight += dy / 2;if (oriLeft < 0) {oriLeft = 0;}if (oriRight - oriLeft < minWidth) {oriLeft = oriRight - minWidth;}if (oriRight > screenWidth) {oriRight = screenWidth;}if (oriRight - oriLeft < minWidth) {oriRight = oriLeft + minWidth;}}if (oriBottom > screenHeight) {oriBottom = screenHeight;// isBottomLimit = true;}if (oriBottom - oriTop < minHeight) {oriBottom = minHeight + oriTop;}}/*** 触摸点为右边缘*/private void right(int dx) {// isTopLimit = false;// isBottomLimit = false;oriRight += dx;if (isImage) {oriTop -= dx / 2;oriBottom += dx / 2;if (oriTop < 0) {oriTop = 0;//isTopLimit = true;}if (oriBottom - oriTop < minHeight)oriTop = oriBottom = minHeight;if (oriBottom > screenHeight) {oriBottom = screenHeight;//isBottomLimit = true;}if (oriBottom - oriTop < minHeight) {oriBottom = minHeight + oriTop;}}if (oriRight > screenWidth) {oriRight = screenWidth;}if (oriRight - oriLeft < minWidth) {oriRight = oriLeft + minWidth;}}/*** 触摸点为左边缘*/private void left(int dx) {// isTopLimit = false;// isBottomLimit = false;oriLeft += dx;if (isImage) {oriTop += dx / 2;oriBottom -= dx / 2;if (oriTop < 0) {oriTop = 0;//isTopLimit = true;}if (oriBottom - oriTop < minHeight)oriTop = oriBottom = minHeight;if (oriBottom > screenHeight) {oriBottom = screenHeight;//isBottomLimit = true;}if (oriBottom - oriTop < minHeight) {oriBottom = minHeight + oriTop;}}if (oriLeft < 0) {oriLeft = 0;}if (oriRight - oriLeft < minWidth) {oriLeft = oriRight - minWidth;}}

总结

以上就是该控件的核心代码和功能介绍。实现平移很简单,实现旋转和缩放的话,重点在于角度和距离的计算,因此需要一定的数学知识。以上代码是从项目中截取的重点部分,可能无法直接套用或者缺少一些东西,但是实现思路很明确了,提供给大家做个参考或者移植到自己的项目中。希望能帮到跟我遇到同样需求的攻城狮。有疑问可在下方留言。

该类完整代码下载地址:/download/yonghuming_jesse/11906385

另,附上博主自己的淘宝客项目下载码(可查淘宝商品优惠券,使用优惠券购物后可加微信客服返现,返现额度全网最高,客服微信android_jesse):

博主上传资源下载链接:

全屏播放视频不拉伸源码:

/download/yonghuming_jesse/10646274

科大讯飞语音评测服务接入源码:

/download/yonghuming_jesse/10616924

android饺子播放器使用源码:

/download/yonghuming_jesse/10619119

视频播放前显示视频第一帧源码:

/download/yonghuming_jesse/10646332

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。