我正在研究这个Android项目,它具有像3D棋盘网格这样的典型UI。在此屏幕上有缩放平移/拖动功能。 我通过创建自定义框架布局类来实现此功能。 片段:
public class ZoomLayout extends FrameLayout implements ScaleGestureDetector.OnScaleGestureListener {
float x1=0,y1=0,x2,y2;
ScaleGestureDetector scaleDetector;
Context mContext;
private enum Mode {
NONE,
DRAG,
ZOOM
}
private static final String TAG = "ZoomLayout";
private static final float MIN_ZOOM = 1.0f;
private static final float MAX_ZOOM = 6.0f;
private Mode mode = Mode.NONE;
private float scale = 1.0f;
private float lastScaleFactor = 0f;
// Where the finger first touches the screen
private float startX = 0f;
private float startY = 0f;
// How much to translate the canvas
private float dx = 0f;
private float dy = 0f;
private float prevDx = 0f;
private float prevDy = 0f;
ApiCommunicationListener apiListener;
Activity mActivity;
public ZoomLayout(Context context, ApiCommunicationListener apiListener, Activity activity) {
super(context);
this.apiListener = apiListener;
this.mActivity = activity;
init(context);
}
public ZoomLayout(Context context) {
super(context);
init(context);
}
public ZoomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZoomLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mContext = context;
scaleDetector = new ScaleGestureDetector(context, this);
}
@Override
public boolean onTouchEvent(final MotionEvent motionEvent) {
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
x1 = motionEvent.getX();
y1 = motionEvent.getY();
// System.out.println("TOUCH DOWN : X:" + x1 + " Y:" + y1);
if (scale > MIN_ZOOM) {
mode = Mode.DRAG;
startX = motionEvent.getX() - prevDx;
startY = motionEvent.getY() - prevDy;
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == Mode.DRAG) {
dx = motionEvent.getX() - startX;
dy = motionEvent.getY() - startY;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = Mode.ZOOM;
break;
case MotionEvent.ACTION_POINTER_UP:
//mode = Mode.DRAG;
break;
case MotionEvent.ACTION_UP:
x2 = motionEvent.getX();
y2 = motionEvent.getY();
// System.out.println("TOUCH UP : X:" + x2 + " Y:" + y2);
mode = Mode.NONE;
prevDx = dx;
prevDy = dy;
if (x1 == x2 && y1 == y2 && ApocketApp.mViewClicked != null) {
Utilities.sysOut("-------------In ZoomLayout");
if (ApocketApp.mViewClicked.getTag().toString().contains("A"))
apiListener.onSuccess("onAvatarClick");
else
apiListener.onSuccess("onBuildingClick");
}
break;
}
scaleDetector.onTouchEvent(motionEvent);
if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {
getParent().requestDisallowInterceptTouchEvent(true);
float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale;
float maxDy = (child().getHeight() - (child().getHeight() / scale)) / 2 * scale;
dx = Math.min(Math.max(dx, -maxDx), maxDx);
dy = Math.min(Math.max(dy, -maxDy), maxDy);
/*Log.i(TAG, "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx
+ ", max " + maxDx);*/
applyScaleAndTranslation();
}
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleDetector) {
// Log.i(TAG, "onScaleBegin");
// setLayerType(View.LAYER_TYPE_HARDWARE, null);
return true;
}
@Override
public boolean onScale(ScaleGestureDetector scaleDetector) {
float scaleFactor = scaleDetector.getScaleFactor();
//Log.i(TAG, "onScale" + scaleFactor);
if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) {
scale *= scaleFactor;
scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
lastScaleFactor = scaleFactor;
} else {
lastScaleFactor = 0;
}
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleDetector) {
//Log.i(TAG, "onScaleEnd");
// setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
private void applyScaleAndTranslation() {
child().setScaleX(scale);
child().setScaleY(scale);
child().setTranslationX(dx);
child().setTranslationY(dy);
}
private View child() {
return getChildAt(0);
}
public void animateToCentre(final RelativeLayout relativeLayout){
Resources res = mContext.getResources();
TypedValue outValue = new TypedValue();
res.getValue(R.dimen.zoom_centre_level_max, outValue, true);
final float zoomEnd = outValue.getFloat();
ObjectAnimator oaX = new ObjectAnimator();
oaX.setDuration(res.getInteger(R.integer.zoom_centre_duration));
oaX.setFloatValues(new float[]{1.0f, zoomEnd});
oaX.setPropertyName("scaleX");
oaX.setFrameDelay(10);
ObjectAnimator oaY = new ObjectAnimator();
oaY.setDuration(res.getInteger(R.integer.zoom_centre_duration));
oaY.setFloatValues(new float[]{1.0f, zoomEnd});
oaY.setPropertyName("scaleY");
oaY.setFrameDelay(10);
ObjectAnimator oaTy = new ObjectAnimator();
oaTy.setDuration(res.getInteger(R.integer.zoom_centre_duration));
oaTy.setFloatValues(new float[]{0.0f, res.getDimension(R.dimen.v_5) * 3});
oaTy.setPropertyName("translationY");
oaTy.setFrameDelay(10);
AnimatorSet zoomAnimation = new AnimatorSet();
zoomAnimation.playTogether(new ObjectAnimator[]{oaX, oaY, oaTy});
//AnimatorSet zoomAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(mContext, R.anim.zoom_in_out);
zoomAnimation.setTarget(child());
zoomAnimation.setInterpolator(new FastOutLinearInInterpolator());
zoomAnimation.start();
zoomAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
@Override
public void onAnimationEnd(Animator animation) {
//setLayerType(View.LAYER_TYPE_HARDWARE, null);
scale = zoomEnd;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
}
在hdpi或xhdpi设备上缩放工作正常,但它落后于xxhdpi和xxxhdpi devices.Hi尝试在清单中使用HardwareAccelaration = true,但没有太大区别。 所以请任何机构建议一些方法来解决这个问题。 提前致谢。