1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > android 自定义view 缩放放大 平移边界检测

android 自定义view 缩放放大 平移边界检测

时间:2024-04-10 06:50:05

相关推荐

android 自定义view 缩放放大 平移边界检测

由于项目的需要,自定义个view,控制父控件,既可以缩放放大,滑动边界检测。自己实现了通过父控件就能操作子控件的自定义view,直接引用就可以使用。

下面是我实现的一个思路,贴了部分代码,大家可以参考。具体的核心代码我都上传到了我的github上了,大家可以下载试试,感觉好的话,大家给个star

demo下载

在MainActivity调用这个方法去初始化就可以了 :

//parentView对应的是父控件,groupView对应的是子控件GestureViewManager bind = GestureViewManager.bind(this, groupView, parentView);

缩放放大手势

这块我主要是继承原生的ScaleGestureDetector并实现OnScaleGestureListener的事件去处理的。

1、在缩放的同时获取detector.getScaleFactor()的值,由于控件大小不停在改变,所以该值会出现误差导致比例出现异常,因为缩放平移肯定需要有一个边界,所以目前我通过外面包裹ViewGroup,通过给ViewGruop设置手势的方式解决这个问题。因为外面的ViewGroup大小是不会改变的,所以系统计算的比例不会出现问题。有一个ViewGruop也符合我们的需求。2、如果View为可点击的View(Button)或我们给它设置了点击事件,这时View是没办法再监听缩放手势的,我们需要额外处理一下,在缩放手势执行前屏蔽点击事件,在结束后再设置允许点击。3、detector.getScaleFactor()得到的缩放比例都是相对于目前view的大小进行计算的,而我们缩放view时,view的比例都是从原始大小开始的,所以我们必须记录上次缩放的比例,下次开始缩放时,从上次的比例大小开始缩放。

上面的三点是我通过查资料总结的方案,下面是我实现的代码

/*** Created by wdh.* Description :放大缩放手势的监听器*/public class ScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener/*, GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener */ {private View targetView;private float scale = 1;private float scaleTemp = 1;private boolean isFullGroup = false;ScaleGestureListener(View targetView, ViewGroup viewGroup) {this.targetView = targetView;}@Overridepublic boolean onScale(ScaleGestureDetector detector) {scale = scaleTemp * detector.getScaleFactor();targetView.setScaleX(scale);targetView.setScaleY(scale);return false;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {scaleTemp = scale;}float getScale() {return scale;}public boolean isFullGroup() {return isFullGroup;}void setFullGroup(boolean fullGroup) {isFullGroup = fullGroup;}void onActionUp() {if (isFullGroup && scaleTemp < 1) {scale = 1;targetView.setScaleX(scale);targetView.setScaleY(scale);scaleTemp = scale;}}}

到这里就基本实现了缩放和放大的功能,很简单。

2、平移的手势以及移动边界计算

这块我也是用的原生的控件去处理的GestureDetector,并继承SimpleOnGestureListener的监听事件

view大小是不能小于viewGroup的大小的,小于group会回弹到充满viewGroup(后面改成了可选设置)。view小于group大小时需要居中显示。并且缩放时,如果view不在中心,需要虽然比例慢慢回到中心。放大平移时,不能移出group边界。滑动和缩放的手势会起冲突,无法同时监听。所以在控件的onTouchEvent方法中,我们需要自己处理一下,我这里是通过判断按在屏幕上的手指数量,来返回不同手势回调的。一根手指按下,则为滑动手势,两根手指,则为缩放手势。接下来就是计算边界,我们先不考虑缩放的情况,只考虑控件本身可移动的大小。能够移动的距离分别为控件距左、上、右、下的距离。也就是,如果控件向左移动,则判断控件距离左边的距离是否大于0,如果大于0,才允许向左移动。以此类推上、右和下。如下图

通过上面的需求,下面是我的主要代码处理

/*** Description :滑动手势的监听器*/public class ScrollGestureListener extends GestureDetector.SimpleOnGestureListener {@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {distanceX = -distanceX;distanceY = -distanceY;if (isFullGroup || scale > 1) {if (viewWidthReal > groupWidth) {translationXOnScrollEvent(distanceX);}if (viewHeightReal > groupHeight) {translationYOnScrollEvent(distanceY);}} else {translationXOnScrollEvent(distanceX);translationYOnScrollEvent(distanceY);}return super.onScroll(e1, e2, distanceX, distanceY);}private void translationXOnScrollEvent(float distanceX) {//最大移动距离全部为正数,所以需要通过判断distanceX的正负,来判断是向左移动还是向右移动,// 然后通过取distanceX的绝对值来和相应移动方向的最大移动距离比较if ((distanceX < 0 && Math.abs(distanceXTemp + distanceX) < maxTranslationLeft)|| (distanceX > 0 && distanceXTemp + distanceX < maxTranslationRight)) {distanceXTemp += distanceX;targetView.setTranslationX(distanceXTemp);//如果超出边界,就移动到最大距离,防止边界有剩余量} else if ((distanceX < 0 && Math.abs(distanceXTemp + distanceX) > maxTranslationLeft)) {distanceXTemp = -maxTranslationLeft;targetView.setTranslationX(-maxTranslationLeft);} else if ((distanceX > 0 && distanceXTemp + distanceX > maxTranslationRight)) {distanceXTemp = maxTranslationRight;targetView.setTranslationX(maxTranslationRight);}}private void translationYOnScrollEvent(float distanceY) {if ((distanceY < 0 && Math.abs(distanceYTemp + distanceY) < maxTranslationTop)|| (distanceY > 0 && distanceYTemp + distanceY < maxTranslationBottom)) {distanceYTemp += distanceY;targetView.setTranslationY(distanceYTemp);//如果超出边界,就移动到最大距离,防止边界有剩余量} else if ((distanceY < 0 && Math.abs(distanceYTemp + distanceY) > maxTranslationTop)) {distanceYTemp = -maxTranslationTop;targetView.setTranslationY(-maxTranslationTop);} else if ((distanceY > 0 && distanceYTemp + distanceY > maxTranslationBottom)) {distanceYTemp = maxTranslationBottom;targetView.setTranslationY(maxTranslationBottom);}}

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