Compose 打造一個Home頁面

Compose 打造一個Home頁面

一般的APP首頁都是由多個Tab組成蕉毯。在Compose中杜秸,要實現(xiàn)這個會變得異常的簡單埋泵,這個得益于Compose自帶的組合函數(shù)功能砂竖。下面是輕松打造一個Home頁面的過程遂蛀。

home_preview.png

BottomNavigationView的實現(xiàn)

由于Compose布局的組合化的靈活谭跨。這里直接實現(xiàn)一個 Image +Text的Tab,通過遍歷數(shù)組進(jìn)行生成即可。拆分步驟如下:

  1. 一個橫向布局螃宙,嵌套多個豎向Tab
  2. Tab具備的信息:圖片(選中和未選中)蛮瞄、文本
  3. 每一個Tab點(diǎn)擊的回調(diào):tag->Unit

模型

data class TabModel(
    val tagTag: String,
    val tabName: Int,
    val normalIcon: Int,
    val selectedIcon: Int
)

主體代碼

@Preview(showBackground = true)
@Composable
fun TabView(
    @PreviewParameter(TabDataSourceMock::class) tabSource: Array<TabModel>,
    tagCallback: ((String) -> Unit)?
) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .shadow(4.dp, RectangleShape, false)
            .wrapContentHeight(Alignment.CenterVertically)
            .background(Color.White)
    ) {

        val imageModifier = Modifier.padding(0.dp, 8.dp, 0.dp, 0.dp)
        val tabModifier = Modifier.padding(0.dp, 0.dp, 0.dp, 5.dp)

        val selectIndex = rememberSaveable {
            mutableStateOf(0)
        }

        tabSource.forEachIndexed { index, currentModel ->

            Column(
                modifier = Modifier
                    .weight(1F, true)
                    .clickable {
                        selectIndex.value = index
                        tagCallback?.invoke(currentModel.tagTag)
                    },
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center,
            ) {
                Image(
                    painter = if (index == selectIndex.value) painterResource(
                        id = currentModel.selectedIcon
                    ) else
                        painterResource(
                            id = currentModel.normalIcon
                        ),
                    contentDescription = stringResource(id = currentModel.tabName),
                    modifier = imageModifier
                )
                Text(
                    stringResource(id = currentModel.tabName),
                    modifier = tabModifier,
                    textAlign = TextAlign.Center,
                    fontSize = 12.sp,
                    color = if (index == selectIndex.value) Color(0xFF07C160) else Color(0xFFAFB2B0),
                )
            }
        }
    }
}

模擬數(shù)據(jù)

class TabDataSourceMock : PreviewParameterProvider<Array<TabModel>> {

    override val values: Sequence<Array<TabModel>>
        get() = listOf<Array<TabModel>>(
            tabDataAll(),
            tabDataWithoutMall()
        ).asSequence()
}

fun tabDataAll(): Array<TabModel> {
    return arrayOf<TabModel>(
        TabModel(
            TabTags.TAG_HOME,
            R.string.tab_home,
            R.drawable.icon_home_normal,
            R.drawable.icon_home_selected
        ),
        TabModel(
            TabTags.TAG_SMART,
            R.string.tab_smart,
            R.drawable.icon_smart_normal,
            R.drawable.icon_smart_selected
        ),
        TabModel(
            TabTags.TAG_MALL,
            R.string.tab_mall,
            R.drawable.icon_mall_normal,
            R.drawable.icon_mall_selected
        ),
        TabModel(
            TabTags.TAG_MORE,
            R.string.tab_more,
            R.drawable.icon_me_normal,
            R.drawable.icon_me_selected
        )
    )
}

