LoginSignup
4
1

More than 5 years have passed since last update.

【ImageView】ScaleTypeを変更したときの内部処理

Last updated at Posted at 2019-02-25

ScaleTypeと表示画像の対応を整理するために作成したサンプルアプリで、ScaleTypeFIT_STARTFIT_XYMATRIXと切り替えたときにFIT_STARTMATRIXのときの画像表示が同じになる現象が発生したので、備忘録を兼ねてその際に調査した内容をまとめました。

ScaleTypeを変更したときの内部処理

ImageView.javaのソースコードはこちらにあります。

まず、ScaleTypeを切り替えるためにsetScaleType()を呼び出します。
引数に指定されたScaleTypemScaleTypeに代入されます。

ImageView.java#LL.827-838
public void setScaleType(ScaleType scaleType) {
  if (scaleType == null) {
    throw new NullPointerException();
  }

  if (mScaleType != scaleType) {
    mScaleType = scaleType;

    requestLayout();
    invalidate();
  }
}

  
このmScaleTypeconfigureBounds()内で分岐条件として使われます。
以下、今回の調査に必要な条件のみを抜粋します。

mScaleType == MATRIXのとき、以下のような処理が行われます。

ImageView#LL.1253-1257
if (mMatrix.isIdentity()) {
  mDrawMatrix = null;
} else {
  mDrawMatrix = mMatrix;
}

mMatrixMatrixの参照を持つ変数です。mDrawMatrixmMatrixの参照を代入するための変数です。この2つの変数によってMatrixによる画像変換を行うか否かを制御しています。
mMatrixが単位行列(変換前後で画像の状態を変化させないMatrix)の場合、mDrawMatrixにnullを代入しています。

mScaleType == FIT_CENTER、FIT_END、FIT_STARTのとき、以下のような処理が行われます。

ImageView#LL.1302-1306
mTempSrc.set(0, 0, dwidth, dheight);
mTempDst.set(0, 0, vwidth, vheight);

mDrawMatrix = mMatrix;
mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));

ネイティブコードを呼び出していたので詳細は確認できなかったのですが、最後のsetRectToRect()によってmScaleTypeに対応したMatrixを計算しているようです。
この処理によってmDrawMatrixの参照先の内容が更新されることがEvaluate Expressionでトレースすることによって分かりました。

mScaleType == FIT_XYのとき、以下のような処理が行われます。
vwidthvheightはそれぞれImageViewの幅と高さです。

ImageView.java#LL.1244-1245
mDrawable.setBounds(0, 0, vwidth, vheight);
mDrawMatrix = null;

  
そして、mDrawMatrixonDraw()内で分岐条件として使われています。
mDrawMatrixがnullでないときのみMatrixによる画像変換が行われます。

ImageView.java#LL.1350-1383
@Override
protected void onDraw(Canvas canvas) {
  ...
  if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
    mDrawable.draw(canvas);
  } else {
    ...
    if (mDrawMatrix != null) {
      canvas.concat(mDrawMatrix);
    }
    mDrawable.draw(canvas);
    canvas.restoreToCount(saveCount);
  }
}

  
以上を踏まえ、改めて状況を整理します。

ScaleTypeFIT_STARTFIT_XYMATRIXと切り替えたとき、

  • FIT_START
    • ②の処理が行われるので、mMatrixの参照先のMatrixの内容はFIT_STARTに対応した値になる
    • mDrawMatrixはnullでないので、Matrixによる画像変換が行われる
  • FIT_XY
    • ③の処理が行われるので、mMatrixの参照先のMatrixの内容はFIT_STARTに対応した値のままになる
    • mDrawMatrixはnullなので、Matrixによる画像変換は行われない
  • MATRIX
    • ①の処理が行われるので、mMatrixの参照先のMatrixの内容はFIT_STARTに対応した値のままになる
    • mDrawMatrixはnullでないので、Matrixによる画像変換が行われる

となるため、FIT_STARTMATRIXのときの画像表示が同じになっていました。

最後に、この現象を回避するためにScaleTypeを変更する前にsetImageMatrix()を呼び出します。

ImageView.java#LL.871-884
public void setImageMatrix(Matrix matrix) {
  // collapse 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();
  }
}

setImageMatrix()の引数に新しい単位行列を代入することでmMatrixが初期化されます。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1