我正在编写一个组件来处理缩放,旋转和平移的手势识别。令人遗憾的是,缩放不起作用,它没有收到缩小,并且放大效果不好,因为当视图很大时,它什么也没做,似乎只有在到达视图边缘时才起作用。
public class MyGestureDetector implements ScaleGestureDetector.OnScaleGestureListener {
private static final int INVALID_POINTER_ID = -1;
private float fX, fY, sX, sY;
private int ptrID1, ptrID2;
private float mAngle;
private float mPreviousAngle = 0;
private float mDeltaAngle;
private float dX, dY;
private boolean isClick, isMove;
private float mRatio = 1.0f;
private int mBaseDist;
private float mBaseRatio;
private final static float STEP = 200;
private Vector2D movement = new Vector2D();
private Vector2D movementRaw = new Vector2D();
private ScaleGestureDetector mScaleGestureDetector;
private OnGestureListener mListener;
public float getAngle() {
return mAngle;
}
public float getScaling() {
return mRatio;
}
public Vector2D getMovement() {
return movement;
}
public Vector2D getMovementRaw() {
return movementRaw;
}
private ScaleGestureDetector gestureScale;
private float scaleFactor = 1;
private boolean inScale = false;
public MyGestureDetector(OnGestureListener listener){
gestureScale = new ScaleGestureDetector((Context) listener, this);
mListener = listener;
ptrID1 = INVALID_POINTER_ID;
ptrID2 = INVALID_POINTER_ID;
}
public boolean onTouchEvent(MotionEvent event, View view){
gestureScale.onTouchEvent(event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
isClick=true;
isMove=true;
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
currentPosition = new Vector2D(event.getRawX(), event.getRawY());
ptrID1 = event.getPointerId(event.getActionIndex());
break;
case MotionEvent.ACTION_POINTER_DOWN:
if(ptrID2 == INVALID_POINTER_ID ) {
ptrID2 = event.getPointerId(event.getActionIndex());
int pt1 = event.findPointerIndex(ptrID1);
int pt2 = event.findPointerIndex(ptrID2);
if(pt1 < 0 || pt2 < 0 ){
return false;
}
mBaseDist = getDistance(event);
mBaseRatio = mRatio;
startX = event.getRawX() - view.getX() + centerX;
startY = event.getRawY() - view.getY() + centerY;
sX = event.getX(pt1);
sY = event.getY(pt1);
fX = event.getX(pt2);
fY = event.getY(pt2);
isClick=false;
isMove=false;
}
break;
case MotionEvent.ACTION_MOVE:
if(ptrID1 != INVALID_POINTER_ID && ptrID2 != INVALID_POINTER_ID) {
int pt1 = event.findPointerIndex(ptrID1);
int pt2 = event.findPointerIndex(ptrID2);
if(pt1 < 0 || pt2 < 0 ){
return false;
}
/// Scaling
float delta = (getDistance(event) - mBaseDist) / STEP;
float multi = (float) Math.pow(2, delta);
//mRatio = Math.min(10.0f, Math.max(0.5f, mBaseRatio * multi));
/// Rotating
float nfX, nfY, nsX, nsY;
nsX = event.getX(pt1);
nsY = event.getY(pt1);
nfX = event.getX(pt2);
nfY = event.getY(pt2);
if(nsX < 0 || nsY < 0 || nfX < 0 || nfY < 0){
return false;
}
mAngle = angleBetweenLines(fX, fY, sX, sY, nfX, nfY, nsX, nsY);
mDeltaAngle = mAngle - mPreviousAngle;
if (mListener != null) {
mPreviousAngle = mAngle;
mListener.OnRotation(this);
//mListener.OnScaling(this);
}
}else{
if(!currentPosition.toString().equals(new Vector2D(event.getRawX(), event.getRawY()).toString())){
isClick=false;
}
currentPosition = new Vector2D(event.getRawX(), event.getRawY());
movement.set(event.getRawX() + dX, event.getRawY() + dY);
movementRaw.set(event.getRawX() , event.getRawY() );
if (isMove && mListener != null) {
mListener.OnMove(this);
}
}
break;
case MotionEvent.ACTION_UP:
if(isClick) {
if (mListener != null) {
mListener.OnClick(this);
}
}else{
mListener.OnStopGesture(this);
}
ptrID1 = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP:
ptrID2 = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_CANCEL:
ptrID1 = INVALID_POINTER_ID;
ptrID2 = INVALID_POINTER_ID;
break;
}
return true;
}
int getDistance(MotionEvent event) {
int dx = (int) (event.getX(0) - event.getX(1));
int dy = (int) (event.getY(0) - event.getY(1));
return (int) (Math.sqrt(dx * dx + dy * dy));
}
float centerX, centerY, startR, startScale, startX, startY, startRotation, startA;
TextView tv;
Vector2D currentPosition;
private float angleBetweenLines (float fX, float fY, float sX, float sY, float nfX, float nfY, float nsX, float nsY)
{
float angle1 = (float) Math.atan2( (fY - sY), (fX - sX) );
float angle2 = (float) Math.atan2( (nfY - nsY), (nfX - nsX) );
float angle = ((float)Math.toDegrees(angle1 - angle2)) % 360;
if (angle < -180.f) angle += 360.0f;
if (angle > 180.f) angle -= 360.0f;
return angle;
}
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
scaleFactor *= scaleGestureDetector.getScaleFactor();
//scaleFactor = (scaleFactor < 1 ? : scaleFactor); // prevent our view from becoming too small //
scaleFactor = ((float)((int)(scaleFactor * 100))) / 100; // Change precision to help with jitter when user just rests their fingers //
mRatio = scaleFactor;
if (mListener != null) {
mListener.OnScaling(this);
}
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
inScale = true;
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
inScale = false;
}
public static interface OnGestureListener {
public void OnRotation(MyGestureDetector rotationDetector);
public void OnScaling(MyGestureDetector rotationDetector);
public void OnMove(MyGestureDetector rotationDetector);
public void OnClick(MyGestureDetector rotationDetector);
public void OnStopGesture(MyGestureDetector rotationDetector);
}
}
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
从你的代码片段来看,你已经实现了对缩放、旋转和平移的手势识别的基本框架。对于缩放功能不理想的问题,这里有几个可能的优化方向和建议:
缩放因子的处理: 在onScale()
方法中,你需要确保缩放因子在合理的范围内,避免过快或过慢的缩放速度导致体验不佳。你可以考虑设置一个最小和最大缩放比例来限制缩放范围,并且使用平滑算法(如指数平滑)来控制缩放速度,使得缩放过程更加自然。
private float scaleFactorMin = 0.5f;
private float scaleFactorMax = 2.0f;
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
float newScaleFactor = scaleFactor * scaleGestureDetector.getScaleFactor();
// 限制缩放因子在指定范围内
scaleFactor = Math.min(Math.max(newScaleFactor, scaleFactorMin), scaleFactorMax);
// 应用缩放
// ...
return true;
}
视图边缘检测问题: 如果缩放仅在视图边缘起作用,这可能是由于你在处理缩放时没有正确地更新视图的位置和大小。确保在缩放操作中同时调整视图的中心点位置以及其尺寸,以适应新的缩放比例。可以使用View.setScaleX()
, View.setScaleY()
或者 View.setTranslationX/Y()
来动态改变视图的大小和位置。
触控点的管理: 确保在多指操作时正确跟踪并计算两个触控点的距离变化,这是缩放动作的基础。你的代码似乎已经包含了这部分逻辑,但要检查是否有逻辑错误或遗漏,特别是在ACTION_POINTER_DOWN
和ACTION_POINTER_UP
事件中的触控点ID管理。
调试与日志: 添加详细的日志记录,特别是关于触控点坐标、缩放因子的变化等信息,可以帮助你定位问题所在。通过观察这些数据,你可以更直观地理解为什么缩放行为不符合预期。
性能与响应性: 确保手势识别和视图更新的效率,避免在UI线程进行耗时操作。如果有必要,可以考虑使用动画或者异步处理来提高用户体验。
最后,考虑到你是在阿里云平台上提问,虽然这个问题更多是关于Android开发技术细节,但如果你的应用涉及到后端服务、数据库存储、图像处理等需求,阿里云提供了诸如对象存储OSS、云数据库RDS、函数计算FC等多种服务,可以为你的应用提供强大的支持。
你好,我是AI助理
可以解答问题、推荐解决方案等