MatrixとCanvas
久々のpostです。MatrixとCanvasの動作に関してです。ちょっとチンプンカンプンなところがあったので動作を確認しながらまとめてみました
今回やりたいこと
- Matrix(とHandler)を使用してIconを縦方向に落下するAnimationをさせる
- Canvasを操作し文字列とIconを縦方向に描画する
Matrixを操作しIconを回転させ、画面に沿って落下させるの図
Canvasを操作し文字列、Iconを縦に回転させるの図
MatrixとCanvasで気付いたこと
1. Matrix
-
- Matrixにはpre-concat系、post-concat系、set系のMatrix操作系methodがある
- 引数に指定するx、yは画面に対してのx、yなのでmatrixを90度回転してもx軸、y軸は変わらない
2. Canvas
その他気付いたこと
-
- Viewを入れ替える際はView.INVISIBLEでは駄目でView.GONEを指定する必要がある
- Matrixを使用する際にはscaleType属性にmatrixを指定する必要あり
- Canvas#drawText()で指定する座標位置はtextのbaselineの座標位置
それでは実装です
layout xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/button_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/matrix" /> <Button android:id="@+id/button_2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/canvas" /> <!-- Matrixを使用する際にはscaleType属性にmatrixを指定する必要あり --> <ImageView android:id="@+id/image_1" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="matrix" android:visibility="gone" /> <com.android.practice.matrix.MyImageView android:id="@+id/image_2" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="matrix" android:visibility="gone" /> </LinearLayout>
Activity(Matrixを操作するclass)
package com.android.practice.matrix; import android.app.Activity; import android.graphics.Matrix; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; public class MyMatrixPracticeActivity extends Activity { private static final String TAG = MyMatrixPracticeActivity.class.getSimpleName(); private static boolean DEBUG = true; public static final int UPDATE_VIEW = 1; private ImageView mImage; private Button mButton1; private Button mButton2; private Handler mHandler = new Handler(){ private Matrix mMtrx = new Matrix(); private int mExtraTrans; @Override public void handleMessage(Message msg) { switch(msg.what){ case UPDATE_VIEW: Log.d(TAG, "UPDATE_VIEW mExtraTrans:" + mExtraTrans); mMtrx.reset(); if(mExtraTrans + getResources().getDrawable(R.drawable.icon).getIntrinsicWidth() + mImage.getPaddingBottom() < mImage.getHeight()){ //引数に指定するx、yは画面に対してのx、yなのでmatrixを90度回転してもx軸、y軸は変わらない mMtrx.postTranslate(-mImage.getWidth()/2, -mImage.getHeight()/2); mMtrx.postRotate(90); mMtrx.postTranslate(-mImage.getHeight()/2 + getResources().getDrawable(R.drawable.icon).getIntrinsicHeight(), mImage.getWidth()/2); mMtrx.postTranslate(0, mExtraTrans); mImage.setImageMatrix(mMtrx); mExtraTrans += 5; Message newMsg = obtainMessage(); newMsg.what = UPDATE_VIEW; sendMessage(newMsg); } break; default: super.handleMessage(msg); } } };; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setUpViews(); } @Override protected void onResume() { super.onResume(); } private void setUpViews(){ mButton1 = (Button)findViewById(R.id.button_1); mButton1.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { startAnimation1(); } }); mButton2 = (Button)findViewById(R.id.button_2); mButton2.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { drawMyImageView(); } }); } private void startAnimation1(){ if(mImage != null){ //Viewを入れ替える際はView.INVISIBLEでは駄目でView.GONEを指定する必要がある mImage.setVisibility(View.GONE); } mImage = (ImageView)findViewById(R.id.image_1); mImage.setImageResource(R.drawable.icon); mImage.setVisibility(View.VISIBLE); if(DEBUG){ Log.d(TAG, "startChangingImageView width: " + mImage.getWidth() + " height: " + mImage.getHeight()); Log.d(TAG, "startChangingImageView measuredWidth: " + mImage.getMeasuredWidth() + " measuredHeight: " + mImage.getMeasuredHeight()); } Message msg = mHandler.obtainMessage(); msg.what = UPDATE_VIEW; mHandler.sendMessage(msg); } private void drawMyImageView(){ mHandler.removeMessages(UPDATE_VIEW); if(mImage != null){ //Viewを入れ替える際はView.INVISIBLEでは駄目でView.GONEを指定する必要がある mImage.setVisibility(View.GONE); } mImage = (ImageView)findViewById(R.id.image_2); mImage.setImageResource(R.drawable.icon); mImage.setVisibility(View.VISIBLE); } }
ImageView拡張class(Canvasを操作)
package com.android.practice.matrix; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.widget.ImageView; public class MyImageView extends ImageView { private static final String TAG = MyImageView.class.getSimpleName(); private static final boolean DEBUG = true; private Paint mPaint; public MyImageView(Context context){ super(context); } public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setTextSize(40); mPaint.setARGB(255, 255, 0, 0); } public MyImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { if(DEBUG)Log.d(TAG, "onDraw Width:" + getWidth() + " Height: " + getHeight()); canvas.save(); //Canvas経由のmatrix操作はpreconcatなので、codeの並び順とは逆順に実行される //Canvasのmatrix操作系methodで引数として指定するx、yは画面に対してのx、yなのでmatrixを90度回転してもx軸、y軸は変わらない canvas.translate(-(getHeight() / 2 - getWidth() / 2), getWidth() / 2); canvas.rotate(90); canvas.translate(-getWidth() / 2, -getHeight() / 2); canvas.drawColor(Color.CYAN); //Canvasの描画系methodで引数として指定するx、yはCanvasに対してのx、yなのでmatrixを90度回転するとx軸、y軸も合わせて回転する //Canvas#drawText()で指定する座標位置はtextのbaselineの座標位置 canvas.drawText("This is a text on (0, 0)", 0, 0, mPaint); canvas.drawLine(0, 0, getHeight(), 0, mPaint); canvas.drawText("This is a text on (0, -40)", 0, -40, mPaint); canvas.drawLine(0, -40, getHeight(), -40, mPaint); Drawable drawable = getDrawable(); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); canvas.restore(); } }