カテゴリー
Kotlin言語

ゼロから始めるAndroidアプリ(Kotlin編)Unit2 – 1 第8回 後半:スタイルの設定、リスナーとラムダ式

Android Developers > スタートガイド > Kotlin と Android をゼロから学ぶ > Unit2 – レイアウトUnit2-1 第8回 後半 の内容をまとめたものです(翻訳ではありません)


Unit2 – 1 第8回 後半

第8回 後半 の内容は以下の通りです

  • スタイル(style)を作成してUIに適用してみます
  • UI部品への入力に応じた処理を、キーリスナー(key listener)にラムダ式を使って記述してみます

具体的には次のようなレッスンです

  • 新しいスタイルを作ってUI部品(View)に適用してみます
  • 色以外のテーマ属性をテーマ(theme)に設定してみます
  • setOnKeyListener() メソッドを使ってキーリスナー(key listener)を設定してみます

スタイル(style)とテーマ(theme)

UI部品にはスタイル(style)を設定できるの

  • スタイルは、UI部品の属性をまとめて名前を付けたものです
  • スタイル(style)は styles.xml に設定します
  • 作成したスタイルはUI部品(View)ごとに適用できます。またテーマ(theme)に適用することでUI全体にまとめて適用することもできます

styles.xml を作成する

styles.xml をつくりますね

  1. res > values と展開して、values の上で右クリック
  2. New > Values Resource File を選択します
  3. 開いたダイアログの File Name: に styles.xml と入れてOK します
  4. 必要最小限の記述がされたファイルが作成されて開きます

TextView に使うスタイルを作成する

スタイルはクラスみたいに親スタイルから設定を引き継ぐことができるの

親スタイルは Material にあるのを使っちゃえばいいんですね

  • スタイルは一からすべて自分で書いても構いません。しかしMDC(Material Design Components)ライブラリにある TextView 用のスタイルを親にして継承したほうがなにかと便利です
  • スタイル名は継承元のスタイル名にある MaterialComponents を自分のアプリの名前に置き換えてつけることをお勧めします。たとえば、
    • 継承元のスタイル名: Widget.MaterialComponents.TextView
    • 作成するスタイル名:Widget.アプリ名.TextView
  • 親スタイルはブラウザで Material Components (Android) にアクセスして適用したいUI部品のページで探します(画面検索で Widget などを探してみます)。たとえば以下のようなものがあります
    • TextView:Widget.MaterialComponents.TextView
    • TextInputLayout: Widget.MaterialComponents.TextInputLayout.OutlinedBox
    • RadioButton: Widget.MaterialComponents.CompoundButton.RadioButton
    • Switch:Widget.MaterialComponents.CompoundButton.Switch

TextView用のスタイルを実際に書いてみる

styles.xml を開いておいてくださいね

  • まず Widget.MaterialComponents.TextView を親スタイルとして継承した Widget.TipTime.TextView スタイルを宣言します
  • styles.xml に次のように記述します

最初に親スタイルを指定して…

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Widget.TipTime.TextView" parent="Widget.MaterialComponents.TextView">
    </style>
</resources>

親スタイルから変えたい属性だけ追加します

<style name="Widget.TipTime.TextView" parent="Widget.MaterialComponents.TextView">
    <item name="android:minHeight">48dp</item>
    <item name="android:gravity">center_vertical</item>
    <item name="android:textAppearance">?attr/textAppearanceBody1</item>
</style>
  • minHeight, gravity はテキストの属性です
  • Material ではテキスト周りのデザイン済みスタイルも提供していて、textAppearance で設定できます
  • 設定できるデザイン済みスタイルはここに書いてあります。textAppearanceBody1 はそのひとつです

作成した TextView用のスタイルをUI部品に適用してみる

作ったスタイルを使ってみますね

  • activity_main.xml を開きます
  • 作成したスタイル(Widget.TipTime.TextView)を TextView に適用するには次のように記述します
