動的にImageViewのサイズと位置を変更することは、簡単そうに思える。本来なら簡単であらねばならない。しかし、苦労をしたので備忘録として書き留めておく。
静的にサイズを決定するのであれば、xmlにサイズを記載すれば良い。
TextViewやButtonは、その枠の大きさを動的に変更するメソッドが用意されている。そして、また、TextViewやButtonに多くの文字列が代入された場合、TextViewやButtonの枠が自動的に拡張されて、挿入した文字列の全てが表示される。
このような機能がImageViewにも用意されているだろうと期待する。しかし、残念なことに、そのようなものは無い。
ImageViewに描画されている画像を拡大しても、ImageViewの枠は拡大しない。画像を拡大した場合、ImageViewの枠内に収まっている画像は表示される。しかし、枠外に行ってしまった部分の画像は表示されない。
例えば「能」と描いた画像をImageViewに表示していたとしよう。この画像を2倍に拡大した場合、ImageViewには「ム」という画像(能という文字の左上部分)が表示される。「月」や「ヒ」は表示されない。
ImageViewの枠の大きさと、ImageViewに表示される画像の大きさとは、別物であり、各々別々に取り扱わねばならない。むむむ。
では、どのようにして、ImageViewの枠を拡大するのであろうか。
ImageViewを載せたxmlは次のとおりである。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<TextView
android:text="@string/Menu_PieceSize"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
>
</TextView>
<SeekBar
android:id="@+id/SeekBarPieceSize"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</SeekBar>
<TextView
android:id="@+id/TextPieceSize"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
>
</TextView>
<ImageView
android:id="@+id/ImagePieceSize"
android:contentDescription="@string/Menu_PieceSize"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="@drawable/ic_launcher"
android:scaleType="matrix"
>
</ImageView>
</LinearLayout>
次の話題は、画像の拡大・縮小と移動とを同時に行うことである。これはJavaでMatrixを使って実現する。
下記のsample codeは、SeekBarをスライドすれば、その移動量に応じて、ドロイド君が拡大・縮小する。
拡大・縮小は、ImageViewの左上端を起点にして行われる。画像を常に画面の中央に位置付けるために、拡大・縮小の程度に応じて、画像の左上端を上下左右に移動させている。
public class PieceSizeActivity extends Activity
implements
OnSeekBarChangeListener
{
final String TAG = "PieceSizeActivity";
SeekBar sb;
ImageView iv;
final int iMulti = 4;//1倍から4倍までの間で拡大縮小させる。
final int iMaxSeekBar = 30;//1.0から4.0まで31個の目盛がある。
int iImageSize;//ドロイド君の画像の一辺の長さ
int iPieceSize;//利用者が選択した長さ
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.piecesize);
Intent it = getIntent();
//他のActivityからstartActivityForResultメソッドで呼ばれる。
iPieceSize = it.getIntExtra("PieceSize", -1);
if(iPieceSize<100 || iPieceSize>400) iPieceSize = 100;
float f = iPieceSize;//整数から浮動小数点数へ変換する。
f /= 100;//小数点数にする。
TextView tv = (TextView)findViewById(R.id.TextPieceSize);
tv.setText(String.valueOf(f));//小数点数を画面に表示する。
sb = (SeekBar)findViewById(R.id.SeekBarPieceSize);
sb.setMax(iMaxSeekBar);//最大値設定
iPieceSize /= 10;
iPieceSize -= 10;
sb.setProgress(iPieceSize);//現在値設定
sb.setOnSeekBarChangeListener(this);
//ドロイド君の画像サイズを取得する。
Resources r = getResources();
Bitmap b = BitmapFactory.decodeResource(r, R.drawable.ic_launcher);
iImageSize = b.getWidth();
//ImageViewのアドレスを取得
iv = (ImageView)findViewById(R.id.ImagePieceSize);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(iPieceSize>=0){//起動直後に表示する画像の設定
Matrix m = new Matrix();
m = new Matrix();
float f = iPieceSize + 10;
f /= 10;
float fX = iImageSize * f;
fX = (sb.getWidth() - fX) / 2;
m.setTranslate(fX, 0);
m.preScale(f, f);
iv.setImageMatrix(m);
iPieceSize = -1;
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(seekBar==sb && fromUser==true){
Matrix m = new Matrix();
float f = progress + 10;
f /= 10;//倍率としての値に変換する。
float fX = iImageSize * f;
fX = (sb.getWidth() - fX) / 2;//横位置を計算する。
m.setTranslate(fX, 0);//最初に位置を設定する
m.preScale(f, f);//次に拡大倍率を設定する。
iv.setImageMatrix(m);//位置及び倍率を適用する。
TextView tv;
tv = (TextView)findViewById(R.id.TextPieceSize);
tv.setText(String.valueOf(f));//画面に倍率を表示する。
return;
}
}
(以下省略)