java - 在自定义布局中平移、翻转、缩放和更正边框
问题描述
你好!感谢您的阅读。
我一直在寻找正确创建一定大小(用户屏幕的 5 倍)的多方向可滚动Android 布局的方法,该布局可以被投掷(&平移)并且也可以被放大。
请注意,让孩子(ConstraintLayout)成为想要的大小(用户屏幕的 5 倍)不是这里的问题。
显然,我在网上找到了很多答案,可以通过不同的方式来整合它。最初,我正准备发布迄今为止我尝试过的所有不同的集成,直到我遇到了Oded 的解决方案。在这一个中,所有不能正常工作的东西都起作用了。
这表示:
- 布局允许滚动孩子的整个宽度和高度,但不能再滚动了
- 可滚动区域的边界/边框使用缩放正确缩放(这是交易破坏者,几乎没有自定义布局可以做到这一点)
- 布局可以平移
- 枢轴点是正确的(在中间)。
这是一个巨大的解脱,因为修改不同的已经制作但缺乏集成(主要修复边界+缩放问题)已经花费了几天时间。
我建议将来遇到类似问题的任何人使用此集成。
在任何情况下,都有一些问题,包括:在屏幕方向更改时返回 (0,0)、没有双击缩放和没有投掷。我认为解决这两个第一个问题并不难,但是第三个问题很成问题。我希望用户能够自由地查看这个大区域。没有投掷能力会使在应用程序中的移动速度比首选速度慢。
我已经尝试过不同的方法来做到这一点,例如使用带有 GestureDetector 的 Scroller 类、使用“Flinger”可运行类(包含 Scroller)、使用某种形式的 Choreographer 等等。
我一直无法让它工作,并且解决方案通常会完全破坏这种布局进行滚动的方式(例如,我注意到 scrollX 永远不会改变,并且不存在 scrollTo 功能(它被 mPosX 取代))。通常在这里添加 Flinging 的正确解决方案似乎无法使用,并且在某些情况下,实现会导致滚动条从应有的位置移动数千个单位。
这是我的 Odid 解决方案的备份副本,唯一的更改是进行细微调整以避免 Android Studio 警告。
片段(必填):
@Override
public boolean onTouchEvent(MotionEvent ev) {
mOnTouchEventWorkingArray[0] = ev.getX();
mOnTouchEventWorkingArray[1] = ev.getY();
mOnTouchEventWorkingArray = scaledPointsToScreenPoints(mOnTouchEventWorkingArray);
ev.setLocation(mOnTouchEventWorkingArray[0], mOnTouchEventWorkingArray[1]);
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
if (mIsScaling && ev.getPointerCount() == 1) {
// Don't move during a QuickScale.
mLastTouchX = x;
mLastTouchY = y;
break;
}
float dx = x - mLastTouchX;
float dy = y - mLastTouchY;
float[] topLeft = {0f, 0f};
float[] bottomRight = {getWidth(), getHeight()};
/*
* Corners of the view in screen coordinates, so dx/dy should not be allowed to
* push these beyond the canvas bounds.
*/
float[] scaledTopLeft = screenPointsToScaledPoints(topLeft);
float[] scaledBottomRight = screenPointsToScaledPoints(bottomRight);
dx = Math.min(Math.max(dx, scaledBottomRight[0] - mCanvasWidth), scaledTopLeft[0]);
dy = Math.min(Math.max(dy, scaledBottomRight[1] - mCanvasHeight), scaledTopLeft[1]);
mPosX += dx;
mPosY += dy;
mTranslateMatrix.preTranslate(dx, dy);
mTranslateMatrix.invert(mTranslateMatrixInverse);
mLastTouchX = x;
mLastTouchY = y;
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
非常感谢您的帮助。
解决方案
推荐阅读
- amazon-web-services - 通过 CloudFormation 从 AWS Marketplace 启动 AMI
- node.js - 当一内一请求时,Chai-http 不检查第二个断言
- java - Wicket - 如何使用 ajax 刷新表中的单行
- python - Robotframework“选择文件”导致AttributeError:模块'base64'在docker中没有属性'encodestring'
- c# - 是否可以获取一个枚举列表并将其转换为另一个?
- swift - 带有导航项的自动布局
- django - Django 管理员查看错误
- docker - Docker Swarm 调度策略
- javascript - 删除后 Nuxt 处理重定向且无错误:beforeUpdate 方向不起作用?
- java - Process,map and collect object in one stream call