Speed round
Week3
お題が出るので、お題に沿ってデザインをコードに実装していく。でもできませんでしたー。
できなーい!だめだ、全然わからない。ちょっと無謀すぎたか…orz 俺の #AndroidDevChallenge はここで終わりだな~ pic.twitter.com/Mt4wU5Z7XE
— dalomo (@dalomo_dalomo) March 13, 2021
悲しい。
何ができなかったか
大変悔しいので、何ができなかったのかをまとめて、一つずつ潰していってみることにした。
全体
- ダークテーマでの色や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関係なくね、と思いつつ。
ついでに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()
てする。
ライト・ダークでのリソース切り替え
これ
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にしてあげると勝手にモードに合わせて表示してくれたりするらしい。
ページごとにファイルを分割した
新しくファイル作ってコードをそっちに移しただけ。
Welcome
葉っぱが切れる
alignment = Alignment.CenterStart
を追加した。なぜこうすると上手くいくのかは謎。
TextをBaseline基準の間隔にする
modifier = Modifier.paddingFromBaseline(top = 32.dp, bottom = 40.dp)
とした。公式の日本語訳のページだとpaddingFromBaselineが載ってなくて迷った。原文にあたれってのはこういうことかと呪ったよね。
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)
これなんでこんな書き方なんだろう。探すの手間どった。
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 ) }
こういうのがあるのね…。どうすれば透明になるんだ~?とかやってたわ。
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 )
上だけで隠れる。下は知らん。
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) ) } } } }
こんな感じで書いたんだけど、結果
うまくいかん。ちょっとどうやってもキレイに表示されんのでこれはもういいや…。
あとなぜかこのあたりから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がなんか悪いのかなーといろいろ調べてたら
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ってのを使えばいいんだろうか。試しに
ここらへん参考にしてみて
val context = LocalContext.current val image : Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.desert_chic, null)!!
こんなコード書いてみたんですが、表示されませんでした…。じゃあURIとか?と思って
を参考に
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使うとこれも改善された。なぜかはよく分かりません。
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*/ } ) } }
最初なぜかアイコンが上にはみ出してキャプションしかバー内に入ってなかった。けどなんか色々やって↑な感じにしたらいい感じだった。
完成
いいんじゃないでしょうか…とりあえず形にはできたよね?まぁチェックボックスの初期値とかダークモードの確認全くやってない(スマホが対応してなかったしプレビューが効かん)とか詰めればきりないんだけどね。あー疲れた!ちなみに第4週は天気アプリだったけど参加はしなかった…。参加してたら天気ルーレットアプリを作りたかったかな、残念!でもまぁここまで参加できて楽しかった~(^^)あ、あと時間帯違いのWeTradeとMySootheがあるから時間あったらやってみようかなぁ~。
コメント