<TextView
    ...
    style="@style/Widget.TipTime.TextView"
    ... />
  • 同じ属性がスタイルとレイアウト、両方に記述されていた場合、レイアウトに記述した内容が適用されます
  • TextView用に作成したスタイルはほかのUI部品(たとえばSwitchなど)には適用できません

styles.xml で使う値を dimens.xml に登録して使う

dimens.xml も使ってみますね

  • よく使う値を dimens.xml を作成して登録、styles.xml で使うこともできます
  • dimens.xml を作成(styles.xmlと同じように作成します)して次のような内容を書き込みます
<resources>
   <dimen name="min_text_height">48dp</dimen>
</resources>

styles.xml の中でこんな感じに利用できます

...
<style name="Widget.TipTime.TextView" parent="Widget.MaterialComponents.TextView">
    <item name="android:minHeight">@dimen/min_text_height</item>
    <item name="android:gravity">center_vertical</item>
    <item name="android:textAppearance">?attr/textAppearanceBody1</item>
</style>
...

RadioButton に使うスタイルを作成する

他のUI部品に使うスタイルも同じように設定すればいいんですね

  • styles.xml を開きます
  • TextView 用のスタイルと同じように、RadioButton 用のスタイルはこんな風に書けます
<style name="Widget.TipTime.CompoundButton.RadioButton"  parent="Widget.MaterialComponents.CompoundButton.RadioButton">
   <item name="android:paddingStart">8dp</item>
   <item name="android:textAppearance">?attr/textAppearanceBody1</item>
</style>

作成したスタイルをテーマに適用する

スタイルはテーマに適用することもできるの

まとめて設定できて便利かも!

styles.xml で作成したスタイルをUI部品(View)ごとではなくテーマ(thema)に適用してみます

  • テーマ(themes.xml)には色指定で使った colorPrimary のようなテーマ属性(theme attribute)が他にもいろいろ用意されています
  • UI部品にスタイルを設定するのには radioButtonStyle, switchStyle , textInputStyle などのテーマ属性が利用できます
  • スタイル設定用のテーマ属性には styles.xml で定義したスタイル、その親スタイルになっている Material で提供されているスタイルなどが適用できます
  • テーマに設定されたスタイルは、テーマとしてUI画面全体に適用されます
  • テーマにスタイルを追加するには、themes.xml(res > values > themes.xml)を開いて次のように記述します。ダークモード用の themes.xml も同様です
<item name="textInputStyle">@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox</item>
<item name="radioButtonStyle">@style/Widget.TipTime.CompoundButton.RadioButton</item>
<item name="switchStyle">@style/Widget.TipTime.CompoundButton.Switch</item>

スマホ画面を回転させたときの設定

横にしちゃうこともありますよね

  • スマホを横(landscape)にしたとき画面の下が切れてしまって操作できなくなることがあります
  • これを避けるには ConstraintLayout 全体を ScrollView で囲むように設定を書き直します
<ScrollView
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_height="match_parent"
   android:layout_width="match_parent">

   <androidx.constraintlayout.widget.ConstraintLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:padding="16dp"
       tools:context=".MainActivity">

       ...
   </ConstraintLayout>

</ScrollView>

Enterキーを押したらキーボードが消えるようにする

フィールドへの入力時、Enter が押されたら入力終了と判断して画面に表示されているソフトキーボードが自動的に消えるようにします

ソフトキーボードを隠すメソッド(ハンドラー)を記述する

ソフトキーボードを隠すメソッドを作っておきます

  • KeyEvent(Enter入力)が発生したときにソフトキーボードを隠す処理を行うメソッドです
  • このメソッドのように何かが起きたときに呼び出されて処理を行うモジュールのことをハンドラー(handler)といいます
  • 次のメソッドを MainActivity.kt に追加します
private fun handleKeyEvent(view: View, keyCode: Int): Boolean {
   if (keyCode == KeyEvent.KEYCODE_ENTER) {
       // Hide the keyboard
       val inputMethodManager =
           getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
       inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
       return true
   }
   return false
}
  • Enter のキーコードは KeyEvent.KEYCODE_ENTER で参照できます
  • InputMethodManager を使うと、ソフトキーボードを表示したり隠したり種類を選択したりすることができます
  • as はキャストです
  • イベント処理を行ったら true、それ以外はfalseを返します

