Jetpack ComposeのAndroid Dev Challengeに応募できなかった Week3

スポンサーリンク
スポンサーリンク

Speed round

Android Dev Challenge: Week 3 - Speed round
News and insights on the Android platform, developer tools, and events.
File not found · android/android-dev-challenge-compose
Template repository for the ADS22 Speed Challenge. Contribute to android/android-dev-challenge-compose development by cr...
スポンサーリンク

Week3

お題が出るので、お題に沿ってデザインをコードに実装していく。でもできませんでしたー。

GitHub - dalomo-net/week3-Speed-Round
Contribute to dalomo-net/week3-Speed-Round development by creating an account on GitHub.

悲しい。

スポンサーリンク

何ができなかったか

大変悔しいので、何ができなかったのかをまとめて、一つずつ潰していってみることにした。

全体

  • ダークテーマでの色やresの切り替え
  • ステータスバー・ナビゲーションバー消してない

Welcome

  • 葉っぱの画像が切れてる
  • Textの間隔がbaselineを意識したものになってない
  • ボタンのサイズ・シェイプが変
  • ボタンの背景色を変えてない

Log in

  • ボタンのサイズ・シェイプが変
  • ボタンの背景色を変えてない

ついで

  • 入力欄にフォーカスした時、説明文字が消えない
  • パスワード欄の文字入力が丸見え

Home

  • Search欄にアイコンがない
  • テキストの間隔が変
  • 下のアプリバー
    • アイコンの大きさ
    • アイコンのキャプション
    • 選択・非選択時の色の切り替え
    • 間隔の整列

BrowseThemes

  • カードが作れてない
  • elevationを設定できていない
  • スクロールできるリストの形になってない

Design your home garden

  • テキストの間隔が変
  • dividerの位置が変
  • スクロールできるリストの形になってない

こんなところでしょうか…。

スポンサーリンク

改善していってみる

完成しますように。とりあえず見れるようにしたい。これが正しいというわけではない。

全体

ステータスバーを透過する

themes.xmlに

<item name="android:statusBarColor" tools:targetApi="l">@android:color/transparent</item>
<item name="android:windowLightStatusBar">true</item>

初っ端からJetpackCompose関係なくね、と思いつつ。

Attention Required! | Cloudflare

ついでにHomeでバーがバーに収まるように

ナビゲーションバー内に収まるようにする

projectのbuild.gradleに

ext.accompanist_version = '0.6.2'

appのbuild.gradleに

implementation "dev.chrisbanes.accompanist:accompanist-coil:$accompanist_version"
implementation "dev.chrisbanes.accompanist:accompanist-insets:$accompanist_version"

onCreateで

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    WindowCompat.setDecorFitsSystemWindows(window, false)
    setContent {
        MyTheme {
            ProvideWindowInsets {
                MyApp()
            }
        }
    }
}

こんな。そんでコンテンツ全体に効くところに

modifier = Modifier.navigationBarsPadding()

てする。

GitHub - google/accompanist: A collection of extension libraries for Jetpack Compose
A collection of extension libraries for Jetpack Compose - google/accompanist
Accompanist
A group of libraries to help write Jetpack Compose apps.

ライト・ダークでのリソース切り替え

これ

MaterialTheme.colors.isLight

でなんか判定ができるみたいなので、ifで分岐させたり

if (MaterialTheme.colors.isLight) R.drawable.light_logo else R.drawable.dark_logo

ResourseManagerでImport Drawablesの時にdark側のQQUALIFIER TYPE-VALUEをNightMode-NightTimeにしてあげると勝手にモードに合わせて表示してくれたりするらしい。

Compose のデザイン システム  |  Jetpack Compose  |  Android Developers
アプリのリソースの概要  |  Android Developers

ページごとにファイルを分割した

新しくファイル作ってコードをそっちに移しただけ。

Welcome

葉っぱが切れる

alignment = Alignment.CenterStart

