グラフライブラリ 4. デザイン適用

*この記事は韓国語から翻訳したものです。不十分な部分があれば、いつでもフィードバックをいただければありがたいです！ ([オリジナル記事](https://github.com/boostcampwm2023/and09-PriceGuard/wiki/%EA%B7%B8%EB%9E%98%ED%94%84-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%94%94%EC%9E%90%EC%9D%B8-%EC%9E%85%ED%9E%88%EA%B8%B0), 同じく私が作成しました。)*

グループプロジェクトでグラフライブラリを実装する過程をまとめてみました。今回の記事ではその中でグラフデザインやテーマの部分について説明します。([project repo](https://github.com/boostcampwm2023/and09-PriceGuard), [library repo](https://github.com/Taewan-P/material-android-chart))

# 目標

<img src="https://github.com/boostcampwm2023/and09-PriceGuard/assets/37584805/a52de0bc-51bd-4205-939f-00283a55bacf" width="300" height="600"/>

私たちが欲しい機能は次のようになります。

- 色が設定されたstyleをカスタムビューに追加すると、その色に合ったグラフが描画されます。
- グラフだけでなく、x, y軸と背景なども一緒に色が変わります。

指定する色は次のように設定しました。

- colorPrimary: 線とグラデーションを描く最も基本的な色。
- colorSecondary: 水平線を描くのに使われる色。
- colorError: Invaildした値を描くのに使われる色。
- colorSurface: 背景色を描画するのに使う色
- colorOnSurface: 背景色の上に表示される文字やアイコンの色。
- colorPrimaryContainer: インタラクション時、グラフの上に表示されるテキストボックスの色。
- colorOnPrimaryContainer: 軸に表示されるラベルの色

# 実装

```java
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
}
```

グラフライブラリでは、グラフはカスタムViewで実装されます。

ViewはdefStyleAttrを引数として受け取ってstyleを適用することができます。

このライブラリを使うプロジェクトでstyleデータを生成してstyleで指定すると、

Viewは該当するstyleのcolor値を受け取り、描画されるグラフの色に反映します。

```xml
<resources>
    <declare-styleable name="Chart">
        <attr name="colorPrimary" format="color" />
        <attr name="colorSecondary" format="color" />
        <attr name="colorError" format="color" />
        <attr name="colorSurface" format="color" />
        <attr name="colorOnSurface" format="color" />
        <attr name="colorPrimaryContainer" format="color" />
        <attr name="colorOnPrimaryContainer" format="color" />
    </declare-styleable>
</resources>
```

ライブラリ内で予めobtainStyledAttributesを定義して、style内のcolorを受け取れるようにします。

```kotlin
    private var colorPrimary: Int
    private var colorSecondary: Int
    private var colorError: Int
    private var colorSurface: Int
    private var colorOnSurface: Int
    private var colorPrimaryContainer: Int
    private var colorOnPrimaryContainer: Int

    init {
        val typedArray = context.obtainStyledAttributes(
            attrs,
            R.styleable.Chart,
            defStyleAttr,
            0
        )
        colorPrimary = typedArray.getColor(
            R.styleable.Chart_colorPrimary,
            Color.BLACK
        )
        colorSecondary = typedArray.getColor(
            R.styleable.Chart_colorSecondary,
            Color.GRAY
        )

        colorError = typedArray.getColor(
            R.styleable.Chart_colorError,
            Color.RED
        )

        colorSurface = typedArray.getColor(
            R.styleable.Chart_colorSurface,
            Color.WHITE
        )
        colorOnSurface = typedArray.getColor(
            R.styleable.Chart_colorOnSurface,
            Color.BLACK
        )

        setBackgroundColor(colorSurface)

        typedArray.recycle()
    }
```


次に、Chart内でグローバルに宣言した変数に色データを保存します。

typedArrayを使って各色を抽出することができます。

もし、該当するattributionがなければ、デフォルト値を設定して適用します。

```xml
<app.priceguard.materialchart.Chart
    android:id="@+id/example_chart_1"
    style="@style/ExampleChartTheme"
    android:layout_width="0dp"
    android:layout_height="400dp" />
```

```xml
<style name="ExampleChartTheme">
    <item name="colorPrimary">?attr/colorPrimary</item>
    <item name="colorSecondary">?attr/colorSecondary</item>
    <item name="colorError">?attr/colorError</item>
    <item name="colorSurface">?attr/colorSurface</item>
    <item name="colorOnSurface">?attr/colorOnSurface</item>
    <item name="colorPrimaryContainer">?attr/colorPrimaryContainer</item>
    <item name="colorOnPrimaryContainer">?attr/colorOnPrimaryContainer</item>
</style>
```

このようにxmlでViewを使う時styleを追加すると好きな色をつけることができます。

追加で色を付ける時、? attr指定子をstyleに適用するとダークモードにも対応できます。

次の記事では、タッチ、インタラクションをどのように実装するかを書く予定です。