CanvasとDrawable


CanvasとDrawable
        Android                ,       

Androidはあなたのインタフェースをカスタマイズするために絵描きAPIを提供しています.2 Dインタフェースをカスタマイズするには2つの方法があります.1、Layoutでviewを描くには、自分の画像やアニメーションを修正するだけです.2,Canvasで直接描画
Canvasはキャンバスで、ブラシをカスタマイズしてキャンバスに絵を描くことができます.
メソッド2:aでは、UIスレッドの場合、カスタムViewを作成し、invalidate()を呼び出して再描画する必要があります.onDraw()コールバックで図面をカスタマイズします.b、個別のプロセスでは、Canvasを描画するためにSurfaceViewを管理する必要があります(invalidate()を呼び出す必要はありません).
Canvas図面の使用
Canvasで絵を描くと、Canvasは本物のsurfaceを操作するインタフェースのようなものです.Canvasは様々なdrawの方法を提供し、図面を描くのに役立ちます.Canvasはその下のBitmapに描かれています.
どこでCanvasを手に入れることができますか?
  • はonDraw()メソッドで入手できます.このメソッドパラメータはCanvasで、Canvas上で描画できます.
  • またはSurface Viewオブジェクトの操作時にSurface Holderを通過する.lockCanvas()を使用してCanvasを取得します.

  • もちろん、新しいCanvasを再作成することもできます.方法は次のとおりです.
    Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);
    

    Bitmapは必須!!Canvasのすべてのdraw描画動作は、実際の効果を反映するために特定のBitmap画像に描画する必要があります.
    このときCanvasの様々な描画方法を呼び出してBitmap上に描画することができます.(Canvasの新規作成はお勧めしませんが、上記2の方法でCanvasを取得します)
    CanvasクラスにはdrawBitmap(...)、drawRect(...)、drawText(...)などの一連の描画方法があります.他のクラスにもdraw()メソッドがあります.たとえば、以下のDrawableオブジェクトにはdrawメソッドがありますが、Canvasをパラメータとしてdrawメソッドに転送します.
    ビューに描画
    アプリケーションが高速処理を必要としない場合や、将棋ゲームなどの高いフレームレートを必要としない場合.カスタムビューを作成することも考えられます.そして、提供されるCanvas上で、ViewのonDrawメソッドで直接描画します.
    Androidフレームワークは必要に応じてonDrawメソッドを呼び出すだけで、システムにonDrawメソッドを呼び出すにはinvalidate()メソッドを使用します.
    onDrawメソッドでは、Canvasが様々なdrawXXXメソッドを呼び出すと、AndroidシステムはこのCanvasを使用して対応するBitmap上に描画します.
    invalidate()     UI   。   UI   ,  postInvalidate().   

    サンプルコード:
        @Override
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            for (int x = 0; x < mXTileCount; x += 1) {
                for (int y = 0; y < mYTileCount; y += 1) {
                    if (mTileGrid[x][y] > 0) {
                        canvas.drawBitmap(mTileArray[mTileGrid[x][y]], mXOffset + x * mTileSize,
                                mYOffset + y * mTileSize, mPaint);
                    }
                }
            }
    
        }

    このサンプルコードは/samples/スナke/.カスタマイズされたTileView.
    Surface Viewで描画
    Surface ViewはViewのサブクラスであり、Viewレベルで専用のペイントインタフェースを提供し、UI以外のスレッドでペイントできるメリットがあります.非UIスレッドは、Android固有の描画スケジュールに従うことなく、Surface Viewオブジェクトを保持し、その上に描画することができます.
    まず、SurfaceViewのサブクラスを作成し、SurfaceHolderを実装する必要があります.Callbackインタフェース.このインタフェースには、次の方法があります.
    戻りタイプ
    方法
    void
    surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    void
    surfaceCreated(SurfaceHolder holder)
    void
    surfaceDestroyed(SurfaceHolder holder)
    これらのコールバックは、Surface Viewに対応するSurfaceが作成され、変更され、破棄されたときに呼び出されます.
    SurfaceViewクラスでは、描画する別のスレッドクラスを定義できます.
    SurfaceはSurfaceHolderによって操作されるべきであり、SurfaceViewの初期化が終了すると、
    getHolder()

    SurfaceHolderオブジェクトを取得し、SurfaceHolderのaddCallback(this)を呼び出すことによって、このSurfaceViewをSurfaceHolderのコールバックに追加します(urfaceViewがSurfaceHolder.Callbackインタフェースを実装しているため).
    スレッドをSurfaceに描画できるようにするには、Surface Holderをスレッドに渡す必要があります.次に、SurfaceHolderのlockCanvas()からCanvasオブジェクトを取得して描画し、描画が終了したらunlockCanvasAndPost(Canvas canvas)を呼び出してCanvasの描画をSurfaceに適用することができます.
    サンプルコード:
    class LunarView extends SurfaceView implements SurfaceHolder.Callback {
        class LunarThread extends Thread {
                @Override
            public void run() {
            /*   SurfaceHolder lockCanvas()  Canvas  ,      ,       unlockCanvasAndPost(Canvas canvas)   Canvas      Surface  */
                while (mRun) {
                    Canvas c = null;
                    try {
                        c = mSurfaceHolder.lockCanvas(null);
                        synchronized (mSurfaceHolder) {
                            if (mMode == STATE_RUNNING) updatePhysics();
                            doDraw(c);
                        }
                    } finally {
                        // do this in a finally so that if an exception is thrown
                        // during the above, we don't leave the Surface in an
                        // inconsistent state
                        if (c != null) {
                            mSurfaceHolder.unlockCanvasAndPost(c);
                        }
                    }
                }
            }
        }
    ....
    ....
    
        public LunarView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            //  SurfaceHolder     
            SurfaceHolder holder = getHolder();
            holder.addCallback(this);
    
            // create thread only; it's started in surfaceCreated()
            thread = new LunarThread(holder, context, new Handler() {
                @Override
                public void handleMessage(Message m) {
                    mStatusText.setVisibility(m.getData().getInt("viz"));
                    mStatusText.setText(m.getData().getString("text"));
                }
            });
    
            setFocusable(true); // make sure we get key events
        }
    
    ....
    ....
    

    このサンプルコードは/samples/lunarLander/.カスタマイズされたLunarView.
    注意:SurfaceHolderからCanvasを得るたびに、Canvasの前の状態は維持されます.あなたの描画をよりよく表示するために、Surface全体を再描画する必要があります.たとえば、drawColor()を使用してカラーまたはdrawBitmap()を塗りつぶして背景を設定し、Canvasの前の状態をクリアできます.そうでなければ、前のCanvasの内容(重ね合わせ)が表示されます.
    Drawables
    Drawableは私たちがよく使うリソースで、画像でもxml定義の形状でも構いません.Drawableは、BitmapDrawable、ShapeDrawable、PictureDrawable、LayerDrawableなどを含むベースクラスです.これらのクラスを継承して独自のDrawableクラスを定義することもできます.Drawableオブジェクトを定義して初期化するには、3つの方法があります.-エンジニアリングリソースで使用されるピクチャファイル-drawableディレクトリのxml、定義されたDrawableオブジェクトを使用します.-Drawableクラスを使用して作成します.
    リソースピクチャから作成
    画像フォーマットはPNG,JPG,GIFに限定され,アプリケーションアイコン,Logo,ゲームリソースなどに用いられることが多い.画像ファイルはres/drawable/ディレクトリに配置され、コードまたはlayoutファイルで使用できます.注意:res/drawable/ディレクトリの下のピクチャファイルは、パッケージ化時にaaptツールによって自動的に最適化される可能性があります.例えば、256色未満の真色のPNGピクチャが8-bitのPNGピクチャに変換され、メモリを節約することができます(ただし、ピクチャの品質はそれほど悪くありません).コードで画像のデータストリームを取得してBitmapを取得したい場合は、res/rawディレクトリの下に画像を置くことができます.res/rawディレクトリは最適化されません.
    サンプルコード:次のコードは、ピクチャリソースを使用してImageViewを作成し、Layoutに追加する方法を示しています.
      LinearLayout mLinearLayout;
    
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    
      // Create a LinearLayout in which to add the ImageView
      mLinearLayout = new LinearLayout(this);
    
      // Instantiate an ImageView and define its properties
      ImageView i = new ImageView(this);
      i.setImageResource(R.drawable.my_image);
      i.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions
      i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT,
      LayoutParams.WRAP_CONTENT));
    
      // Add the ImageView to the layout and set the layout as the content view
      mLinearLayout.addView(i);
      setContentView(mLinearLayout);
      }
    
    

    Drawableオブジェクトを入手したい場合は、(IntのIDではなく)次のように操作できます.
    Resources res = mContext.getResources();
    Drawable myImage = res.getDrawable(R.drawable.my_image);
    

    xmlファイル:
    <ImageView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:tint="#55ff0000" android:src="@drawable/my_image"/>
    

    注意:このリソースを使用してオブジェクトをインスタンス化しても、プロジェクト内の各リソースは1つの状態しか維持できません.たとえば、1つのピクチャを使用して、2つのDrawableオブジェクトをインスタンス化し、alphaなどのプロパティを変更します.では、この修正は別のDrawableにも影響します.同じリソースを使用する複数のインスタンスを処理したい場合は、Viewアニメーションを使用することを考慮してください.
    XMLリソースファイルを使用したDrawableのカスタマイズ
    Drawableがピクチャでない場合、コードを使用してDrawableリソースを初期化することに対して、XMLを使用する利点は明らかであり、ここでは後述しない.DrawableのXMLファイルはres/drawable/ディレクトリの下にあり、同じようにResourcesを通じて使用できます.getDrawable(resourceID)を使用してDrawableオブジェクトを取得します.inflate()メソッドを実装したDrawableサブクラスはすべてXMLによって定義および初期化でき、DrawableサブクラスはXMLで定義されたプロパティによってDrawableオブジェクトを作成します.
    Drawableサブクラス:
    AnimatedRotateDrawable
    BitmapDrawable
    ClipDrawable
    ColorDrawable
    DrawableContainer
    GradientDrawable
    InsetDrawable
    LayerDrawable
    NinePatchDrawable
    PictureDrawable
    RotateDrawable
    ScaleDrawable
    ScrollBarDrawable
    ShapeDrawable 
    

    TransitionDrawableの例:TransitionDrawableは遷移効果のあるdrawableです.
    継承関係:android.graphics.drawable.Drawable android.graphics.drawable.LayerDrawable android.graphics.drawable.TransitionDrawable xmlファイルを使用して、2つのピクチャを含むTransitionDrawableを定義します.
    XML定義(expand_collapse.xml):
    <transition xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <item android:drawable="@drawable/penguins"/>
        <item android:drawable="@drawable/tulips"/>
    
    </transition>
    

    Javaで使用する:
          Resources res = mContext.getResources();
          TransitionDrawable transition = (TransitionDrawable)
    res.getDrawable(R.drawable.expand_collapse);
          ImageView image = (ImageView) findViewById(R.id.toggle_image);
          image.setImageDrawable(transition);
    

    そして呼び出すことができます
    transition.startTransition(1000);

    で行ないます.効果の例:
    Shape Drawable
    Drawableはその名の通り描くことができ、画像はもちろん描くことができますが、画像のほかに形も描くことができます.-効果は粗いですが.ShapeDrawableはDrawableの拡張ですが、結局Drawableなので、Viewの背景(setBackgroundDrawable()にすることができます.自分のビューをカスタマイズすることもできます.ShapeDrawableには独自のdraw()メソッドがあるので、Viewをカスタマイズするときは、View.onDraw()メソッドで呼び出してこのShapeDrawableを描画します.次のコードは、カスタムViewの例です.
    public class CustomDrawableView extends View {
          private ShapeDrawable mDrawable;
    
          public CustomDrawableView(Context context) {
          super(context);
    
          int x = 10;
          int y = 10;
          int width = 300;
          int height = 50;
    
          mDrawable = new ShapeDrawable(new OvalShape());
          mDrawable.getPaint().setColor(0xff74AC23);//       ,    
          mDrawable.setBounds(x, y, x + width, y + height);//   bound       
          }
    
          protected void onDraw(Canvas canvas) {
          mDrawable.draw(canvas);
          }
          }
    

    コードは楕円形をカスタムビューとして描き、onDrawメソッドでこのDrawableを描きます.
    カスタマイズされたViewが定義されると、コードで直接使用できます.上のカスタマイズされたViewの使用は次のようになります.
        CustomDrawableView mCustomDrawableView;
    
          protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          mCustomDrawableView = new CustomDrawableView(this);
    
          setContentView(mCustomDrawableView);
          }
    

    XMLでも定義できます.
    <com.example.shapedrawable.CustomDrawableView  android:layout_width="fill_parent" android:layout_height="wrap_content" />
    

    カスタムViewの場合は、独自のプロパティをカスタマイズし、XMLでもカスタムViewを定義できます.ここでは余計なことは言わないで、後で1編だけ書きます.
    Nine-patch画像
    Nine-patch画像は9.pngの最後の画像で、一般的にres/drawable/ディレクトリに置かれています.コードの中でNinePatchDrawableオブジェクトです.AndroidではNine-patch画像をViewの背景にすることができます.メリットは、画像が伸びてモザイクにならないことです.Androidが持っているButtonボタンのような典型的なアプリケーションは、ボタンがどんなに大きくても滑らかに見えます.Nine-patchピクチャは、標準的なPNGピクチャに基づいて周辺に画素を1周増やした.
    外輪の多いピクセルは、ピクチャがスケールされたときに、どの領域が引き伸ばされ、どの領域が動かないかを定義するために使用されます.
         :        1                。
         :        1                。(   )
    (    View    9.png     ,   View     ,           ,          ,           )
    

    次の図は典型的な9である.PNGのボタン画像
           

    ただし、1は、上図のグレーポイントで構成された領域が、画像が伸びたときにコピーされた画像を塗りつぶします.2,下の図のピンクの領域が内部のTextに入らない場合、画像が引っ張られます.
    9.PNGの編集
    9.PNGの使用
    仮定9.PNGはres/drawable/my_として保存button_background.9.pngファイルは、この画像のXmlファイルを使用して以下のように定義されています.
    <Button id="@+id/tiny" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerInParent="true" android:text="Tiny" android:textSize="8sp" android:background="@drawable/my_button_background"/>
    
    <Button id="@+id/big" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerInParent="true" android:text="Biiiiiiig text!" android:textSize="30sp" android:background="@drawable/my_button_background"/>
    

    その中でlayout_widthとlayout_heightはwrap_に設定されていますコンテンツが増えるにつれて、画像が自動的に