を追加した。なぜこうすると上手くいくのかは謎。

Jetpack Compose: Layouts
IntroductionJetpack Compose provides a declarative way of building the UI of the Android app. Layouts are an essential c...

TextをBaseline基準の間隔にする

modifier = Modifier.paddingFromBaseline(top = 32.dp, bottom = 40.dp)

とした。公式の日本語訳のページだとpaddingFromBaselineが載ってなくて迷った。原文にあたれってのはこういうことかと呪ったよね。

Layouts in Compose  |  Jetpack Compose  |  Android Developers

Buttonのサイズを変える

Button(
    onClick = { },
    shape = MaterialTheme.shapes.medium,
    modifier = Modifier
        .fillMaxWidth()
        .height(48.dp)
        .padding(start = 16.dp,end = 16.dp)
)

潰れてたのが直った。

Buttonの背景色を変える

colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.secondary)

これなんでこんな書き方なんだろう。探すの手間どった。

Attention Required! | Cloudflare

TextButtonを使う

TextButton(
    onClick = { navController.navigate("login") },
    modifier = Modifier
        .fillMaxWidth()
        .height(48.dp)
        .padding(top = 8.dp)
) {
    Text(
        text = "Log in",
        color = MaterialTheme.colors.secondary,
        style = MaterialTheme.typography.button
    )
}

こういうのがあるのね…。どうすれば透明になるんだ~?とかやってたわ。

Exploring Jetpack Compose: Button
This was originally posted on my personal blog

Log in

TextをBaseline基準の間隔にする

modifier = Modifier.paddingFromBaseline(top = 184.dp, bottom = 16.dp),

先程に続き再び。これTextの下はOutlinedTextFieldの方で変えたほうがいいのかな。どっちなんだろ。

TextFieldにプレースホルダーを設定する

placeholder = {
    Text(text = "Email address", style = MaterialTheme.typography.body1)
}

こうだった。これで文字入力し始めると文字が消える。

TextFieldの入力表示を隠す

visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
    keyboardType = KeyboardType.Password
)

上だけで隠れる。下は知らん。

https://android–code.blogspot.com/2021/03/jetpack-compose-password-textfield.html

Buttonの形と背景色を変える

Button(
    onClick = { navController.navigate("home") },
    shape = MaterialTheme.shapes.medium,
    modifier = Modifier
        .fillMaxWidth()
        .height(48.dp),
    colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.secondary)
) {
    Text(
        text = "Log in",
        color = MaterialTheme.colors.background,
        style = MaterialTheme.typography.button
    )
}

さっきと一緒。

Home

TextField内の最初にアイコンを付ける

leadingIcon = {
    Icon(
        imageVector = Icons.Default.Search,
        contentDescription = "search",
        Modifier.size(18.dp)
    )
}

Iconというのがあるのだな…。頑張ってリソースに追加してたよ。。。

Browse Themesのカード作り

ひぃひぃ言いながら

@Composable
fun ThemeCard(n: String, rid: Int) {

    Card(
        modifier = Modifier
            .size(136.dp)
            .clickable { },
        shape = MaterialTheme.shapes.small,
        elevation = 1.dp,
        backgroundColor = MaterialTheme.colors.surface
    ) {
        Column(modifier = Modifier.fillMaxSize()) {
            Image(
                painter = painterResource(id = rid),
                contentDescription = n,
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .height(96.dp)
            )
            Box() {
                Text(
                    text = n,
                    style = MaterialTheme.typography.h2,
                    modifier = Modifier
                        .padding(start = 8.dp)
                        .paddingFromBaseline(top = 24.dp)
                )
            }
        }
    }
}

こんな感じで書いたんだけど、結果

うまくいかん。ちょっとどうやってもキレイに表示されんのでこれはもういいや…。

androidx.compose.material  |  Android Developers

