アプリで静止画像を表示する必要がある場合は、Drawable
クラスとそのサブクラスを使用して、図形や画像を描画できます。Drawable
は、描画可能なものの一般的な抽象化です。さまざまなサブクラスが特定の画像シナリオに役立ち、それらを拡張して、独自の動作をする独自のドローアブル オブジェクトを定義できます。
クラス コンストラクタを使用する以外に、Drawable
を定義しインスタンス化する方法には次の 2 つがあります。
- プロジェクトに保存されている画像リソース(ビットマップ ファイル)をインフレートする。
- ドローアブル プロパティを定義する XML リソースをインフレートする。
注: 代わりにベクター型ドローアブルを使用することをおすすめします。ベクター型ドローアブルでは、点、線、曲線のセットと関連する色情報を使用して画像を定義します。これにより、品質を損なうことなく、ベクター型ドローアブルをさまざまなサイズにスケーリングできます。詳しくは、ベクター型ドローアブルの概要をご覧ください。
リソースの画像からドローアブルを作成する
プロジェクト リソースの画像ファイルを参照して、アプリにグラフィックを追加できます。サポートされているファイル形式は、PNG(推奨)、JPG(使用可能)、GIF(非推奨)です。アプリアイコン、ロゴ、その他のグラフィック(ゲームで使用されるもの)は、この手法に適しています。
画像リソースを使用するには、プロジェクトの res/drawable/
ディレクトリにファイルを追加します。プロジェクトに追加されたら、コードまたは XML レイアウトから画像リソースを参照できます。いずれの場合も、リソース ID を使用して参照されます。リソース ID は、ファイル形式の拡張子を除いたファイル名です。たとえば、my_image.png
は my_image
と表します。
注: res/drawable/
ディレクトリに配置された画像リソースは、ビルドプロセス中に aapt
ツールによって可逆画像圧縮で自動的に最適化されます。たとえば、256 色を超える色を必要としないトゥルーカラーの PNG を、カラーパレットを使用する 8 ビットの PNG に変換できます。これにより、画質を変えずにメモリ使用量を削減できます。そのため、このディレクトリに配置されたイメージバイナリはビルド時に変更される可能性があります。画像をビットマップに変換するためにビットストリームとして読み取る場合は、代わりに画像を res/raw/
フォルダに保存し、aapt
ツールで変更しないようにします。
次のコード スニペットは、ドローアブル リソースから作成された画像を使用してレイアウトに追加する ImageView
の作成方法を示しています。
Kotlin
private lateinit var constraintLayout: ConstraintLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Instantiate an ImageView and define its properties val i = ImageView(this).apply { setImageResource(R.drawable.my_image) contentDescription = resources.getString(R.string.my_image_desc) // set the ImageView bounds to match the Drawable's dimensions adjustViewBounds = true layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) } // Create a ConstraintLayout in which to add the ImageView constraintLayout = ConstraintLayout(this).apply { // Add the ImageView to the layout. addView(i) } // Set the layout as the content view. setContentView(constraintLayout) }
Java
ConstraintLayout constraintLayout; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create a ConstraintLayout in which to add the ImageView constraintLayout = new ConstraintLayout(this); // Instantiate an ImageView and define its properties ImageView i = new ImageView(this); i.setImageResource(R.drawable.my_image); i.setContentDescription(getResources().getString(R.string.my_image_desc)); // set the ImageView bounds to match the Drawable's dimensions i.setAdjustViewBounds(true); i.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); // Add the ImageView to the layout and set the layout as the content view. constraintLayout.addView(i); setContentView(constraintLayout); }
また、次の例に示すように、画像リソースを Drawable
オブジェクトとして処理することもできます。
Kotlin
val myImage: Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)
Java
Resources res = context.getResources(); Drawable myImage = ResourcesCompat.getDrawable(res, R.drawable.my_image, null);
警告: プロジェクト内の一意の各リソースは、インスタンス化するオブジェクトの数に関係なく、1 つの状態のみを維持できます。たとえば、同じ画像リソースから 2 つの Drawable
オブジェクトをインスタンス化し、一方のオブジェクトのプロパティ(アルファなど)を変更すると、他方にも影響します。画像リソースの複数のインスタンスを処理する場合は、Drawable
オブジェクトを直接変換するのではなく、トゥイーン アニメーションを実行する必要があります。
次の XML スニペットは、XML レイアウトの ImageView
にドローアブル リソースを追加する方法を示しています。
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/my_image" android:contentDescription="@string/my_image_desc" />
プロジェクト リソースの使用方法の詳細については、リソースとアセットをご覧ください。
注: 画像リソースをドローアブルのソースとして使用する場合は、さまざまなピクセル密度に適した画像サイズであることを確認してください。画像が正しくない場合、収まるように拡大されます。これにより、ドローアブルがアーティファクトになる可能性があります。詳しくは、各種のピクセル密度をサポートするをご覧ください。
XML リソースからドローアブルを作成する
最初はコードやユーザー操作によって定義された変数に依存しない、作成する Drawable
オブジェクトがある場合、XML で Drawable
を定義することをおすすめします。ユーザーによるアプリの操作中に Drawable
がそのプロパティを変更することが予想される場合でも、XML でオブジェクトを定義することを検討する必要があります。オブジェクトをインスタンス化した後にプロパティを変更できるためです。
Drawable
を XML で定義したら、プロジェクトの res/drawable/
ディレクトリにファイルを保存します。次の例は、Drawable
を継承する TransitionDrawable
リソースを定義する XML を示しています。
<!-- res/drawable/expand_collapse.xml --> <transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/image_expand"/> <item android:drawable="@drawable/image_collapse"/> </transition>
次に、Resources#getDrawable()
を呼び出して XML ファイルのリソース ID を渡すことで、オブジェクトを取得してインスタンス化します。inflate()
メソッドをサポートするすべての Drawable
サブクラスを XML で定義して、アプリでインスタンス化できます。
XML インフレーションをサポートする各ドローアブル クラスは、オブジェクト プロパティの定義に役立つ特定の XML 属性を利用します。次のコードは、TransitionDrawable
をインスタンス化し、ImageView
オブジェクトのコンテンツとして設定します。
Kotlin
val transition= ResourcesCompat.getDrawable( context.resources, R.drawable.expand_collapse, null ) as TransitionDrawable val image: ImageView = findViewById(R.id.toggle_image) image.setImageDrawable(transition) // Description of the initial state that the drawable represents. image.contentDescription = resources.getString(R.string.collapsed) // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000) // After the transition is complete, change the image's content description // to reflect the new state.
Java
Resources res = context.getResources(); TransitionDrawable transition = (TransitionDrawable) ResourcesCompat.getDrawable(res, R.drawable.expand_collapse, null); ImageView image = (ImageView) findViewById(R.id.toggle_image); image.setImageDrawable(transition); // Description of the initial state that the drawable represents. image.setContentDescription(getResources().getString(R.string.collapsed)); // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000); // After the transition is complete, change the image's content description // to reflect the new state.
サポートされている XML 属性の詳細については、上記のクラスをご覧ください。
シェイプ ドローアブル
ShapeDrawable
オブジェクトは、2 次元のグラフィックを動的に描画する場合に適しています。プログラムで ShapeDrawable
オブジェクトにプリミティブ シェイプを描画し、アプリに必要なスタイルを適用できます。
ShapeDrawable
は Drawable
のサブクラスです。このため、Drawable
が想定される場所であればどこでも ShapeDrawable
を使用できます。たとえば、ShapeDrawable
オブジェクトを使用してビューの setBackgroundDrawable()
メソッドに渡すことで、ビューの背景を設定できます。シェイプを独自のカスタムビューとして描画し、アプリのレイアウトに追加することもできます。
ShapeDrawable
には独自の draw()
メソッドがあるため、次のコードサンプルに示すように、onDraw()
イベント中に ShapeDrawable
オブジェクトを描画する View
のサブクラスを作成できます。
Kotlin
class CustomDrawableView(context: Context) : View(context) { private val drawable: ShapeDrawable = run { val x = 10 val y = 10 val width = 300 val height = 50 contentDescription = context.resources.getString(R.string.my_view_desc) ShapeDrawable(OvalShape()).apply { // If the color isn't set, the shape uses black as the default. paint.color = 0xff74AC23.toInt() // If the bounds aren't set, the shape can't be drawn. setBounds(x, y, x + width, y + height) } } override fun onDraw(canvas: Canvas) { drawable.draw(canvas) } }
Java
public class CustomDrawableView extends View { private ShapeDrawable drawable; public CustomDrawableView(Context context) { super(context); int x = 10; int y = 10; int width = 300; int height = 50; setContentDescription(context.getResources().getString( R.string.my_view_desc)); drawable = new ShapeDrawable(new OvalShape()); // If the color isn't set, the shape uses black as the default. drawable.getPaint().setColor(0xff74AC23); // If the bounds aren't set, the shape can't be drawn. drawable.setBounds(x, y, x + width, y + height); } protected void onDraw(Canvas canvas) { drawable.draw(canvas); } }
上記のコードサンプルの CustomDrawableView
クラスは、他のカスタムビューと同様に使用できます。たとえば、次の例に示すように、プログラムでアプリのアクティビティに追加できます。
Kotlin
private lateinit var customDrawableView: CustomDrawableView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) customDrawableView = CustomDrawableView(this) setContentView(customDrawableView) }
Java
CustomDrawableView customDrawableView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); customDrawableView = new CustomDrawableView(this); setContentView(customDrawableView); }
代わりに XML レイアウトでカスタムビューを使用する場合は、CustomDrawableView
クラスで View(Context, AttributeSet)
コンストラクタをオーバーライドする必要があります。このコンストラクタは、クラスが XML からインフレートされたときに呼び出されます。次の例は、XML レイアウト内で CustomDrawableView
を宣言する方法を示しています。
<com.example.shapedrawable.CustomDrawableView android:layout_width="fill_parent" android:layout_height="wrap_content" />
ShapeDrawable
クラスでは、android.graphics.drawable
パッケージの他の多くのドローアブル タイプと同様に、パブリック メソッドを使用してオブジェクトのさまざまなプロパティを定義できます。調整するプロパティの例としては、アルファ透明度、カラーフィルタ、ディザ、不透明度、色などがあります。
XML リソースを使用して基本的なドローアブル図形を定義することもできます。詳しくは、 ドローアブル リソースタイプの シェイプ ドローアブルをご覧ください。
NinePatch ドローアブル
NinePatchDrawable
グラフィックは、ビューの背景として使用できる伸縮可能なビットマップ画像です。Android は、ビューのコンテンツに合わせてグラフィックのサイズを自動的に変更します。NinePatch 画像の使用例として、標準の Android ボタンで使用される背景があります。ボタンは、さまざまな長さの文字列に対応できるように伸縮させる必要があります。NinePatch グラフィックは、1 ピクセルの枠線を含む標準 PNG 画像です。これは、プロジェクトの res/drawable/
ディレクトリに 9.png
拡張子を付けて保存する必要があります。
枠線を使用して、画像の拡大可能な領域と静的な領域を定義します。枠線の左側と上部に 1 ピクセル幅の黒い線(複数可)を描画して、伸縮可能領域を指定します(他の枠線ピクセルは完全に透明または白にする必要があります)。伸縮可能なセクションは必要な数だけ設定できます。伸縮可能なセクションの相対的なサイズは同じままであるため、最大のセクションが常に最大のままです。
右側に線を、下部に線を描画して、画像のオプションのドローアブル セクション(実質的にはパディング線)を定義することもできます。View
オブジェクトが NinePatch グラフィックを背景として設定してからビューのテキストを指定すると、すべてのテキストが右側の線と下の線(含まれる場合)で指定された領域のみを占有するようにオブジェクトが拡大されます。パディング ラインが含まれていない場合、Android は左と上のラインを使用してこのドローアブル領域を定義します。
線の違いを明確にするために、左と上の線は、画像を引き伸ばすために複製できる画像のピクセルを定義します。下と右の線は、ビューのコンテンツが占有できる画像内の相対的な領域を定義します。
図 1 は、ボタンの定義に使用する NinePatch グラフィックの例を示しています。
![伸縮可能領域とパディング ボックスの画像](https://developer.android.google.cn/static/images/ninepatch_raw.png?authuser=7&hl=ja)
図 1: ボタンを定義する NinePatch グラフィックの例
この NinePatch グラフィックは、左と上の線で 1 つの伸縮可能領域を定義し、下と右の線でドローアブル領域を定義しています。上の画像でグレーの点線は、イメージを引き伸ばすために複製されたイメージの領域を示しています。下の画像のピンク色の長方形は、ビューのコンテンツが許可される領域を示します。コンテンツがこの領域に収まらない場合は、収まるように画像が引き伸ばされます。
Draw 9-patch ツールを使用すると、WYSIWYG グラフィック エディタを使用して NinePatch 画像を簡単に作成できます。さらに、伸縮可能領域に定義した領域が、ピクセル レプリケーションの結果として描画アーティファクトを生成するリスクがある場合、警告を表示します。
次のサンプル レイアウト XML は、いくつかのボタンに NinePatch グラフィックを追加する方法を示しています。NinePatch 画像は res/drawable/my_button_background.9.png
に保存されます。
<Button android: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 android: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_content
に設定して、ボタンがテキストの周囲にきちんと収まるようにしています。
図 2 は、上記の XML と NinePatch の画像からレンダリングされた 2 つのボタンを示しています。ボタンの幅と高さがテキストに応じて異なり、それに合わせて背景画像が引き伸ばされます。
![小型と標準サイズのボタンの画像](https://developer.android.google.cn/static/images/ninepatch_examples.png?authuser=7&hl=ja)
図 2: XML リソースと NinePatch グラフィックを使用してレンダリングされたボタン
カスタム ドローアブル
カスタムの図形描画を作成する場合は、Drawable
クラス(またはそのサブクラス)を拡張します。
実装する最も重要なメソッドは draw(Canvas)
です。これは、描画命令を提供するために使用する必要がある Canvas
オブジェクトを提供するためです。
次のコードは、円を描画する Drawable
のシンプルなサブクラスを示しています。
Kotlin
class MyDrawable : Drawable() { private val redPaint: Paint = Paint().apply { setARGB(255, 255, 0, 0) } override fun draw(canvas: Canvas) { // Get the drawable's bounds val width: Int = bounds.width() val height: Int = bounds.height() val radius: Float = Math.min(width, height).toFloat() / 2f // Draw a red circle in the center canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, redPaint) } override fun setAlpha(alpha: Int) { // This method is required } override fun setColorFilter(colorFilter: ColorFilter?) { // This method is required } override fun getOpacity(): Int = // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE PixelFormat.OPAQUE }
Java
public class MyDrawable extends Drawable { private final Paint redPaint; public MyDrawable() { // Set up color and text size redPaint = new Paint(); redPaint.setARGB(255, 255, 0, 0); } @Override public void draw(Canvas canvas) { // Get the drawable's bounds int width = getBounds().width(); int height = getBounds().height(); float radius = Math.min(width, height) / 2; // Draw a red circle in the center canvas.drawCircle(width/2, height/2, radius, redPaint); } @Override public void setAlpha(int alpha) { // This method is required } @Override public void setColorFilter(ColorFilter colorFilter) { // This method is required } @Override public int getOpacity() { // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE return PixelFormat.OPAQUE; } }
続いて、以下に示すように、ドローアブルを ImageView
内など、任意の場所に追加できます。
Kotlin
val myDrawing = MyDrawable() val image: ImageView = findViewById(R.id.imageView) image.setImageDrawable(myDrawing) image.contentDescription = resources.getString(R.string.my_image_desc)
Java
MyDrawable mydrawing = new MyDrawable(); ImageView image = findViewById(R.id.imageView); image.setImageDrawable(mydrawing); image.setContentDescription(getResources().getString(R.string.my_image_desc));
Android 7.0(API レベル 24)以降では、次の方法で XML を使用してカスタム ドローアブルのインスタンスを定義することもできます。
- XML 要素名として完全修飾クラス名を使用する。この方法の場合、カスタム ドローアブル クラスはパブリック トップレベル クラスにする必要があります。
<com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android" android:color="#ffff0000" />
- XML タグ名として
drawable
を使用し、class 属性から完全修飾クラス名を指定する。この方法は、パブリック トップレベル クラスとパブリック静的内部クラスの両方に使用できます。<drawable xmlns:android="http://schemas.android.com/apk/res/android" class="com.myapp.MyTopLevelClass$MyDrawable" android:color="#ffff0000" />
ドローアブルに色合いを追加する
Android 5.0(API レベル 21)以降では、アルファマスクとして定義されたビットマップと 9-patch の色合いを調整できます。カラーリソースまたはカラーリソースに解決されるテーマ属性(?android:attr/colorPrimary
など)で色合いを調整できます。通常、これらのアセットは 1 回だけ作成し、テーマに合わせて自動的に色を付けます。
setTint()
メソッドを使用して、BitmapDrawable
、NinePatchDrawable
、VectorDrawable
のオブジェクトに色合いを適用できます。android:tint
属性と android:tintMode
属性を使用して、レイアウトの色とモードを設定することもできます。
画像から代表色を抽出する
Android サポート ライブラリには、画像から代表色を抽出できる Palette
クラスが含まれています。ドローアブルを Bitmap
として読み込み、Palette
に渡してその色にアクセスできます。詳しくは、Palette API を使用した色の選択をご覧ください。