このコードでタッチイベントのImageViewを移動しようとしました:
public class ScrollableImageView extends ImageView {
private GestureDetectorCompat gestureDetectorCompat;
public ScrollableImageView(Context context) {
this(context, null);
}
public ScrollableImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScrollableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setScaleType(ScaleType.MATRIX);
gestureDetectorCompat = new GestureDetectorCompat(context,
new MySimpleOnGestureListener(this));
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
gestureDetectorCompat.onTouchEvent(event);
return true;
}
public void scroll(float distance) {
Matrix imageMatrix = getImageMatrix();
imageMatrix.postTranslate(distance, 0);
setImageMatrix(imageMatrix);
invalidate();
}
private static class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
private ScrollableImageView scrollableImageView;
public MySimpleOnGestureListener(ScrollableImageView scrollableImageView) {
this.scrollableImageView = scrollableImageView;
}
@Override
public boolean onDown(MotionEvent e) {
Utils.log("onDown");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
scrollableImageView.scroll(-distanceX);
return true;
}
}
}
最初は、すべてがNexus 5(Android 4.4.4およびLollipop)でうまく機能していました。しかし、4.0.4(Galaxy S2)やNexus S(4.1.1)などの古いバージョンのAndroidを試してみましたが、どれも機能しませんでした。
それからしばらく苦労した後、私はこの解決策を思いつきました、そしてそれはすべてのデバイスでうまくいきました:
(現在、ImageViewのgetImageMatrix()を介して取得するのではなく、ローカルオブジェクトによってImageViewのマトリックスオブジェクトを追跡していることに注意してください)
public class ScrollableImageView extends ImageView {
private GestureDetectorCompat gestureDetectorCompat;
private Matrix imageMatrix;
public ScrollableImageView(Context context) {
this(context, null);
}
public ScrollableImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScrollableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setScaleType(ScaleType.MATRIX);
imageMatrix = new Matrix();
gestureDetectorCompat = new GestureDetectorCompat(context,
new MySimpleOnGestureListener(this));
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
gestureDetectorCompat.onTouchEvent(event);
return true;
}
public void scroll(float distance) {
imageMatrix.postTranslate(distance, 0);
setImageMatrix(imageMatrix);
invalidate();
}
private static class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
private ScrollableImageView scrollableImageView;
public MySimpleOnGestureListener(ScrollableImageView scrollableImageView) {
this.scrollableImageView = scrollableImageView;
}
@Override
public boolean onDown(MotionEvent e) {
Utils.log("onDown");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
scrollableImageView.scroll(-distanceX);
return true;
}
}
}
私は解決策を手に入れましたが、以前のコードが機能しなかった理由をまだ理解できませんでしたか?!
私は調査しようとしましたが、理にかなっているのはImageViewのgetImageMatrix()のドキュメントだけでした。
ビューのオプションのマトリックスを返します。これは、ビューが描画されるときにビューのドローアブルに適用されます。行列がない場合、このメソッドは単位行列を返します。このマトリックスをその場で変更せずに、コピーを作成してください。ドローアブルに別のマトリックスを適用する場合は、必ずsetImageMatrix()を呼び出してください。
それから、それは私をもっと混乱させましたDo not change this matrix in place but make a copy
、そうすることのポイントは何ですか?以前のコードで行ったようにできないのはなぜですか?(ImageViewの現在のマトリックスを取得してから変換を適用し、ドキュメントに記載されているようにsetImageMatrix()を介して元に戻します)
誰かが私にいくつかの光を当ててください、これは私にとってあまりにも多くの混乱です。
わかった、みんな、わかった!
実際、ドキュメントは理にかなっています。
ビューのオプションのマトリックスを返します。これは、ビューが描画されるときにビューのドローアブルに適用されます。行列がない場合、このメソッドは単位行列を返します。このマトリックスをその場で変更せずに、コピーを作成してください。ドローアブルに別のマトリックスを適用する場合は、必ずsetImageMatrix()を呼び出してください。
ics_mr1のImageViewソースコードにこのコードがあるため:
public void setImageMatrix(Matrix matrix) {
// collaps null and identity to just null
if (matrix != null && matrix.isIdentity()) {
matrix = null;
}
// don't invalidate unless we're actually changing our matrix
if (matrix == null && !mMatrix.isIdentity() ||
matrix != null && !mMatrix.equals(matrix)) {
mMatrix.set(matrix);
configureBounds();
invalidate();
}
}
だから私が好きなら:
Matrix imageMatrix = getImageMatrix();
imageMatrix.postTranslate(distance, 0);
setImageMatrix(imageMatrix);
matrix != null && !mMatrix.equals(matrix)
なりますfalse
私は(ドキュメントが言った理由のがいるのと同じMatrixオブジェクトを再利用するためDo not change this matrix in place but make a copy
の条件のいずれも満たしていないため)、その後、何も起こらないだろう。
それから今、私ははるかにエレガントな解決策を思いつきます:
Matrix imageMatrix = new Matrix(getImageMatrix());
imageMatrix.postTranslate(distance, 0);
setImageMatrix(imageMatrix);
それは
YIKESです
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加