Android ARCore:修改平移与旋转的默认手势
嘿,我之前刚好折腾过Sceneform的手势自定义,这个需求完全可以通过重写手势检测逻辑来实现,给你一步步拆解怎么做:
自定义Sceneform手势交互实现方案
首先得明确:Sceneform默认的单指平移、双指旋转是由TransformableNode自带的TransformationSystem处理的,我们要做的就是替换这套默认逻辑,实现自己的触摸事件响应。
1. 写一个自定义手势检测器
先创建一个CustomGestureDetector类,用来区分单指和双指操作,同时定义回调接口让我们后续处理具体的模型变换:
public class CustomGestureDetector extends BaseGestureDetector { private final ScaleGestureDetector scaleDetector; private final GestureDetector tapDetector; private MotionEvent lastEvent; private OnCustomGestureListener listener; // 自定义手势回调,把不同操作的事件抛出去 public interface OnCustomGestureListener { void onSingleFingerRotate(float deltaX); // 单指左右滑动旋转 void onTwoFingerPan(float dx, float dy); // 双指平移 } public CustomGestureDetector(Context context, OnCustomGestureListener listener) { this.listener = listener; scaleDetector = new ScaleGestureDetector(context, new ScaleListener()); tapDetector = new GestureDetector(context, new TapListener()); } @Override public boolean onTouchEvent(MotionEvent event) { scaleDetector.onTouchEvent(event); tapDetector.onTouchEvent(event); // 先记录上一次的触摸事件,用来计算偏移量 if (lastEvent == null) { lastEvent = MotionEvent.obtain(event); return true; } int pointerCount = event.getPointerCount(); switch (pointerCount) { case 1: // 单指操作:左右滑动触发旋转 if (event.getAction() == MotionEvent.ACTION_MOVE) { float deltaX = event.getX() - lastEvent.getX(); listener.onSingleFingerRotate(deltaX); } break; case 2: // 双指操作:计算双指中点的偏移,用来平移模型 float currMidX = (event.getX(0) + event.getX(1)) / 2; float currMidY = (event.getY(0) + event.getY(1)) / 2; float lastMidX = (lastEvent.getX(0) + lastEvent.getX(1)) / 2; float lastMidY = (lastEvent.getY(0) + lastEvent.getY(1)) / 2; float dx = currMidX - lastMidX; float dy = currMidY - lastMidY; listener.onTwoFingerPan(dx, dy); break; } lastEvent.recycle(); lastEvent = MotionEvent.obtain(event); return true; } // 如果你需要保留缩放功能,可以在这里实现,不需要就留空 private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {} // 处理点击类的手势,比如重置模型位置之类的,按需添加 private class TapListener extends GestureDetector.SimpleOnGestureListener {} }
2. 在AR场景中替换默认手势
找到你的ARFragment或者Activity,获取到要操作的TransformableNode,然后禁用默认手势,绑定我们自己的检测器:
// 假设你已经通过加载模型创建了TransformableNode TransformableNode modelNode = ...; ARSceneView sceneView = arFragment.getArSceneView(); // 第一步:禁用Sceneform默认的手势识别 modelNode.getTransformationSystem().clearGestureRecognizers(); // 第二步:初始化自定义手势检测器,实现具体的模型变换逻辑 CustomGestureDetector customDetector = new CustomGestureDetector(getContext(), new CustomGestureDetector.OnCustomGestureListener() { @Override public void onSingleFingerRotate(float deltaX) { // 调整旋转灵敏度:deltaX乘以的系数越大,旋转越快,按需调整 float rotationDegree = deltaX * 0.4f; // 绕Y轴旋转(左右滑对应水平旋转) Quaternion rotation = Quaternion.axisAngle(new Vector3(0, 1, 0), rotationDegree); modelNode.setWorldRotation(modelNode.getWorldRotation().multiply(rotation)); } @Override public void onTwoFingerPan(float dx, float dy) { // 将屏幕坐标的偏移转换为世界坐标的平移,Z值可以根据模型距离调整,影响平移速度 Camera camera = sceneView.getScene().getCamera(); Vector3 worldDelta = camera.screenToWorldPoint(new Vector3(dx, -dy, 0)); // 更新模型位置 modelNode.setWorldPosition(modelNode.getWorldPosition().add(worldDelta)); } }); // 第三步:将自定义检测器绑定到场景的触摸事件 sceneView.getScene().addOnTouchListener((v, event) -> customDetector.onTouchEvent(event));
3. 细节优化建议
- 旋转灵敏度:可以根据实际体验调整
rotationDegree = deltaX * 0.4f里的系数,数值越大旋转越灵敏 - 平移速度:
screenToWorldPoint的Z参数如果设得更大,平移速度会变慢,反之更快,你可以根据模型和相机的距离动态调整 - 误触防护:可以给单指旋转加个阈值,比如当
deltaX的绝对值大于5才触发旋转,避免轻微滑动就误操作 - 保留缩放:如果需要保留双指缩放,只需要在
ScaleListener里实现onScale方法,调整模型的缩放比例就行
我当时也是翻了好久官方文档没找到明确说明,后来自己啃了默认手势的源码才搞明白这套逻辑,上面的代码应该能直接满足你的需求啦!
内容的提问来源于stack exchange,提问作者vtodorova
相关产品推荐
相关产品推荐

