ビュークラスを作成する

Compose を試す
Jetpack Compose は Android で推奨される UI ツールキットです。Compose でレイアウトを操作する方法を学習します。

優れたデザインのカスタムビューは、他の優れたデザインのクラスと同様です。特定の機能セットをシンプルなインターフェースでカプセル化し、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 つのカスタム属性(showTextlabelPosition)を宣言しています。スタイル設定可能なエンティティの名前は通常、カスタムビューを定義するクラスの名前と同じにします。この規則に従う必要はありませんが、多くの一般的なコードエディタでは、この命名規則を使用してステートメントを補完しています。

定義したカスタム属性は、組み込み属性と同様にレイアウト 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 から直接値を読み取ることもできますが、それにはいくつかのデメリットがあります。

  • 属性値内のリソース参照は解決されません。
  • スタイルは適用されません。

代わりに、AttributeSetobtainStyledAttributes() に渡します。このメソッドは、すでに逆参照とスタイルが設定された値の 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 オブジェクトは共有リソースであり、使用後にリサイクルする必要があります。

プロパティとイベントを追加する

属性はビューの動作と外観を制御する強力な方法ですが、属性を読み取ることができるのはビューの初期化時のみです。動的な動作を実現するには、カスタム属性ごとにプロパティ ゲッターとセッターのペアを公開します。次のスニペットは、PieChartshowText というプロパティを公開する方法を示しています。

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();
}

setShowTextinvalidate()requestLayout() を呼び出すことに注意してください。これらの呼び出しは、ビューが確実に動作することを保証するために不可欠です。プロパティに変更が加えられて外観が変わる可能性がある場合は、ビューを再描画する必要があることをシステムが認識できるように、ビューを無効にする必要があります。同様に、プロパティが変更され、ビューのサイズや形状に影響する可能性がある場合は、新しいレイアウトをリクエストする必要があります。これらのメソッド呼び出しを忘れると、見つけにくいバグが発生する可能性があります。

カスタムビューは、重要なイベントを伝えるイベント リスナーもサポートする必要があります。たとえば、PieChartOnCurrentItemChanged というカスタム イベントを公開し、ユーザーが円グラフを回転させて新しいスライスにフォーカスしたことをリスナーに通知します。

特に、カスタムビューのユーザーが 1 人だけの場合は、プロパティとイベントの公開を忘れがちです。 時間をかけてビューのインターフェースを慎重に定義することで、将来のメンテナンス コストを削減できます。カスタムビューの表示形式や動作に影響するプロパティは常に公開することをおすすめします。

アクセシビリティを考慮した設計

カスタムビューは幅広いユーザーに対応している必要があります。これには、タッチスクリーンを見られない、または使用できない障がいのあるユーザーも含まれます。障がいのあるユーザーをサポートするには、次のようにします。

  • android:contentDescription 属性を使用して入力フィールドにラベルを付けます。
  • 必要に応じて sendAccessibilityEvent() を呼び出して、ユーザー補助イベントを送信します。
  • D-pad やトラックボールなどの代替コントローラをサポートする。

アクセス可能なビューの作成について詳しくは、 アプリのユーザー補助機能を強化するをご覧ください。