あとなぜかこのあたりからCannot access class ‘androidx.compose.ui.graphics.painter.Painter’. Check your module classpath for missing or conflicting dependenciesというエラーが出るようになった。ImageとpainterResourceのところに赤波線が付いてるけどBuildは通る…。解決策が分からないのでほっといてる。

このカード達をLazyRowを使って行方向に並べているわけだけど、他の人と比べるとなんかカクカクしてしまっている。なんでなんだろう、多分何かが違うんだろうけど、その何かが分からないー。

Design your home gardenの並びにフィルターアイコンを付ける

Row(
    horizontalArrangement = Arrangement.SpaceBetween,
    verticalAlignment = Alignment.CenterVertically,
    modifier = Modifier
        .fillMaxWidth()
        .paddingFromBaseline(top = 40.dp)
) {

    Text(
        text = "Design your home garden",
        style = MaterialTheme.typography.h1,
        color = MaterialTheme.colors.onPrimary,
    )
    Icon(
        imageVector = Icons.Default.FilterList,
        contentDescription = "filterlist",
        modifier = Modifier.size(24.dp)
    )
}

こうなった。Rowにpaddingfrombaselineに気づくのに時間かかった。

LazyColumnに2つ以上アイテムがあると落ちる

@Composable
fun LazyColumnList() {
    LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp))
    {
        item {
            PlantItem(n = "Monstera", rid = R.drawable.monstera)
        }
        item {
            PlantItem(n = "Aglaonema", rid = R.drawable.aglaonema)
        }
        item {
            PlantItem(n = "Peace Lily", rid = R.drawable.peace_lilly)
        }
        item {
            PlantItem(n = "Fiddle Leaf tree", rid = R.drawable.fiddle_leaf)
        }
        item {
            PlantItem(n = "Snake plant", rid = R.drawable.snake_plant)
        }
        item {
            PlantItem(n = "Pothos", rid = R.drawable.pothos)
        }
    }
}

こうして

@Composable
fun PlantItem(n: String, rid: Int) {
    Row(
        modifier = Modifier
            .height(64.dp)
            .fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceBetween,
        verticalAlignment = Alignment.CenterVertically
    ) {
        Image(
            painter = painterResource(id = rid),
            contentDescription = n,
            modifier = Modifier.clip(shape = MaterialTheme.shapes.small)
        )
        Column() {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {

                Column(modifier = Modifier.padding(start = 16.dp)) {

                    Text(
                        text = n,
                        style = MaterialTheme.typography.h2,
                        color = MaterialTheme.colors.onPrimary,
                        modifier = Modifier.paddingFromBaseline(top = 24.dp)
                    )
                    Text(
                        text = "This is a description",
                        style = MaterialTheme.typography.body1,
                        color = MaterialTheme.colors.onPrimary
                    )
                }
                Checkbox(
                    checked = true,
                    onCheckedChange = {},
                    modifier = Modifier.size(24.dp)
                )
            }
            Divider(modifier = Modifier.padding(start = 8.dp))
        }
    }
}

こう作ってみたんだけどLazyColumnのItemが2つ以上になるとアプリが落ちる。なんでだーと思ってPlantItemの内容を一個ずつ削って見るとImageを削ったときだけはちゃんと表示される。つーことはImageがなんか悪いのかなーといろいろ調べてたら

Compose and other libraries  |  Jetpack Compose  |  Android Developers
File not found · google/accompanist
A collection of extension libraries for Jetpack Compose - File not found · google/accompanist

CoilImageっていうのが使えるようになるやつがあるみたい。そんでdataには読み込みたいURLを指定するらしいんだがres/drawableに入れてる場合はどうするんだろう。

dataが対応してる型が

String (mapped to a Uri)
Uri (“android.resource”, “content”, “file”, “http”, and “https” schemes only)
HttpUrl
File
DrawableRes
Drawable
Bitmap

Drawableってのを使えばいいんだろうか。試しに

