For my question I have prepared a very simple test app at Github.
For simplicity I have removed flinging, scroll constraints and edge effects (which actually work well i
Using Matrix
is a really better idea - the code is much more simple and you dont have to prove your math skills ;-), see how Matrix#postTranslate
and Matrix#postScale
methods are used:
class MyView extends View {
private static final String TAG = "MyView";
private final ScaleGestureDetector mScaleDetector;
private final GestureDetector mGestureDetector;
private final Drawable mBoard;
private final float mBoardWidth;
private final float mBoardHeight;
private Matrix mMatrix;
public MyView(Context context) {
this(context, null, 0);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mBoard = ResourcesCompat.getDrawable(context.getResources(), R.drawable.chrome, null);
mBoardWidth = mBoard.getIntrinsicWidth();
mBoardHeight = mBoard.getIntrinsicHeight();
mBoard.setBounds(0, 0, (int) mBoardWidth, (int) mBoardHeight);
mMatrix = new Matrix();
mScaleDetector = new ScaleGestureDetector(context, scaleListener);
mGestureDetector = new GestureDetector(context, listener);
}
ScaleGestureDetector.OnScaleGestureListener scaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector scaleDetector) {
float factor = scaleDetector.getScaleFactor();
mMatrix.postScale(factor, factor, getWidth() / 2f, getHeight() / 2f);
ViewCompat.postInvalidateOnAnimation(MyView.this);
return true;
}
};
GestureDetector.OnGestureListener listener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float dX, float dY) {
mMatrix.postTranslate(-dX, -dY);
ViewCompat.postInvalidateOnAnimation(MyView.this);
return true;
}
};
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
float scale = Math.max(w / mBoardWidth, h / mBoardHeight);
mMatrix.setScale(scale, scale);
mMatrix.postTranslate((w - scale * mBoardWidth) / 2f, (h - scale * mBoardHeight) / 2f);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.concat(mMatrix);
mBoard.draw(canvas);
canvas.restore();
}
@Override
@SuppressLint("ClickableViewAccessibility")
public boolean onTouchEvent(MotionEvent e) {
mGestureDetector.onTouchEvent(e);
mScaleDetector.onTouchEvent(e);
return true;
}
}