JetpackCompose日記#3

## マテリアルテーマ設定
大体[ここに](https://developer.android.com/jetpack/compose/designsystems/material?hl=ja)まとめられている。
Jetpack Compose には、デジタル インターフェースを作成するための包括的なデザイン システムであるマテリアル デザインの実装が用意されています。マテリアル デザインのコンポーネント（ボタン、カード、スイッチなど）は、プロダクトのブランドをより良く反映するようにマテリアル デザインをカスタマイズする体系的な方法である、マテリアル テーマ設定に基づいて構築されています。マテリアル テーマは、色、タイポグラフィ、シェイプの属性で構成されています。これらの属性を***カスタマイズ***すると、その変更内容は、アプリのビルドに使用するコンポーネントに自動的に反映されます。

##### 色
マテリアル デザインでは、アプリ全体で使用できる、意味的に名付けられた色が複数定義されています。
![colorImage](https://developer.android.com/static/codelabs/jetpack-compose-theming/img/62ccfe5761fd9eda_1920.png?hl=ja)
- プライマリはメインのブランドカラーです。
- セカンダリはアクセントに使用します。コントラストが強い部分には、さらに暗いまたは明るいバリエーションを提供できます。
- 背景色とサーフェス色は、アプリの「サーフェス」に理論上存在するコンポーネントを保持するコンテナに使用します。マテリアルでは「on」色（指定した色の上に配置されるコンテンツに使用する色）も定義します。たとえば「サーフェス」色のコンテナ内のテキストは、「サーフェス上」の色になります。

マテリアル コンポーネントは、こうしたテーマの色を使用するように設定されます。たとえばデフォルトでは、フローティング アクション ボタンの色は secondary、カードのデフォルトは surface などです。

名前付きの色を定義すると、ライトモードとダークモードの両方など、代替のカラーパレットを提供できるようになります。

![image](https://developer.android.com/static/codelabs/jetpack-compose-theming/img/1a9b78141ddfa87b_1920.png?hl=ja)
小さなカラーパレットを定義し、アプリ全体で一貫して使用することもおすすめします。マテリアル カラーツールを使用すると、色を選択して[カラーパレット](https://material.io/resources/color/)を作成でき、その組み合わせにもアクセスできるようになります。

##### タイポグラフィ
同様に、マテリアルでは、意味する内容に基づいて名付けられたタイプスタイルがいくつか定義されています。
![image](https://developer.android.com/static/codelabs/jetpack-compose-theming/img/1d44de3ff2f7fd1c_1920.png?hl=ja)
テーマによってタイプスタイルを変えることはできませんが、タイプスケールを使用すると、アプリ内での一貫性が向上します。独自のフォントや他のタイプ カスタマイズを指定すると、アプリで使用するマテリアル コンポーネントに反映されます（アプリバーはデフォルトで h6 スタイルを使用し、ボタンは button を使用するなど）。タイプスケールを作成するには、マテリアル [タイプスケール生成ツール](https://material.io/design/typography/the-type-system.html#type-scale)を使用すると便利です。

##### シェイプ
マテリアルでは、シェイプを使用して体系的にブランドを表現できます。コンポーネントについて小、中、大という 3 つのカテゴリを定義します。それぞれに使用するシェイプを定義でき、角のスタイル（切り落としまたは丸）とサイズをカスタマイズできます。
![image](https://developer.android.com/static/codelabs/jetpack-compose-theming/img/886b811cc9cad18e_1920.png?hl=ja)
シェイプテーマのカスタマイズは多くのコンポーネントに反映されます（ボタンとテキスト フィールドは小、カードとダイアログは中、シートは大のシェイプテーマをデフォルトで使用するなど）。コンポーネントとシェイプテーマの対応関係について詳しくは[こちら](https://material.io/design/shape/applying-shape-to-ui.html#shape-scheme)をご覧ください。
##### ベースライン
マテリアルのデフォルトは「ベースライン」テーマです。カラーパターンは紫色、タイプスケールは Roboto であり、シェイプは上の図のようにやや丸みを帯びています。テーマを指定しない場合、またはカスタマイズしない場合、コンポーネントはベースライン テーマを使用します。

##### テーマを定義する
- ###### MaterialTheme
Jetpack Compose でテーマ設定を実装するための主な要素は、MaterialTheme コンポーザブルです。このコンポーザブルを Compose 階層に配置すると、その中にあるすべてのコンポーネントの色、タイプ、シェイプのカスタマイズを指定できます。このコンポーザブルは、ライブラリで次のように定義されています。
```
@Composable
fun MaterialTheme(
    colors: Colors,
    typography: Typography,
    shapes: Shapes,
    content: @Composable () -> Unit
) { ...
```
##### テーマを作成する

スタイル設定を一元管理するために、MaterialTheme をラップして設定する独自のコンポーザブルを作成することをおすすめします。これにより、テーマのカスタマイズを 1 か所で指定し、複数の画面や @Preview など、さまざまな場所で簡単に再利用できるようになります。たとえば、アプリのセクションごとに異なるスタイルをサポートする場合など、必要に応じて複数のテーマ コンポーザブルを作成できます。

```
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
  MaterialTheme(content = content)
}
```
***注***: この構造は Android Studio の Compose プロジェクト テンプレートで作成されますが、コンセプトについての理解を深めるために最初から作成しています。

##### 色
アプリに実装するカラーパレットは次のとおりです。
![image](https://developer.android.com/static/codelabs/jetpack-compose-theming/img/b2635ed3ec4bfc8f_1920.png?hl=ja)
Compose では、Color クラスを使用して色を定義します。コンストラクタが複数あり、ULong として、または個別のカラー チャンネルで色を指定できます。

***注***: 色を指定する一般的な「#dd0d3c」形式から変換するには、「#」を「0xff」に置き換えます。つまり Color(0xffdd0d3c) の「ff」はフルアルファを意味します。

theme パッケージに新しいファイル Color.kt を作成します。このファイルに、最上位の公開プロパティとして次の色を追加します。

```
val Red700 = Color(0xffdd0d3c)
val Red800 = Color(0xffd00036)
val Red900 = Color(0xffc20029)
```
***注***: 色を定義する際は、「意味的に」ではなく、色の値に基づいて「文字どおりに」名前を付けます（例: primary ではなく Red500）。これにより、複数のテーマを定義できます。たとえば、ダークモードやスタイルの異なる画面で、別の色を primary とみなすことができます。

アプリの色を定義したので、今度はそれを MaterialTheme で必要となる Colors オブジェクトにまとめ、マテリアルの名前付きの色に具体的な色を割り当てます。Theme.kt に戻り、次のコードを追加します。
```
private val LightColors = lightColors(
    primary = Red700,
    primaryVariant = Red900,
    onPrimary = Color.White,
    secondary = Red700,
    secondaryVariant = Red900,
    onSecondary = Color.White,
    error = Red800
)
```
lightColors 関数を使用して Colors を作成します。適切なデフォルト値が提供されるため、マテリアル カラーパレットの構成色をすべて指定する必要はありません。たとえば、background 色や「on」色の多くを指定していないため、デフォルトを使用します。
これを適用する。

```
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
    MaterialTheme(
        colors = LightColors,
        content = content
    )
}
```
##### タイポグラフィ
アプリに実装するタイプスケールは次のとおりです。
![image](https://developer.android.com/static/codelabs/jetpack-compose-theming/img/54c420f78529b77d_1920.png?hl=ja)

Compose では、TextStyle オブジェクトを定義して、あるテキストのスタイルを設定するために必要な情報を定義できます。その属性のサンプルを次に示します。
```
data class TextStyle(
    val color: Color = Color.Unset,
    val fontSize: TextUnit = TextUnit.Inherit,
    val fontWeight: FontWeight? = null,
    val fontStyle: FontStyle? = null,
    val fontFamily: FontFamily? = null,
    val letterSpacing: TextUnit = TextUnit.Inherit,
    val background: Color = Color.Unset,
    val textAlign: TextAlign? = null,
    val textDirection: TextDirection? = null,
    val lineHeight: TextUnit = TextUnit.Inherit,
    ...
)
```

目的のタイプスケールでは、タイトルに Montserrat を使用し、本文に Domine を使用します。関連するフォント ファイルは、プロジェクトの res/fonts フォルダにすでに追加されています。

theme パッケージに新しいファイル Typography.kt を作成します。まず、FontFamily（各 Font のさまざまなウェイトの組み合わせ）を定義しましょう。

```
private val Montserrat = FontFamily(
    Font(R.font.montserrat_regular),
    Font(R.font.montserrat_medium, FontWeight.W500),
    Font(R.font.montserrat_semibold, FontWeight.W600)
)

private val Domine = FontFamily(
    Font(R.font.domine_regular),
    Font(R.font.domine_bold, FontWeight.Bold)
)
```
次に、MaterialTheme が受け入れる Typography オブジェクトを作成し、スケールのセマンティック スタイルごとに TextStyle を指定します。
```
val JetnewsTypography = Typography(
    h4 = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.W600,
        fontSize = 30.sp
    ),
    h5 = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.W600,
        fontSize = 24.sp
    ),
    h6 = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.W600,
        fontSize = 20.sp
    ),
    subtitle1 = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.W600,
        fontSize = 16.sp
    ),
    subtitle2 = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.W500,
        fontSize = 14.sp
    ),
    body1 = TextStyle(
        fontFamily = Domine,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp
    ),
    body2 = TextStyle(
        fontFamily = Montserrat,
        fontSize = 14.sp
    ),
    button = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.W500,
        fontSize = 14.sp
    ),
    caption = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.Normal,
        fontSize = 12.sp
    ),
    overline = TextStyle(
        fontFamily = Montserrat,
        fontWeight = FontWeight.W500,
        fontSize = 12.sp
    )
)
```
Theme.kt を開き、新しい Typography を使用するように JetnewsTheme コンポーザブルを更新します。

```
...
MaterialTheme(
        typography = JetnewsTypography,
...
```
##### シェイプ
アプリでシェイプを使用してブランドを表現します。一部の要素には、角を切り落としたシェイプを使用します。

Compose には、シェイプテーマを定義するために使用できる RoundedCornerShape クラスと CutCornerShape クラスが用意されています。

theme パッケージに新しいファイル Shape.kt を作成し、次のコードを追加します。
```
val JetnewsShapes = Shapes(
    small = CutCornerShape(topStart = 8.dp),
    medium = CutCornerShape(topStart = 24.dp),
    large = CutCornerShape(8.dp)
)
```
Theme.kt を開き、これらの Shapes を使用するように JetnewsTheme コンポーザブルを更新します。

```
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
  MaterialTheme(
    colors = LightColors,
    typography = JetnewsTypography,
+   shapes = JetnewsShapes,
    content = content
  )
}
```
##### コンテンツのアルファ
重要性を伝え、視覚的な階層を持たせるために、コンテンツを強調または抑制することはよくあります。マテリアル デザインでは、異なるレベルの透明度を利用してさまざまな重要度レベルを示すことを推奨しています。

Jetpack Compose は LocalContentAlpha を介して、これを実装します。この CompositionLocal に値を指定することで、階層のコンテンツのアルファを指定できます。子のコンポーザブルは、この値を使用できます。たとえば、Text と Icon は、LocalContentAlpha を使用するように調整された LocalContentColor の組み合わせをデフォルトで使用します。マテリアルは、ContentAlpha オブジェクトによってモデル化される一部の標準的なアルファ値（high、medium、disabled）を指定します。なお、MaterialTheme では LocalContentAlpha のデフォルトが ContentAlpha.high に設定されます。
```
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
    Text(...)
}
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
    Icon(...)
    Text(...)
}
```