ドローアブルの概要  |  Views  |  Android Developers
Attention Required! | Cloudflare

ここらへん参考にしてみて

val context = LocalContext.current
val image : Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.desert_chic, null)!!

こんなコード書いてみたんですが、表示されませんでした…。じゃあURIとか?と思って

Attention Required! | Cloudflare

を参考に

val path: Uri = Uri.parse("android.resource://com.example.androiddevchallenge/" + R.drawable.desert_chic)

こうして、dataにpathを渡したけどこれも表示されませんでした…。他に引数に@DrawableResつけてみたりしたけど駄目だった。

contentDescription = ""

これ!これが足りなかった!

CoilImage(
    data = rid,
    contentDescription = "",
    modifier = Modifier
        .size(64.dp)
        .clip(shape = MaterialTheme.shapes.small),
    contentScale = ContentScale.Crop
) {}

こう!でいけたわ~。

LazyColumn, LazyRowのスクロールがカクカクする

CoilImage使うとこれも改善された。なぜかはよく分かりません。

Attention Required! | Cloudflare

BottomBarにLazyColumnのリストが隠れる

contentPadding = PaddingValues(bottom=56.dp)

LazyColumnにBottomBarの高さのpaddingを入れてみたけどもっとキレイなやり方ないんだろうか。

BottomAppBarとBottomNavigationの違い

さっきからBottomAppBarって言ってたような気がするが、BottomAppBarはページ内でなんらかのアクションをする際に使うやつで、BottomNavigationはページ遷移をするときに使うやつらしい。多分。で、今回の場合はBottomNavigationを使うんかな。

BottomNavigationを実装する

@Composable
fun BottomBar() {

    BottomNavigation(
        backgroundColor = MaterialTheme.colors.primary,
        modifier = Modifier.height(56.dp)
    ) {
        BottomNavigationItem(
            selected = true,
            onClick = { /*TODO*/ },
            icon = { Icon(imageVector = Icons.Default.Home, contentDescription = "Home") },
            label = { Text(text = "Home",style = MaterialTheme.typography.caption) }
        )
        BottomNavigationItem(
            selected = false,
            icon = { Icon(imageVector = Icons.Default.FavoriteBorder, contentDescription = "favorite") },
            label = { Text(text = "Favorites",style = MaterialTheme.typography.caption) },
            onClick = { /*TODO*/ }
        )
        BottomNavigationItem(
            selected = false,
            icon = { Icon(imageVector = Icons.Default.AccountCircle, contentDescription = "profile") },
            label = { Text(text = "Profile",style = MaterialTheme.typography.caption) },
            onClick = { /*TODO*/ }
        )
        BottomNavigationItem(
            selected = false,
            icon = { Icon(imageVector = Icons.Default.ShoppingCart, contentDescription = "cart") },
            label = { Text(text = "Cart",style = MaterialTheme.typography.caption) },
            onClick = { /*TODO*/ }
        )
    }
}

最初なぜかアイコンが上にはみ出してキャプションしかバー内に入ってなかった。けどなんか色々やって↑な感じにしたらいい感じだった。

androidx.compose.material  |  Android Developers
androidx.compose.material  |  Android Developers
スポンサーリンク

完成

GitHub - dalomo-net/week3-Speed-Round
Contribute to dalomo-net/week3-Speed-Round development by creating an account on GitHub.

いいんじゃないでしょうか…とりあえず形にはできたよね?まぁチェックボックスの初期値とかダークモードの確認全くやってない(スマホが対応してなかったしプレビューが効かん)とか詰めればきりないんだけどね。あー疲れた!ちなみに第4週は天気アプリだったけど参加はしなかった…。参加してたら天気ルーレットアプリを作りたかったかな、残念!でもまぁここまで参加できて楽しかった~(^^)あ、あと時間帯違いのWeTradeとMySootheがあるから時間あったらやってみようかなぁ~。

コメント

タイトルとURLをコピーしました