優れたデザインのカスタムビューは、他の優れたデザインのクラスと同様です。特定の機能セットをシンプルなインターフェースでカプセル化し、CPU とメモリを効率的に使用します。カスタムビューは、適切に設計されたクラスであるだけでなく、次のことを行う必要があります。
- Android 標準に準拠する。
- Android XML レイアウトと連携する、カスタムのスタイル設定可能な属性を提供します。
- ユーザー補助イベントを送信する。
- 複数の Android プラットフォームと互換性がある
Android フレームワークには、これらの要件をすべて満たすビューの作成に役立つ基本クラスと XML タグのセットが用意されています。このレッスンでは、Android フレームワークを使用してビュークラスのコア機能を作成する方法について説明します。
詳細については、カスタムビュー コンポーネントをご覧ください。
ビューをサブクラス化する
Android フレームワークで定義されているすべてのビュークラスは View
を拡張します。カスタムビューは View
を直接拡張することもできます。また、既存のビュー サブクラス(Button
など)を拡張することで時間を節約することもできます。
Android Studio がビューを操作できるようにするには、少なくとも Context
オブジェクトと AttributeSet
オブジェクトをパラメータとして受け取るコンストラクタを用意する必要があります。このコンストラクタにより、Layout Editor でビューのインスタンスを作成、編集することが可能になります。
Kotlin
class PieChart(context: Context, attrs: AttributeSet) : View(context, attrs)
Java
class PieChart extends View { public PieChart(Context context, AttributeSet attrs) { super(context, attrs); } }
カスタム属性を定義する
組み込みの View
をユーザー インターフェースに追加するには、XML 要素で指定し、要素の属性で外観と動作を制御します。XML を使用して、カスタムビューの追加やスタイル設定を行うこともできます。カスタムビューでこの動作を有効にする手順は次のとおりです。
<declare-styleable>
リソース要素でビューのカスタム属性を定義します。- XML レイアウトで属性の値を指定します。
- 実行時に属性値を取得します。
- 取得した属性値をビューに適用します。
このセクションでは、カスタム属性を定義し、その値を指定する方法について説明します。次のセクションでは、実行時に値を取得して適用する方法について説明します。
カスタム属性を定義するには、プロジェクトに <declare-styleable>
リソースを追加します。これらのリソースは res/values/attrs.xml
ファイル内に配置するのが慣例です。attrs.xml
ファイルの例を次に示します。
<resources> <declare-styleable name="PieChart"> <attr name="showText" format="boolean" /> <attr name="labelPosition" format="enum"> <enum name="left" value="0"/> <enum name="right" value="1"/> </attr> </declare-styleable> </resources>
このコードは、PieChart
という名前のスタイル設定可能なエンティティに属する 2 つのカスタム属性(showText
と labelPosition
)を宣言しています。スタイル設定可能なエンティティの名前は通常、カスタムビューを定義するクラスの名前と同じにします。この規則に従う必要はありませんが、多くの一般的なコードエディタでは、この命名規則を使用してステートメントを補完しています。
定義したカスタム属性は、組み込み属性と同様にレイアウト XML ファイルで使用できます。唯一の違いは、カスタム属性が別の名前空間に属していることです。これらは、http://schemas.android.com/apk/res/android
名前空間ではなく、http://schemas.android.com/apk/res/[your package name]
に属します。たとえば、PieChart
に定義された属性の使用方法は次のとおりです。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto"> <com.example.customviews.charting.PieChart custom:showText="true" custom:labelPosition="left" /> </LinearLayout>
長い名前空間 URI を繰り返す必要がないように、サンプルでは xmlns
ディレクティブが使用されています。このディレクティブは、名前空間 http://schemas.android.com/apk/res/com.example.customviews
にエイリアス custom
を割り当てます。名前空間には任意のエイリアスを選択できます。
カスタムビューをレイアウトに追加する XML タグの名前にご注意ください。これは、カスタムビュー クラスの完全修飾名です。ビュークラスが内部クラスの場合は、さらにビューの外部クラスの名前で修飾します。たとえば、PieChart
クラスには PieView
という内部クラスがあります。このクラスのカスタム属性を使用するには、com.example.customviews.charting.PieChart$PieView
タグを使用します。
カスタム属性を適用する
XML レイアウトからビューが作成されると、XML タグ内のすべての属性がリソース バンドルから読み取られ、AttributeSet
としてビューのコンストラクタに渡されます。AttributeSet
から直接値を読み取ることもできますが、それにはいくつかのデメリットがあります。
- 属性値内のリソース参照は解決されません。
- スタイルは適用されません。
代わりに、AttributeSet
を obtainStyledAttributes()
に渡します。このメソッドは、すでに逆参照とスタイルが設定された値の TypedArray
配列を返します。
Android リソース コンパイラは、obtainStyledAttributes()
の呼び出しを容易にするためにさまざまな処理を行います。res/
ディレクトリ内の <declare-styleable>
リソースごとに、生成された R.java
は属性 ID の配列と、配列内の各属性のインデックスを定義する定数セットの両方を定義します。事前定義された定数を使用して、TypedArray
から属性を読み取ります。PieChart
クラスがその属性を読み取る方法を次に示します。
Kotlin
init { context.theme.obtainStyledAttributes( attrs, R.styleable.PieChart, 0, 0).apply { try { mShowText = getBoolean(R.styleable.PieChart_showText, false) textPos = getInteger(R.styleable.PieChart_labelPosition, 0) } finally { recycle() } } }
Java
public PieChart(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.PieChart, 0, 0); try { mShowText = a.getBoolean(R.styleable.PieChart_showText, false); textPos = a.getInteger(R.styleable.PieChart_labelPosition, 0); } finally { a.recycle(); } }
TypedArray
オブジェクトは共有リソースであり、使用後にリサイクルする必要があります。
プロパティとイベントを追加する
属性はビューの動作と外観を制御する強力な方法ですが、属性を読み取ることができるのはビューの初期化時のみです。動的な動作を実現するには、カスタム属性ごとにプロパティ ゲッターとセッターのペアを公開します。次のスニペットは、PieChart
が showText
というプロパティを公開する方法を示しています。
Kotlin
fun isShowText(): Boolean { return mShowText } fun setShowText(showText: Boolean) { mShowText = showText invalidate() requestLayout() }
Java
public boolean isShowText() { return mShowText; } public void setShowText(boolean showText) { mShowText = showText; invalidate(); requestLayout(); }
setShowText
が invalidate()
と requestLayout()
を呼び出すことに注意してください。これらの呼び出しは、ビューが確実に動作することを保証するために不可欠です。プロパティに変更が加えられて外観が変わる可能性がある場合は、ビューを再描画する必要があることをシステムが認識できるように、ビューを無効にする必要があります。同様に、プロパティが変更され、ビューのサイズや形状に影響する可能性がある場合は、新しいレイアウトをリクエストする必要があります。これらのメソッド呼び出しを忘れると、見つけにくいバグが発生する可能性があります。
カスタムビューは、重要なイベントを伝えるイベント リスナーもサポートする必要があります。たとえば、PieChart
は OnCurrentItemChanged
というカスタム イベントを公開し、ユーザーが円グラフを回転させて新しいスライスにフォーカスしたことをリスナーに通知します。
特に、カスタムビューのユーザーが 1 人だけの場合は、プロパティとイベントの公開を忘れがちです。 時間をかけてビューのインターフェースを慎重に定義することで、将来のメンテナンス コストを削減できます。カスタムビューの表示形式や動作に影響するプロパティは常に公開することをおすすめします。
アクセシビリティを考慮した設計
カスタムビューは幅広いユーザーに対応している必要があります。これには、タッチスクリーンを見られない、または使用できない障がいのあるユーザーも含まれます。障がいのあるユーザーをサポートするには、次のようにします。
android:contentDescription
属性を使用して入力フィールドにラベルを付けます。- 必要に応じて
sendAccessibilityEvent()
を呼び出して、ユーザー補助イベントを送信します。 - D-pad やトラックボールなどの代替コントローラをサポートする。
アクセス可能なビューの作成について詳しくは、 アプリのユーザー補助機能を強化するをご覧ください。