2の「ImageView様にセットして頂いたMatrxの値を頂戴して保存」と3の「その時点での拡大率を最低拡大率として保存」はこんな感じになります。
1 2 3 4 |
… mState = -1; setState(STATE_NON); mMinScale = getMatrixScale(); … |
で、setStateとgetMatrixScaleの実体は下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
… private final void setState(int state) { if (mState != state) { mState = state; // ImageView様からMatrixを頂戴して値をコピーする mSavedImageMatrix.set(getImageMatrix()); if (!mImageMatrix.equals(mSavedImageMatrix)) { mImageMatrix.set(mSavedImageMatrix); mImageMatrixChanged = true; } } } /** * 保持しているMatrixから拡大率を取得する */ private final float getMatrixScale() { // このメソッド呼び出しでMatrixのキャッシュ(float配列)に必要であれば値をコピーする updateMatrixCache(); // アスペクト比を維持して拡大縮小しているで横方向の拡大率と縦方向の拡大率は同じはずだけど念の為に小さい方を取得する。 final float scale = Math.min(mMatrixCache[Matrix.MSCALE_X], MatrixCache[Matrix.MSCALE_X]); // イメージが設定されてなかったりすると0が返ってくるのでこの時はデフォルト値を返す if (scale <= 0f) { // for prevente disappering or reversing if (DEBUG) Log.w(TAG, "getMatrixScale:scale<=0, set to default"); return DEFAULT_SCALE; } return scale; } /** * Matrixが変更された場合(mImageMatrixChanged=true)にその要素値をキャッシュ用のfloat配列にコピーする */ protected final float[] mMatrixCache = new float[9]; protected boolean updateMatrixCache() { if (mImageMatrixChanged) { mImageMatrix.getValues(mMatrixCache); mImageMatrixChanged = false; return true; } return false; } … |
内容は、ImageView#getImageMatrixを呼び出して取得したImageView内部のMatrixの値をコピー(参照を代入するわけではありません)してmSavedImageMatrixフィールドとmImageMatrixフィールドにセットします。
更に、Matrixの値をfloat型の配列にコピーします。なぜわざわざfloat配列にコピーしておくかと言うと、Matrix内の個別要素に後々頻繁にアクセスすることになるのですが、Matrixの実体がJNIオブジェクトでアクセスのオーバーヘッドが大きいこと、またアクセスの大部分が読み取りのみなので変更を自前で管理可能なことからキャッシュのためにfloat配列にコピーします。
4.の「拡大縮小等を行わない元のイメージの大きさだけを取得して保存」と5.の「後々の移動範囲の制限用のフィールドなども設定」はこんな感じに。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
… final Drawable dr = getDrawable(); if (dr != null) { mImageRect.set(dr.getBounds()); } else { mImageRect.setEmpty(); } // 後々イメージの移動時の制限用の矩形をついでに設定しちゃいます。 final Rect tmp = new Rect(); getDrawingRect(tmp); mLimitRect.set(tmp); mLimitRect.inset(MOVE_LIMIT, MOVE_LIMIT); mLimitSegments[0] = null; … |
そして最後の6.の「ごめんなさいやっぱり自前のMatrixを使いたいです、とImageView様にお願い」はこんな感じ。
1 2 3 4 |
… super.setScaleType(ImageView.ScaleType.MATRIX); super.setImageMatrix(mImageMatrix); … |
ここまでで、イメージの拡大縮小・移動・回転に必要な準備はほぼ全部終了です。あとはタッチ操作に合わせてMatrixを変更してsuper.setImageMatrixを呼び出すだけです。描画に必要なことはみんなImageView様が行ってくれます。
4000字も超えて長くなってきたので今回はここまで。
お疲れ様でした。
と言いつつ、もう一つ。
部分部分のソースを貼り付けているのでわかりにくいのと、最後まで読まないと使えないなんてのはあんまりなので、全体のソースへのリンクを貼っつけておきます(いつ全部書き終えるかわかんないし(^_^;))。
1 2