JetpackComposeでカスタムビューを作ってみた

5 min read読了の目安(約4700字

最近話題のJetpackComposeですが、1画面まるっと対応は少し不安があるのでカスタムビューから対応してみたいと思ってやってみた記録です。
とりあえず動いたレベルなので、誤りや非推奨のコードもあるかもしれません

Build.gradle

コードラボSetupも参考にしてください

buildscript {
    ext {
        compose_version = '1.0.0-alpha03'
    }
    ext.kotlin_version = "1.4.10"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.0-alpha12'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

こちらはコードラボの物をそのまま使ってます。
kotlinのバージョンが1.4以上であれば大丈夫なはずです。

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.0"

    defaultConfig {
        applicationId "com.example.statecodelab"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    kotlinOptions {
        jvmTarget = '1.8'
        useIR = true
        allWarningsAsErrors = false
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    buildFeatures {
        compose true
        viewBinding true
    }
    composeOptions {
        kotlinCompilerExtensionVersion "$compose_version"
        kotlinCompilerVersion "$kotlin_version"
    }
}

dependencies {
〜略〜
    implementation "androidx.compose.animation:animation:$compose_version"
    implementation "androidx.compose.foundation:foundation:$compose_version"
    implementation "androidx.compose.foundation:foundation-layout:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.material:material-icons-extended:$compose_version"
    implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
    implementation "androidx.compose.runtime:runtime:$compose_version"
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.ui:ui-tooling:$compose_version"
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
    kotlinOptions {
        jvmTarget = "1.8"
        freeCompilerArgs += [
                "-Xopt-in=kotlin.RequiresOptIn"
        ]
    }
}

こちらもほぼコードラボと同じですが、使用している別のライブラリの影響でallWarningsAsErrorsをtrueにしておくとビルドが通らなかったのでfalseに変更しています。

カスタムビュー

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.compose.foundation.Text
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Recomposer
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.setContent
import sobaya.example.allflow.R

class ComposeSample @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) {

    init {
        val view = LayoutInflater.from(context).inflate(R.layout.compose, this, true)
        (view as ViewGroup).setContent(Recomposer.current(), null) {
            MaterialTheme {
                customView()
            }
        }
    }

    @Composable
    fun customView() {
        Text(text = "TEST", color = Color.Black)
    }
}

LayoutInflaterでFramelayoutを宣言してるだけのLayout.xmlを読み込ませて、
そこにcustomView()メソッドで作成したレイアウトを差し込んでいます。
ここはxmlの読み込みが無駄に思えるのですが、他に方法が見つからなかったのでこうしています。

FragmentのonCreateViewのようにViewを返却すれば描画してくれる場合にはComposeViewと言うクラスが用意されているので

ComposeView(requireContext()).apply {
    setContent {
	Text(text = "TEST", color = Color.Black)
    }

こんな感じに記載することができます。
※ComposeViewをViewとして渡してあげれば描画してくれる

Layout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

本当に何も記載していません

画面


表示はこのようになりました


気になったのでレイアウトの構成を眺めてみたら、この程度の内容なのにかなり深くなっておられる。。。

サンプルコード

https://github.com/sobaya-0141/AllFlow/tree/compose