Android控件全解手册 - 任意View缩放平移工具-源码
Unity3D特效百例 | 案例项目实战源码 | Android-Unity实战问题汇总 |
---|---|---|
游戏脚本-辅助自动化 | Android控件全解手册 | 再战Android系列 |
Scratch编程案例 | 软考全系列 | Unity3D学习专栏 |
蓝桥系列 | ChatGPT和AIGC |
👉关于作者
专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
有什么需要欢迎底部卡片私我,交流让学习不再孤单。
👉实践过程
GestureViewBinder
public class GestureViewBinder {
private ScaleGestureBinder scaleGestureBinder;
private ScrollGestureBinder scrollGestureBinder;
private ScaleGestureListener scaleGestureListener;
private ScrollGestureListener scrollGestureListener;
private View targetView;
private ViewGroup viewGroup;
private boolean isScaleEnd = true;
private OnScaleListener onScaleListener;
private boolean isFullGroup = false;
public static GestureViewBinder bind(Context context, ViewGroup viewGroup, View targetView) {
return new GestureViewBinder(context, viewGroup, targetView);
}
private GestureViewBinder(Context context, ViewGroup viewGroup, View targetView) {
this.targetView = targetView;
this.viewGroup = viewGroup;
scaleGestureListener = new ScaleGestureListener(targetView, viewGroup);
scrollGestureListener = new ScrollGestureListener(targetView, viewGroup);
scaleGestureBinder = new ScaleGestureBinder(context, scaleGestureListener);
scrollGestureBinder = new ScrollGestureBinder(context, scrollGestureListener);
targetView.setClickable(false);
viewGroup.setOnTouchListener(new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getPointerCount() == 1 && isScaleEnd) {
return scrollGestureBinder.onTouchEvent(event);
} else if (event.getPointerCount() == 2 || !isScaleEnd) {
isScaleEnd = event.getAction() == MotionEvent.ACTION_UP;
if (isScaleEnd) {
scaleGestureListener.onActionUp();
}
scrollGestureListener.setScale(scaleGestureListener.getScale());
if (onScaleListener != null) {
onScaleListener.onScale(scaleGestureListener.getScale());
}
return scaleGestureBinder.onTouchEvent(event);
}
return false;
}
});
}
private void fullGroup() {
targetView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
targetView.getViewTreeObserver().removeOnPreDrawListener(this);
float viewWidth = targetView.getWidth();
float viewHeight = targetView.getHeight();
float groupWidth = viewGroup.getWidth();
float groupHeight = viewGroup.getHeight();
ViewGroup.LayoutParams layoutParams = targetView.getLayoutParams();
float widthFactor = groupWidth / viewWidth;
float heightFactor = groupHeight / viewHeight;
if (viewWidth < groupWidth && widthFactor * viewHeight <= groupHeight) {
layoutParams.width = (int) groupWidth;
layoutParams.height = (int) (widthFactor * viewHeight);
} else if (viewHeight < groupHeight && heightFactor * viewWidth <= groupWidth) {
layoutParams.height = (int) groupHeight;
layoutParams.width = (int) (heightFactor * viewWidth);
}
targetView.setLayoutParams(layoutParams);
return true;
}
});
}
public boolean isFullGroup() {
return isFullGroup;
}
public void setFullGroup(boolean fullGroup) {
isFullGroup = fullGroup;
scaleGestureListener.setFullGroup(fullGroup);
scrollGestureListener.setFullGroup(fullGroup);
fullGroup();
}
public void setOnScaleListener(OnScaleListener onScaleListener) {
this.onScaleListener = onScaleListener;
}
public interface OnScaleListener {
void onScale(float scale);
}
}
ScaleGestureBinder
public class ScaleGestureBinder extends ScaleGestureDetector {
ScaleGestureBinder(Context context, ScaleGestureListener scaleGestureListener) {
super(context, scaleGestureListener);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
}
ScaleGestureListener
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;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
scale = scaleTemp * detector.getScaleFactor();
targetView.setScaleX(scale);
targetView.setScaleY(scale);
return false;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public 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;
}
}
}
ScrollGestureBinder
class ScrollGestureBinder extends GestureDetector {
ScrollGestureBinder(Context context, ScrollGestureListener scrollGestureListener) {
super(context, scrollGestureListener);
}
}
ScrollGestureListener
public class ScrollGestureListener extends GestureDetector.SimpleOnGestureListener {
private float scale = 1;
private View targetView;
private ViewGroup viewGroup;
private float distanceXTemp = 0;
private float distanceYTemp = 0;
private float viewWidthReal = 0;
private float viewHeightReal = 0;
private float viewWidthRealTemp = 0;
private float viewHeightRealTemp = 0;
private boolean isCalculate = false;
private int viewWidthNormal = 0;
private int viewHeightNormal = 0;
private int groupWidth = 0;
private int groupHeight = 0;
private float maxTranslationLeft = 0;
private float maxTranslationTop = 0;
private float maxTranslationRight = 0;
private float maxTranslationBottom = 0;
private boolean isFullGroup = false;
ScrollGestureListener(View targetView, ViewGroup viewGroup) {
this.targetView = targetView;
this.viewGroup = viewGroup;
}
@Override
public 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);
}
}
@Override
public boolean onDown(MotionEvent e) {
//计算能移动的最大距离
if (!isCalculate) {
isCalculate = true;
maxTranslationLeft = targetView.getLeft();
maxTranslationTop = targetView.getTop();
maxTranslationRight = viewGroup.getWidth() - targetView.getRight();
maxTranslationBottom = viewGroup.getHeight() - targetView.getBottom();
viewWidthNormal = targetView.getWidth();
viewHeightNormal = targetView.getHeight();
viewWidthRealTemp = viewWidthNormal;
viewHeightRealTemp = viewHeightNormal;
viewWidthReal = viewWidthNormal;
viewHeightReal = viewHeightNormal;
groupWidth = viewGroup.getWidth();
groupHeight = viewGroup.getHeight();
}
return true;
}
void setScale(float scale) {
viewWidthReal = viewWidthNormal * scale;
viewHeightReal = viewHeightNormal * scale;
//如果view比group小
if (viewWidthReal < groupWidth) {
if (isFullGroup) {
distanceXTemp = 0;
targetView.setTranslationX(0);
}
maxTranslationLeft = targetView.getLeft() - (viewWidthReal - viewWidthNormal) / 2;
maxTranslationRight = (viewGroup.getWidth() - targetView.getRight()) - (viewWidthReal - viewWidthNormal) / 2;
//如果移动距离超过最大可移动距离
if (scale > this.scale && distanceXTemp < 0 && -distanceXTemp > maxTranslationLeft) {
float translate = (viewWidthReal - viewWidthRealTemp) / 2;
targetView.setTranslationX(targetView.getTranslationX() + translate);
distanceXTemp = distanceXTemp + translate;
} else if (scale > this.scale && distanceXTemp > 0 && distanceXTemp > maxTranslationRight) {
float translate = (viewWidthReal - viewWidthRealTemp) / 2;
targetView.setTranslationX(targetView.getTranslationX() - translate);
distanceXTemp = distanceXTemp - translate;
}
} else {
maxTranslationLeft = (viewWidthReal - viewWidthNormal) / 2 - (viewGroup.getWidth() - targetView.getRight());
maxTranslationRight = (viewWidthReal - viewWidthNormal) / 2 - targetView.getLeft();
if (scale < this.scale && distanceXTemp < 0 && -distanceXTemp > maxTranslationLeft) {
float translate = (viewWidthRealTemp - viewWidthReal) / 2;
targetView.setTranslationX(targetView.getTranslationX() + translate);
distanceXTemp = distanceXTemp + translate;
} else if (scale < this.scale && distanceXTemp > 0 && distanceXTemp > maxTranslationRight) {
float translate = (viewWidthRealTemp - viewWidthReal) / 2;
targetView.setTranslationX(targetView.getTranslationX() - translate);
distanceXTemp = distanceXTemp - translate;
}
}
if (viewHeightReal < groupHeight) {
maxTranslationTop = targetView.getTop() - (viewHeightReal - viewHeightNormal) / 2;
maxTranslationBottom = (viewGroup.getHeight() - targetView.getBottom()) - (viewHeightReal - viewHeightNormal) / 2;
if (isFullGroup) {
distanceYTemp = 0;
targetView.setTranslationY(0);
}
//如果移动距离超过最大可移动距离
if (scale > this.scale && distanceYTemp < 0 && -distanceYTemp > maxTranslationTop) {
float translate = (viewHeightReal - viewHeightRealTemp) / 2;
targetView.setTranslationY(targetView.getTranslationY() + translate);
distanceYTemp = distanceYTemp + translate;
} else if (scale > this.scale && distanceYTemp > 0 && distanceYTemp > maxTranslationBottom) {
float translate = (viewHeightReal - viewHeightRealTemp) / 2;
targetView.setTranslationY(targetView.getTranslationY() - translate);
distanceYTemp = distanceYTemp - translate;
}
} else {
maxTranslationTop = (viewHeightReal - viewHeightNormal) / 2 - (viewGroup.getHeight() - targetView.getBottom());
maxTranslationBottom = (viewHeightReal - viewHeightNormal) / 2 - targetView.getTop();
if (scale < this.scale && distanceYTemp < 0 && -distanceYTemp > maxTranslationTop) {
float translate = (viewHeightRealTemp - viewHeightReal) / 2;
targetView.setTranslationY(targetView.getTranslationY() + translate);
distanceYTemp = distanceYTemp + translate;
} else if (scale < this.scale && distanceYTemp > 0 && distanceYTemp > maxTranslationBottom) {
float translate = (viewHeightRealTemp - viewHeightReal) / 2;
targetView.setTranslationY(targetView.getTranslationY() - translate);
distanceYTemp = distanceYTemp - translate;
}
}
viewWidthRealTemp = viewWidthReal;
viewHeightRealTemp = viewHeightReal;
this.scale = scale;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
float left = viewWidthReal > groupWidth ? 0 : (targetView.getLeft() - ((viewWidthReal - viewWidthNormal) / 2));
float top = viewHeightReal > groupHeight ? 0 : (targetView.getTop() - ((viewHeightReal - viewHeightNormal) / 2));
float right = viewWidthReal > groupWidth ? groupWidth : viewGroup.getWidth() - ((viewGroup.getWidth() - targetView.getRight()) - (viewWidthReal - viewWidthNormal) / 2);
float bottom = viewHeightReal > groupHeight ? groupHeight : viewGroup.getHeight() - ((viewGroup.getHeight() - targetView.getBottom()) - (viewHeightReal - viewHeightNormal) / 2);
RectF rectF = new RectF(left, top, right, bottom);
if (rectF.contains(e.getX(), e.getY())) {
targetView.performClick();
}
return super.onSingleTapUp(e);
}
public boolean isFullGroup() {
return isFullGroup;
}
void setFullGroup(boolean fullGroup) {
isFullGroup = fullGroup;
}
}
👉其他
📢作者:小空和小芝中的小空
📢转载说明-务必注明来源:https://zhima.blog.csdn.net/
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。
温馨提示:点击下方卡片获取更多意想不到的资源。