jetpack compose实战——基本框架搭建

前言

  • 项目地址:https://github.com/Peakmain/ComposeProject
  • 网上现在有不少jetpack compose的文章和教程,但是实战项目不多。
  • 项目接口基于玩Android,这里也非常感谢大佬提供的免费接口

建议
先学习kotlin语言,最好有Android App开发经验

项目结构

新建项目New Project->选择 Empty Compose Activity


image.png

填写必要信息,完成项目创建


image.png
Compose和Android View的区别
Android View compose
Button Button
TextView Text
EditText TextField
ImageView Image
LinearLayout(horizontally) Row
LinearLayout(vertically) Column
FrameLayout Box
RecyclerView LazyColumn
RecyclerView(horizontally) LazyRow
Snackbar Snackbar

一些基础知识

Scaffold
@Composable
fun Scaffold(
    modifier: Modifier = Modifier,
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    topBar: @Composable () -> Unit = {},
    bottomBar: @Composable () -> Unit = {},
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
    floatingActionButton: @Composable () -> Unit = {},
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    isFloatingActionButtonDocked: Boolean = false,
    drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
    drawerGesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    drawerScrimColor: Color = DrawerDefaults.scrimColor,
    backgroundColor: Color = MaterialTheme.colors.background,
    contentColor: Color = contentColorFor(backgroundColor),
    content: @Composable (PaddingValues) -> Unit
) 

Scaffold主要用于快速搭建一个项目的结构,包含:

  • topBar:通常是TopAppBar
  • bottomBar 通常是一个 BottomNavigation,里面每个item是BottomNavigationItem
  • floatingActionButton 悬浮按钮
  • floatingActionButtonPosition 悬浮按钮位置
  • isFloatingActionButtonDocked 悬浮按钮是否贴到 bottomBar 上
  • drawerContent 侧滑菜单
  • content:内容区域
BottomNavigationItem
fun RowScope.BottomNavigationItem(
    selected: Boolean,//是否被选中
    onClick: () -> Unit,//点击事件
    icon: @Composable () -> Unit,//icon图标
    modifier: Modifier = Modifier,
    enabled: Boolean = true,//是否可用
    label: @Composable (() -> Unit)? = null,//这里就是文本
    alwaysShowLabel: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    selectedContentColor: Color = LocalContentColor.current,
    unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium)
)
  • selected:是否被选中
  • onClick:点击事件
  • icon:Icon的图标
  • modifier: Modifier
  • enabled:是否可用
  • label:这里就是文本内容区域
  • selectedContentColor:选中时的颜色
  • unselectedContentColor:未选中的颜色
状态
状态和组合

由于 Compose 是声明式工具集,因此更新它的唯一方法是通过新参数调用同一可组合项。这些参数是界面状态的表现形式。每当状态更新时,都会发生重组。因此,TextField 不会像在基于 XML 的命令式视图中那样自动更新。可组合项必须明确获知新状态,才能相应地进行更新

@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       Text(
           text = "Hello!",
           modifier = Modifier.padding(bottom = 8.dp),
           style = MaterialTheme.typography.h5
       )
       OutlinedTextField(
           value = "",
           onValueChange = { },
           label = { Text("Name") }
       )
   }
}
  • OutlinedTextField与 TextField 只是样式不同
  • 如果运行此代码,您将不会看到任何反应。这是因为,TextField 不会自行更新,但会在其 value 参数更改时更新。
Compose中的状态
  • Composable中可以使用remember来记住单个对象。
  • 系统会在初始化由 remember计算的值存储在Composable中,并在重组的时候返回存储的值
  • remember既可以存储可变对象,也可以存储不可变对象。
注意:remember 会将对象存储在组合中,当调用 remember 的可组合项从组合中移除后,它会忘记该对象。

mutableStateOf 会创建可观察的 MutableState<T>,后者是与 Compose 运行时集成的可观察类型。

interface MutableState<T> : State<T> {
    override var value: T
}

value 如有任何更改,系统会安排重组读取 value 的所有可组合函数。

在可组合项中声明 MutableState 对象的方法有三种:

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

这些声明是等效的,以语法糖的形式针对状态的不同用法提供。您选择的声明应该能够在您编写的可组合项中生成可读性最高的代码。

所以上面代码的解决办法

@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       var name by remember { mutableStateOf("") }//👈🏻定义状态
       if (name.isNotEmpty()) {
           Text(
               text = "Hello, $name!",
               modifier = Modifier.padding(bottom = 8.dp),
               style = MaterialTheme.typography.h5
           )
       }
       OutlinedTextField(
           value = name,//👈🏻要显示的当前值
           onValueChange = { name = it },//👈🏻请求更改值的事件,其中 T 是建议的新值
           label = { Text("Name") }
       )
   }
}

小技巧:Compose的代码模板

在搭建基本框架之前,我们先来定义一个模板,方便大家开发(我的是Mac电脑)

  • 1、Android Studio-> Preferences->Editor->File and Code Templates


    image.png
  • 2、点击➕号

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}

#end
#parse("File Header.java")

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

#if (${Function_Name} == "" )
@Composable
fun ${NAME}() {
}

@Preview
@Composable
fun ${NAME}Preview() {
    ${NAME}()
}
#end

#if (${Function_Name} != "" )
@Composable
fun ${Function_Name}() {
}

@Preview
@Composable
fun ${Function_Name}Preview() {
    ${Function_Name}()
}
#end

image.png
  • 3、使用,右击选择New->kotlin compose


    image.png

    image.png

基本框架搭建

效果图


效果图.gif

13.png
  • 1、新建项目,修改MainActivity
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeProjectTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    MainFrame()
                }
            }
        }
    }
}
  • 2、MainFrame
@Composable
fun MainFrame() {
    val navigationItems = listOf(
        NavigationItem("首页", Icons.Default.Home),
        NavigationItem("项目", Icons.Default.Article),
        NavigationItem("分类", Icons.Default.Category),
        NavigationItem("我的", Icons.Default.Person)
    )
    var currentNavigationIndex by remember {
        mutableStateOf(0)
    }
    Scaffold(
        bottomBar = {
            BottomNavigation(backgroundColor = MaterialTheme.colors.surface) {
                navigationItems.forEachIndexed { index, navigationItem ->
                    BottomNavigationItem(
                        selected = currentNavigationIndex == index,
                        onClick = { currentNavigationIndex = index },
                        icon = {
                            Icon(imageVector = navigationItem.icon, contentDescription = null)
                        },
                        label = {
                            Text(text = navigationItem.title)
                        },
                        selectedContentColor = Color_149EE7,
                        unselectedContentColor = Color_999999
                    )
                }
            }
        },
    ) {
        when (currentNavigationIndex) {
            0 -> HomeFragment()
            1 -> ProjectFragment()
            2 -> TypeFragment()
            else -> MineFragment()
        }
    }
}

代码其实很简单,主要通过Scaffold来搭建一个项目结构,用remember+ mutableStateOf来记住状态。内容区域通过选中的index来展示不同的Fragment

implementation "androidx.compose.material:material-icons-extended:$compose_version"

总结

到这里呢,基本框架已经搭完了,其实还是比较简单的。有不动的呢,可以多看看Google官方文档:https://developer.android.google.cn/jetpack/compose

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容