fun tabDataWithoutMall(): Array<TabModel> {
    return arrayOf<TabModel>(
        TabModel(
            TabTags.TAG_HOME,
            R.string.tab_home,
            R.drawable.icon_home_normal,
            R.drawable.icon_home_selected
        ),
        TabModel(
            TabTags.TAG_SMART,
            R.string.tab_smart,
            R.drawable.icon_smart_normal,
            R.drawable.icon_smart_selected
        ),
        TabModel(
            TabTags.TAG_MORE,
            R.string.tab_more,
            R.drawable.icon_me_normal,
            R.drawable.icon_me_selected
        )
    )
}
class TabTags {
    companion object {
        const val TAG_HOME = "home"
        const val TAG_SMART = "smart"
        const val TAG_MALL = "mall"
        const val TAG_MORE = "more"
    }
}

預(yù)覽如下

mock_preview2.png

這里為什么有兩個預(yù)覽呢?主要是在模擬函數(shù)返回了兩個source谆扎。

開發(fā)中遇到的問題

資源引用

  1. 引用字符串 stringResource(id = currentModel.tabName)
  2. 引用圖片資源 painterResource(id = currentModel.selectedIcon)

預(yù)覽函數(shù)

PreviewParameterProvider<Array<TabModel>> 這個函數(shù)正確使用方式如下

@Preview(showBackground = true)
@Composable
fun TabView(
   @PreviewParameter(TabDataSourceMock::class) tabSource: Array<TabModel>,
   tagCallback: ((String) -> Unit)?
) 

模型抽象的錯誤

開始時挂捅,我對TabModel的抽象是直接使用了 Painter 導(dǎo)致了一個錯誤 Functions which invoke @Composable functions must be marked with the @Composable annotation
這個錯誤已經(jīng)非常明顯,所以不能在非@Composable 函數(shù)下堂湖。盡可能抽象出不依賴Compose的model闲先。

Compose的便捷

通過這個簡單的例子發(fā)現(xiàn)。

  1. 簡約到極致无蜂。 Compose的便捷不單單在簡約伺糠,而且特別省時間,開發(fā)效率可以說是翻了好幾倍斥季。你想想训桶,如果之前要實現(xiàn)這個,你要多少的封裝酣倾,可能還要使用到Fragment的管理舵揭。真不敢想象。
  2. 依賴減少灶挟。 開發(fā)這個首頁居然可以0依賴琉朽,沒有什么第三方控件的引入,也沒有去找控件的煩惱稚铣。這里需要注意的是箱叁,很多人擔(dān)心Compose沒有那么多開源框架,其實這個擔(dān)心是多余的惕医。因為Compose簡化了布局的實現(xiàn)耕漱,已經(jīng)不需要那些什么約束布局和線性布局的思路了,也不需要什么UI庫抬伺,萬物皆組合螟够。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市峡钓,隨后出現(xiàn)的幾起案子妓笙,更是在濱河造成了極大的恐慌,老刑警劉巖能岩,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寞宫,死亡現(xiàn)場離奇詭異,居然都是意外死亡拉鹃,警方通過查閱死者的電腦和手機(jī)辈赋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門鲫忍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钥屈,你說我怎么就攤上這事悟民。” “怎么了篷就?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵射亏,是天一觀的道長。 經(jīng)常有香客問我竭业,道長鸦泳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任永品,我火速辦了婚禮做鹰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鼎姐。我一直安慰自己钾麸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布炕桨。 她就那樣靜靜地躺著饭尝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪献宫。 梳的紋絲不亂的頭發(fā)上钥平,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機(jī)與錄音姊途,去河邊找鬼涉瘾。 笑死,一個胖子當(dāng)著我的面吹牛捷兰,可吹牛的內(nèi)容都是我干的立叛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼贡茅,長吁一口氣:“原來是場噩夢啊……” “哼秘蛇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起顶考,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤赁还,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后驹沿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艘策,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年甚负,在試婚紗的時候發(fā)現(xiàn)自己被綠了柬焕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡梭域,死狀恐怖斑举,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情病涨,我是刑警寧澤富玷,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站既穆,受9級特大地震影響赎懦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜幻工,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一励两、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囊颅,春花似錦当悔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胳挎,卻和暖如春饼疙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背慕爬。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工窑眯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人医窿。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓伸但,卻偏偏與公主長得像,于是被迫代替她去往敵國和親留搔。 傳聞我的和親對象是個殘疾皇子更胖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345