Jetpack Compose - Chat Interface
foreword
At present, declarative UI has become the trend of front-end development. In addition to the initial cross-end development of React, Flutter, etc. and Web support, subsequent Android and IOS platforms have also launched declarative development. Android is developed through Jetpack Compose and Kotlin’s powerful language features. , completely get rid of the imperative use of XML files for UI layout
effect video
Android Jetpack - a simple chat interface
introduce
Before code analysis, introduce several common layouts
Row
horizontal
Similar to the arrangement of LinearLayout in Android , it is consistent with Flutter's Row.
Modifier basically performs most of the configuration work of a component. It implements a series of extension functions internally and realizes then
chain calls through functions. verticalAlignment
The attribute is vertical alignment and horizontalArrangement
horizontal alignment
Row(
modifier = Modifier.padding(all = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start
) {
//some sub views
}
Column
Except for the arrangement of Column and Row, the rest are roughly the same, similar to the vertical
arrangement of LinearLayout
Column(
modifier = Modifier.weight(1f),
horizontalAlignment = Alignment.End
){
//some sub views
}
Text
Text box, similar to Android TextView
, text
the attribute is the text content, color
the attribute is the text color, style
the attribute is the text style, you can set the text size, whether it is bold, the style, etc., the system has many built-in styles, and the textAlign
attribute is the text alignment
Text(
text = msg.author,
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodySmall,
textAlign = TextAlign.Right
)
Image
Equivalent to Android ImageView
, painter
you can directly configure the image address (drawable) through painterResource, and modifier
we can directly modify the attributes of the image such as rounded corners, borders, and size through attributes, so there is no need to create an xml file to configure
Image(
painter = painterResource(id = msg.img),
contentDescription = "",
modifier = Modifier
.size(40.dp)
.clickable { CircleShape }
.border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)
)
chat interface
By LazyColumn
implementing a vertical list, the data is fixed data, and the subscripts are located at the left and right ends of the layout, and then the default text displays one line. After clicking on the line of text, the text content will be expanded and its background color will be changed. This Demo adapted from the official
Effect
left layout
Only by adding @Composable
annotations can the declarative UI be used. The declarative UI adopts a tree structure. In this example, Row is the root node of the tree and has two child nodes, namely and (the space placeholder in the middle is omitted), Image
and Column
then Column
It also has two child nodes, namely Surface
and Text
, which Surface
has another Text
child node.
Monitor whether a row is clicked, and then perform background modification mainly through the following, which is equivalent to the observer mode, monitor isExpanded
the field, and then change, it is similar to the observer immediately. The official explanation is as follows:
重组:可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。
该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)
通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
//监听isExpanded字段
var isExpanded by remember { mutableStateOf(false) }
//收缩和扩展对应俩种颜色,由isExpanded字段决定
val surfaceColor by animateColorAsState(
targetValue = if (isExpanded)
Color.Cyan
else
MaterialTheme.colorScheme.surface
)
Finally, add modifier = Modifier .clickable { isExpanded = !isExpanded }
it . Every click will change its value, and then get the node of the value to redraw and update
@Composable
fun MessageLeft(msg : Message){
Row(
modifier = Modifier.padding(all = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start) {
//图像
Image(
painter = painterResource(id = msg.img),
contentDescription = "",
modifier = Modifier
.size(40.dp)//图像大小
.clip(CircleShape)
.border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)
)
//左右间隔
Spacer(modifier = Modifier.width(10.dp))
//重组:可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。
// 该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)
//通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
var isExpanded by remember { mutableStateOf(false) }
val surfaceColor by animateColorAsState(
targetValue = if (isExpanded)
Color.Cyan
else
MaterialTheme.colorScheme.surface
)
Column() {
Text(
text = msg.author,
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodySmall
)
//上下间隔
Spacer(modifier = Modifier.height(10.dp))
Surface(
shape = RectangleShape,
shadowElevation = 1.dp,
tonalElevation = 1.dp,
color = surfaceColor,
modifier = Modifier
.animateContentSize()
.padding(1.dp)
) {
Text(
text = msg.content,
modifier = Modifier
.clickable { isExpanded = !isExpanded }
.padding(all = 4.dp),
maxLines = if (isExpanded) Int.MAX_VALUE else 1,
style = MaterialTheme.typography.bodyMedium,
overflow = TextOverflow.Ellipsis
)
}
}
}
}
right layout
horizontalArrangement
The right side is similar to the left side, the difference is that the arrangement is changed so that it is arranged on the right side, and then a weight attribute is added to the text modifier = Modifier.weight(1f),
to prevent the line from having too much content and squeeze the right image out of the screen
@Composable
fun MessageRight(msg: Message){
Row(
modifier = Modifier
.padding(10.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End) {
//给左边文字一个权重,避免文字过多,让右边图像无法显示
Column(
modifier = Modifier.weight(1f),
horizontalAlignment = Alignment.End
) {
Text(
text = msg.author,
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodySmall,
textAlign = TextAlign.Right
)
Spacer(modifier = Modifier.height(10.dp))
var isExpanded by remember { mutableStateOf(false) }
val surfaceColor by animateColorAsState(
targetValue = if (isExpanded)
Color.Green
else
MaterialTheme.colorScheme.surface
)
Surface(
shape = RectangleShape,
shadowElevation = 1.dp,
tonalElevation = 1.dp,
color = surfaceColor,
modifier = Modifier
.animateContentSize()
.padding(1.dp)
) {
Text(
text = msg.content,
modifier = Modifier
.clickable { isExpanded = !isExpanded }
.padding(all = 4.dp),
maxLines = if (isExpanded) Int.MAX_VALUE else 1,
style = MaterialTheme.typography.bodyMedium,
overflow = TextOverflow.Ellipsis
)
}
}
Spacer(modifier = Modifier.width(10.dp))
Image(
painter = painterResource(id = msg.img),
contentDescription = "",
modifier = Modifier
.size(40.dp)
.clickable { CircleShape }
.border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)
)
}
}
insert data
Is it equivalent to Android XML RecyclerView
, is it very simple, no need to write Adapter
and sub-item XMl files and a lot of interfaces or something
@Composable
fun ShowMessage(msgList: List<Message>){
//竖向列表
LazyColumn{
itemsIndexed(items = msgList){
index, item ->
if (index %2 == 0)
MessageLeft(msg = item)
else
MessageRight(msg = item)
}
}
}
Summarize
The Jetpack Compose declarative UI may not be used at first, but after getting used to it, it will take off directly, greatly improving development efficiency and reducing development time, and most of the front-ends use declarative UI. Kung fu, such as Flutter, the two are basically similar in terms of UI, except that Flutter is divided into three parts , , and , through Widget
nesting , and judges whether the node is modified by and , so as to judge whether it needs to be redrawn. Finally, I suggest you Android developers to use it. Android Jetpack Compose has been out for almost a year, and it is gradually stabilizing.Widget
Element
RenderObject
runtimetype
key