キーリスナーを設置する

  • Enterキーが押されたことを検知(listen)できるようにテキストフィールドにキーリスナーを設置します
  • MainActivity.kt の onCreate() の中にコードを記述します(アプリが起動したらすぐに機能するように)

コードはこんなかんじです

override fun onCreate(savedInstanceState: Bundle?) {
   ...

   setContentView(binding.root)

   binding.calculateButton.setOnClickListener { calculateTip() }

   binding.costOfServiceEditText.setOnKeyListener { view, keyCode, _ -> handleKeyEvent(view, keyCode)
   }
}
  • UI部品(View)の TextInputEditText にキー入力(キーイベント)を検知するキーリスナーを設置します
  • キーイベントが発生したら key listener でキーイベントを受け取り handleKeyEvent メソッド(ハンドラー)で処理を行います
  • キーリスナーの設置には setOnKeyListener() メソッドを使います
  • TextInputEditText は id名 cost_of _service_edit_text なので、Kotlinコードからは binding.costOfServiceEditText でアクセスできます
  • ボタンに設置した click listener と基本的に同じしくみです
  • setOnKeyListener の後ろはラムダ式という記述方法です

ラムダ式?

うん、「インタフェースとラムダ式(Kotlin編)」にまとめたので見てくださいね

  • setOnKeyListener() メソッドの引数は OnKeyListener 型で、OnKeyListener はインタフェースです
  • 引数になっているインタフェースにメソッドが1つしかないとき、ラムダ式を使うと処理が簡潔に記述できます
  • setOnKeyListener() の引数はちょうどその条件を満たしていて、ラムダ式を使って短く記述されています
  • ラムダ式に使われいるアンダースコア(_)は「この引数は使用しません」という意味です

その他

TalkBack を有効にして試してみる

いろんな使い方でテストしてみます

  • TalkBack(Androidに搭載されているGoogleのスクリーンリーダ)を有効にして、デバイスをいじって操作感に問題がないか試してみます
    1. Androidデバイス(エミュレータ,実機)で設定を開きます
    2. 「ユーザー補助 > TalkBack」を選択します
    3. TalkBack を使用する > OK」とします
  • activity_main.xml で importantForAccessibility=”no” としてあるUI部品は読み上げ対象になりません

ベクター画像の色合いを調整する

  • ベクター画像はXMLファイルを修正して画像の色味を変更できます
  • Android Studio の Drawables に登録したベクター画像のXMLを直接書き換えて色味を変えてみます

テーマを使ってベクター画像の色味を変更することもできるの

ベクター画像(XML)の修正手順

  • ベクター画像のXMLを開きます。android:tint と android:fillColor の属性に注目
    • android:tint はテーマを使って色味を指定する属性です
    • android:fillColor の設定は android:tint の設定があるとオーバーライド(上書き)されて無効になります
  • android:tint の標準設定は次のとおりです。アイコンはグレーで表示されます
<vector ...
   android:tint="?attr/colorControlNormal">
   ...
</vector>
  • これを次のように設定します
  • ベクター画像の色にテーマ(theme)の colorPrimary で設定した色が適用されます
  • 標準(light)テーマとダークテーマ、それぞれのテーマの色が自動的に画像に適用されます
<vector ...
   android:tint="?attr/colorPrimary">
   ...
</vector>

まとめ

チュートリアル Unit2 – 1 終了です。お疲れさまでした!

  • ここまでで作成したアプリのプロジェクトはここからダウンロードできます・・・Solution Code URL: https://github.com/google-developer-training/android-basics-kotlin-tip-calculator-app-solution
  • スタイル(style)を使うとUI部品の属性をまとめて指定できます
  • キーリスナー(key listener)は、ラムダ式を使って簡潔に記述できます
  • アプリのテストでは、あまりしないような使い方(edge case)も試して問題点を探してみましょう
  • コードにはコメントを入れましょう
  • コードはできるだけ見やすく簡潔に書きましょう

参考