アプリに静止画像を表示する必要がある場合は、Drawable
クラスとそのサブクラスを使用して図形や画像を描画できます。Drawable
は、描画可能なものの一般的な抽象化です。各種のサブクラスは特定の画像シナリオに役立ちます。また、サブクラスを拡張して、独自の動作をする独自のドローアブル オブジェクトを定義することもできます。
クラス コンストラクタを使用する以外に、Drawable
を定義しインスタンス化する方法には次の 2 つがあります。
- プロジェクトに保存されている画像リソース(ビットマップ ファイル)をインフレートする。
- ドローアブル プロパティを定義する XML リソースをインフレートする。
注: 代わりにベクター型ドローアブルを使用することをおすすめします。ベクター型ドローアブルを使用すると、関連する色情報とともに点、線、曲線のセットで画像を定義できます。これにより、品質を損なうことなく、ベクター型ドローアブルをさまざまなサイズにスケーリングできます。詳細については、ベクター型ドローアブルの概要をご覧ください。
リソースの画像からドローアブルを作成する
アプリにグラフィックを追加するには、プロジェクト リソースから画像ファイルを参照します。サポートされているファイル形式は、PNG(推奨)、JPG(使用可能)、GIF(非推奨)です。アプリのアイコン、ロゴ、その他のグラフィック(ゲームで使用されるものなど)は、この手法に適しています。
イメージ リソースを使用するには、プロジェクトの res/drawable/
ディレクトリにファイルを追加します。プロジェクトに入ると、コードまたは XML レイアウトから画像リソースを参照できます。いずれの場合も、リソース 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 でオブジェクトを定義することを検討してください。
XML で Drawable
を定義したら、ファイルをプロジェクトの 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" />
android.graphics.drawable
パッケージに含まれる他の多くのドローアブル タイプと同様に、ShapeDrawable
クラスでは、パブリック メソッドを使用してオブジェクトのさまざまなプロパティを定義できます。調整可能なプロパティの例として、アルファ透明度、カラーフィルタ、ディザ、不透明度、色などがあります。
XML リソースを使用して基本的なドローアブル図形を定義することもできます。詳細については、 ドローアブルのリソースタイプの シェイプ ドローアブルをご覧ください。
NinePatch ドローアブル
NinePatchDrawable
グラフィックは、ビューの背景として使用できる伸縮可能なビットマップ画像です。Android は、ビューのコンテンツに合わせてグラフィックのサイズを自動的に変更します。NinePatch 画像の使用例は、標準の Android ボタンで使用される背景です。ボタンは、さまざまな長さの文字列に合わせて拡大する必要があります。NinePatch グラフィックは、1 ピクセルの枠線が追加された標準の PNG 画像です。これは、9.png
拡張機能を使用して、プロジェクトの res/drawable/
ディレクトリに保存する必要があります。
枠線を使用して、画像の伸縮可能領域と静的領域を定義します。 伸縮可能セクションを指定するには、枠線の左側と上部に幅 1 ピクセルの黒い線を 1 本以上描画します(他の境界ピクセルは完全に透明または白にする必要があります)。伸縮可能セクションは必要な数だけ作成できます。伸縮可能セクションの相対サイズは変わらないため、最大セクションは常に最大のままです。
右側に線を、下部に線を描画することで、画像のオプションのドローアブル セクション(実際にはパディング ライン)を定義することもできます。View
オブジェクトが背景として NinePatch グラフィックを設定し、ビューのテキストを指定すると、すべてのテキストが右と下の線(含まれている場合)で指定された領域のみを占めるように拡大されます。パディング ラインが含まれていない場合、Android は左と上の線を使用してこのドローアブル領域を定義します。
線の違いを明確にするために、左と上の線は、画像を引き伸ばすために複製できる画像のピクセルを定義します。下と右の線は、ビューのコンテンツが占有できる画像内の相対領域を定義します。
図 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 つのボタンを示しています。ボタンの幅と高さはテキストによって異なり、背景画像はそれに合わせて拡大されます。
カスタム ドローアブル
カスタムの図形描画を作成する場合は、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
を使用し、クラス属性から完全修飾クラス名を指定する。この方法は、パブリック トップレベル クラスとパブリック静的内部クラスの両方に使用できます。<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 を使用した色の選択をご覧ください。