Compose项目依赖配置
compose_ui_version = '1.4.3'
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
//app build.gradle
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
implementation("io.coil-kt:coil-compose:2.4.0")
implementation "io.coil-kt:coil-svg:2.4.0" // Gradle
//landscapist可以缩放,coil是转换成位图显示无法无损缩放
implementation "com.github.skydoves:landscapist-coil:1.3.2"
1. Button
@Composable
fun ButtonStateDemo() {
//记录按压状态
val interactionState = remember {
MutableInteractionSource()
}
val (text, textColor, buttonColor) = when {
//判断是否是按压状态
interactionState.collectIsPressedAsState().value -> {
ButtonState("press", Color.White, Color.Blue)
}
else -> {
ButtonState("unPress", Color.Black, Color.Green)
}
}
Button(
onClick = { /*TODO*/ },
modifier = Modifier.background(buttonColor),
interactionSource = interactionState
) {
Icon(Icons.Filled.Favorite, null, modifier = Modifier.size(ButtonDefaults.IconSize))
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
Text(text = text, color = textColor)
}
}
data class ButtonState(var text: String, var textColor: Color, var buttonColor: Color)
2. Card
Card
是 Compose 中一个布局组件,我们用它可以来创造出一些类似于卡片界面
@Composable
fun CardDemo() {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)//外边距
.clickable {
// 设置点击波纹效果,注意如果 CardDemo() 函数不在 MaterialTheme 下调用
// 将无法显示波纹效果
},
// 设置阴影
elevation = 10.dp
) {
Column(
modifier = Modifier
.fillMaxWidth()
//内边距
.padding(10.dp)
) {
Text(
text = buildAnnotatedString {
append("欢迎来到")
withStyle(
style = SpanStyle(
fontWeight = FontWeight.W900,
color = Color.Magenta
)
) {
append("Jetpack Compose")
}
})
Text(text = buildAnnotatedString {
append("你现在学习的章节是")
withStyle(style = SpanStyle(fontWeight = FontWeight.W900, color = Color.Green)) {
append("Card")
}
})
}
}
3.Icon
Icon 组件用于帮助开发者显示一系列的小图标。Icon 组件支持三种不同类型的图片设置:
Icon(imageVector = ImageVector.vectorResource(
id = R.drawable.ic_svg, contentDescription = "矢量图资源")
Icon(bitmap = ImageBitmap.imageResource(
id = R.drawable.ic_png), contentDescription = "图片资源")
Icon(painter = painterResource(
id = R.drawable.ic_both), contentDescription = "任意类型资源")
Material 自带的包仅有一些常用的图标,如需使用其他所有的 Material 图标,可以添加依赖项,
implementation "androidx.compose.material:material-icons-extended:$compose_version"
Icon加载资源图片显示黑色没有加载出图片?别慌,因为默认的tint模式是AmbientContentColor.current,我们需要去掉它默认的着色模式,所以需要将tint的属性设置为Color.Unspecified
@Composable
fun IconDemo() {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.visual_pwd),
contentDescription = null,
tint = Color.Unspecified
)
}
4. IconButton
IconButton
是一个可点击的图标,用于表示动作(复制,粘贴,保存,等等)。IconButton
的整体最小触摸目标尺寸为 48 x 48dp,以满足无障碍准则。content
会在IconButton
内居中。
content
通常应该是一个图标,使用androidx.compose.material.icons.Icons
中的一个图标。如果使用自定义图标,请注意内部图标的典型尺寸是 24 x 24 dp。
@Composable
fun IconButtonDemo() {
Row {
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Filled.Search, null)
}
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Filled.ArrowBack, null)
}
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Filled.Done, null)
}
}
}
有些时候我们想要取消按钮点击所产生的波纹要怎么办?
IconButton
的源码中其实将Box
里的modifier.clickable
参数Indication
设置成波纹了,那我们只需要复制源码的代码添加到自己的项目中,并且将indication
设置为null
就好了
@Composable
fun MyIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) {
// 这也是源码的一部分
val IconButtonSizeModifier = Modifier.size(48.dp)
Box(
modifier = modifier
.clickable(
onClick = onClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = null
)
.then(IconButtonSizeModifier),
contentAlignment = Alignment.Center
) { content() }
}
5.!!! Image
Image
可以帮我们加载一张图片。我们可以使用Surface
来帮助我们设置形状,或者在 Image 组件中使用 modifier.clip() 来裁剪形状。
@Composable
fun ImageDemo() {
Surface(
//修改形状
shape = CircleShape,
//利用 Surface 中的 border 参数来设置边框
border = BorderStroke(2.dp,Color.Green)
) {
Image(
painter = painterResource(id = R.drawable.car2),
contentDescription = null,
modifier = Modifier.size(350.dp),//.clip(CircleShape)
//默认fit模式缩放
contentScale = ContentScale.Crop
)
}
}
使用 Coil 来动态加载图片,Compose 自带的
Image
只能加载资源管理器中的图片文件,如果想加载网络图片或者是其他本地路径下的文件,则需要考虑其他的库,比如 [Coil](Jetpack Compose - Coilimplementation("io.coil-kt:coil-compose:2.4.0")
Image(
painter = rememberAsyncImagePainter(model = "https://kuriname.com/wp-content/uploads/2019/07/Doupo-Cangqiong-Season-3-Episode-3.jpg"),
contentDescription = null,
)
//直接使用Coil库控件
AsyncImage(model = "https://kuriname.com/wp-content/uploads/2019/07/Doupo-Cangqiong-Season-3-Episode-3.jpg", contentDescription = null)
//如果需要自定义尺寸
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(imageUrl)
.size(480, 320)
.build(),
contentDescription = null,
contentScale = ContentScale.Crop
)
加载 Svg 图像
添加依赖
implementation "io.coil-kt:coil-svg:2.4.0" // Gradle
implementation("io.coil-kt:coil-svg:2.4.0") // KTS
//landscapist可以缩放,coil是转换成位图显示无法无损缩放
implementation "com.github.skydoves:landscapist-coil:1.3.2"
@Composable
fun ImageSvgDemo() {
val context = LocalContext.current
val imageLoader = ImageLoader.Builder(context)
.components {
add(SvgDecoder.Factory())
}
.build()
var flag by remember { mutableStateOf(false) }
val size by animateDpAsState(targetValue = if(flag) 450.dp else 50.dp)
CoilImage(
imageModel = "https://www.svgrepo.com/show/71379/square-root-of-x-math-formula.svg",
contentDescription = null,
modifier = Modifier
.size(size)
.clickable(
onClick = {
flag = !flag
},
indication = null,
interactionSource = MutableInteractionSource()
),
imageLoader = imageLoader
)
}
6.TextField -> EditText
无边框的输入框
TextField
@Composable
fun TextField() {
val input = remember { mutableStateOf("") }
var isHidden by remember { mutableStateOf(true) }
//rememberSaveable与remember相似,但存储的值将使用保存的实例状态机制
// 在活动或进程重新创建后继续存在(例如,在 Android 应用程序中旋转屏幕时会发生这种情况)。
var isError by rememberSaveable { mutableStateOf(false) }
fun validate(text: String) {
isError = text.count() < 8
}
TextField(
modifier = Modifier
.width(200.dp)
.height(60.dp)
.background(Color.White)
.padding(all = 3.dp),
value = input.value,
onValueChange = {
input.value = it
},
//单行显示,设置后maxLines失效
singleLine = true,
//是否显示密码形态
visualTransformation = if (isHidden) PasswordVisualTransformation() else VisualTransformation.None,
//输入框形状
shape = MaterialTheme.shapes.small,
colors = TextFieldDefaults.textFieldColors(
textColor = Color.Black, //光标颜色
cursorColor = Color.Blue
),
//没有输入时显示hint
// placeholder = {
// Text(text = "请输入密钥", fontSize = 16.sp)
// },
// 是否可用,如果为false,将不可选中,不可输入,呈现出禁用状态
enabled = true,
//是否只读,如果是true,则不可编辑,但是可以选中,可以触发复制
readOnly = false,
//文本样式,和Text的TextStyle是一样的
textStyle = TextStyle.Default,
//显示在文本字段内的可选标签
label = { Text(if (isError) "长度不能少于8位" else "请输入密码") },
//输入内容是否错误,如果为true,则label,Icon等会相应的展示错误的显示状态
isError = isError,
//ImeAction
keyboardActions = KeyboardActions { validate(input.value) },
//软件键盘选项
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Password),
//输入框头部显示icon
//leadingIcon = { },
//输入框末尾显示icon
trailingIcon = {
IconButton(onClick = {
isHidden = !isHidden
}) {
Icon(
imageVector = ImageVector.vectorResource(id = if (isHidden) R.drawable.unvisual_pwd else R.drawable.visual_pwd),
contentDescription = if (isHidden) "不显示密钥" else "显示密钥",
modifier = Modifier
.width(20.dp)
.padding(horizontal = 3.dp)
)
}
},
)
}
有边框的输入框
OutlinedTextField
@Composable
fun InputTextBorder() {
Column(Modifier.statusBarsPadding()) {
var text by remember { mutableStateOf("") }
//带边框的输入框
OutlinedTextField(
value = text,
onValueChange = { text = it },
placeholder = { Text(text = "请输入搜索关键字", color = Color.LightGray, fontSize = 12.sp) },
modifier = Modifier
.padding(horizontal = 5.dp)
.fillMaxWidth()
.background(Color.White),
singleLine = true,
leadingIcon = {
Image(
painter = painterResource(id = R.drawable.car2),
contentDescription = "图标",
modifier = Modifier.size(20.dp)
)
},
shape = RoundedCornerShape(12.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.DarkGray, //有焦点的边框颜色
unfocusedBorderColor = Color.LightGray, //无焦点的边框颜色
cursorColor = Color.Blue
),
)
}
}
BasicTextField可以实现高度自定义编辑框
@Composable
@Preview
fun BasicTextFieldDemo(){
var text by remember { mutableStateOf("") }
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFFD3D3D3)),
contentAlignment = Alignment.Center
) {
BasicTextField(
value = text,
onValueChange = {
text = it
},
modifier = Modifier
.background(Color.White, CircleShape)
.height(35.dp)
.fillMaxWidth(),
decorationBox = { innerTextField ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(horizontal = 10.dp)
) {
IconButton(
onClick = { }
) {
Icon(painterResource(id = R.drawable.visual_pwd), null, tint = Color.Unspecified)
}
Box(
modifier = Modifier.weight(1f),
contentAlignment = Alignment.CenterStart
) {
innerTextField()
}
IconButton(
onClick = { },
) {
Icon(Icons.Filled.Send, null)
}
}
}
)
}
}
7.Slider -> ProgressBar
Slider
反映了一个沿条的数值范围,用户可以从中选择一个单一的数值。它们是调整音量、亮度或应用图像过滤器等设置的理想选择。
@Composable
fun Slider(){
var progress by remember{ mutableStateOf(0f)}
Slider(
value = progress,
colors = SliderDefaults.colors(
thumbColor = Color.White, // 圆圈的颜色
activeTrackColor = Color.Blue
),
onValueChange = {
progress = it
},
)
}
8. Text ->TextView
@Composable
fun Text() {
Column(modifier = Modifier.fillMaxWidth().background(Color.White)) {
Text(
//从res加载文字,stringResource(id = R.string.content)
// text = "这是一个标题,不是很长",
//如果我们想让一个 Text 语句中使用不同的样式,比如粗体提醒,特殊颜色
//则我们需要使用到 AnnotatedString
text = buildAnnotatedString {
append("你好:")
withStyle(SpanStyle(Color.Green, fontWeight = FontWeight.W900)) {
append("\"特殊格式\"")
}
},
style = MaterialTheme.typography.h6,//配置文本的行高,颜色,粗体等设置
maxLines = 1,
letterSpacing = 7.sp,//文字间距
overflow = TextOverflow.Ellipsis, //文字溢出
textAlign = TextAlign.Left,//设置文本对齐方式
fontFamily = FontFamily.Serif,//可以自定义字体
// 你也可以加载 res/font 下的字体
// fontFamily = FontFamily(
// Font(R.font.pingfang, FontWeight.W700)
// )
//有的时候也许您需要将文本当作按钮,那么只需要添加 Modifier.clickable 即可
modifier = Modifier
.clickable(
onClick = {},
//以下两条取消波纹效果
indication = null,
interactionSource = MutableInteractionSource()
)
//设置底色
.background(Color.LightGray)
)
//可点击的text,文字超链接,按下标返回,打字效果还行
ClickableText(text = buildAnnotatedString {
withStyle(SpanStyle(Color.Blue, fontWeight = FontWeight.W900)) {
append("用户协议")
}
}, onClick = { offset ->
Log.d("lgf", "Hi,你按到了第 $offset 位的文字")
})
//默认情况下 Text 并不能进行复制等操作,我们需要设置 SelectionContainer 来包装 Text
SelectionContainer(modifier = Modifier.fillMaxWidth()) {
Text(
text = "这段文字可以复制",
modifier = Modifier
.width(200.dp)
.background(Color.Magenta),
textAlign = TextAlign.Center
)
}
//文字强调效果,Material Design 建议采用不同的不透明度来传达这些不同的重要程度,你可以通过 LocalContentAlpha 实现此功能
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Text("这里是禁用后的效果")
}
}
}
9. Box ->FrameLayout
Box 是一个能够将里面的子项依次按照顺序堆叠的布局组件
fun BoxDemo(){
Box(
modifier = Modifier
.size(300.dp)
.background(Color(140, 67, 86)),
//很有用,嵌套操作子控件位置
contentAlignment = Alignment.Center
) {
Text(text = "Hello World")
}
}
10. Row
Row 组件能够将里面的子项按照从左到右的方向水平排列。和 Column 组件一起配合,我们可以构建出很丰富的界面。
@Composable
fun RowDemo() {
Row(
modifier = Modifier.fillMaxWidth(),
//horizontalArrangement 参数帮助我们合理地分配了按钮的水平位置
horizontalArrangement = Arrangement.SpaceBetween
) {
IconButton(
onClick = { /*TODO*/ }
) {
Icon(Icons.Filled.Favorite, null)
}
IconButton(
onClick = { /*TODO*/ },
) {
Icon(painterResource(id = R.drawable.visual_pwd), null)
}
IconButton(
onClick = { /*TODO*/ },
) {
Icon(Icons.Filled.Share, null)
}
}
}
11. Column
Column 是一个布局组件,它能够将里面的子项按照从上到下的顺序垂直排列,
verticalArrangment
和horizontalAlignment
参数分别可以帮助我们安排子项的垂直/水平位置,在默认的情况下,子项会以垂直方向上靠上(Arrangment.Top),水平方向上靠左(Alignment.Start)来排布。
12. Flow Layout
Flow Layout 在 Compose 1.4 中“转正”。在此之前,你需要使用 Accompanist 的实现
@Composable
fun FlowLayoutDemo() {
val filters = listOf(
"Washer/Dryer", "Ramp access", "Garden", "Cats OK", "Dogs OK", "Smoke-free"
)
FlowRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
filters.forEach { title ->
var selected by remember { mutableStateOf(false) }
val leadingIcon: @Composable () -> Unit = { Icon(Icons.Default.Check, null) }
FilterChip(
selected,
onClick = { selected = !selected },
leadingIcon = if (selected) leadingIcon else null
){
Text(text = title)
}
}
}
}
13. Surface
Surface 从字面上来理解,是一个平面,在
Material Design
设计准则中也同样如此,我们可以将很多的组件摆放在这个平面之上,我们可以设置这个平面的边框,圆角,颜色等等。接下来,我们来用 Surface 组件做出一些不同的效果。
Surface(
shape = RoundedCornerShape(8.dp),
elevation = 10.dp,
modifier = Modifier
.width(300.dp)
.height(100.dp),
//改变圆角内部分
color = Color.LightGray,
//会改变文字颜色
contentColor = Color.Yellow
) {
Row(
modifier = Modifier
.clickable {}
) {
Image(
painter = painterResource(id = R.drawable.car2),
contentDescription = stringResource(R.string.app_name),
modifier = Modifier.size(100.dp),
contentScale = ContentScale.Crop
)
Spacer(Modifier.padding(horizontal = 12.dp))
Column(
modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.Center
) {
Text(
text = "Liratie",
style = MaterialTheme.typography.h6
)
Spacer(Modifier.padding(vertical = 8.dp))
Text(
text = "礼谙"
)
}
}
}
14. Scaffold
@Composable
fun ScaffoldDemo() {
var selectedItem by remember { mutableStateOf(0) }
val items = listOf("主页", "我喜欢的", "设置")
Scaffold(
topBar = {
TopAppBar(
title = {
Text("主页")
},
navigationIcon = {
IconButton(
onClick = { } //do something
) {
Icon(Icons.Filled.ArrowBack, null)
}
},
actions = {
IconButton(
onClick = { } //do something
) {
Icon(Icons.Filled.Search, null)
}
IconButton(
onClick = { } //do something
) {
Icon(Icons.Filled.MoreVert, null)
}
}
)
},
bottomBar = {
BottomNavigation {
items.forEachIndexed { index, item ->
BottomNavigationItem(
icon = {
when (index) {
0 -> Icon(Icons.Filled.Home, contentDescription = null)
1 -> Icon(Icons.Filled.Favorite, contentDescription = null)
else -> Icon(Icons.Filled.Settings, contentDescription = null)
}
},
label = { Text(item) },
selected = selectedItem == index,
onClick = { selectedItem = index }
)
}
}
}
) {
}
}
15. Pager ->ViewPager
Pager
即传统 View 体系中ViewPager
的替代,但在使用上大大降低了复杂度。它包括VerticalPager
和HorizontalPager
两类,分别对应纵向和横向的滑动。Pager
的底层基于 LazyColumn/LazyRow 实现,在使用上也基本与它们等同
HorizontalPager(pageCount = 10) { page ->
// 每一页的内容,比如显示个文本
Text(
text = "Page: $page",
modifier = Modifier.fillMaxWidth().height(100.dp),
color = Color.Blue
)
}
待补充
16. Animation
animate*AsState
函数是Compose
中最简单的动画API
,用于为单个值制作动画。你只需提供结束值(或目标值),API 就会从当前值到指定值开始动画。
Compose
为Float
、Color
、Dp
、Size
、Bounds
、Offset
、Rect
、Int
、IntOffset
和IntSize
提供animate*AsState
函数。通过为带有通用类型的animateValueAsState
提供TwoWayConverter
,可以轻松添加对其他数据类型的支持。
@Composable
fun AnimationDemo() {
var change by remember{ mutableStateOf(false) }
var flag by remember{ mutableStateOf(false) }
val buttonSize by animateDpAsState(
targetValue = if(change) 32.dp else 24.dp
)
if(buttonSize == 32.dp) {
change = false
}
IconButton(
onClick = {
change = true
flag = !flag
}
) {
Icon(Icons.Rounded.Favorite,
contentDescription = null,
modifier = Modifier.size(buttonSize),
tint = if(flag) Color.Red else Color.Gray
)
}
}
Animatable
是一个能够提供初始值的基础API
,animate*AsState
系列 API 其内部均使用Animatable
定制完成的。当你希望对自定义的数据类型进行动画计算时,可以选择使用Animatable
来完成,使用Animatable重新实现上述案例
var change by remember{ mutableStateOf(false) }
var flag by remember{ mutableStateOf(false) }
//在 Composable 使用 Animatable 时,其必须包裹在 rememebr 中
val buttonSizeVariable = remember {
Animatable(24.dp, Dp.Companion.VectorConverter)
}
LaunchedEffect(change) {
buttonSizeVariable.animateTo(if(change) 32.dp else 24.dp)
}
if(buttonSizeVariable.value == 32.dp) {
change = false
}
IconButton(
onClick = {
change = true
flag = !flag
}
) {
Icon(
Icons.Rounded.Favorite,
contentDescription = null,
modifier = Modifier.size(buttonSizeVariable.value),
tint = if(flag) Color.Red else Color.Gray
)
}
updateTransiton
是 Jetpack Compose 中实现过渡动画的关键 API 。所谓过渡动画,即当依赖的某个状态发生改变时连锁发生的一系列动画效果。前面我们所提到的AnimateState
与Animatable
都是针对一个属性进行变换的,而updateTransition
允许开发者将多个属性数值绑定到一个状态,当这个状态发生改变时,多个属性同时进行变换。
@Composable
fun SwitchBlock(){
var selectedState: SwitchState by remember { mutableStateOf(SwitchState.CLOSE) }
val transition = updateTransition(selectedState, label = "switch_transition")
val selectBarPadding by transition.animateDp(transitionSpec = { tween(1000) }, label = "") {
when (it) {
SwitchState.CLOSE -> 40.dp
SwitchState.OPEN -> 0.dp
}
}
val textAlpha by transition.animateFloat(transitionSpec = { tween(1000) }, label = "") {
when (it) {
SwitchState.CLOSE -> 1f
SwitchState.OPEN -> 0f
}
}
Box(
modifier = Modifier
.size(150.dp)
.padding(8.dp)
.clip(RoundedCornerShape(10.dp))
.clickable {
selectedState = if (selectedState == SwitchState.OPEN) SwitchState.CLOSE else SwitchState.OPEN
}
) {
Image(
painter = painterResource(id = R.drawable.car2),
contentDescription = "node_background",
contentScale = ContentScale.FillBounds
)
Text(
text = "点我",
fontSize = 30.sp,
fontWeight = FontWeight.W900,
color = Color.White,
modifier = Modifier
.align(Alignment.Center)
.alpha(textAlpha)
)
Box(modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.height(40.dp)
.padding(top = selectBarPadding)
.background(Color(0xFF5FB878))
) {
Row(modifier = Modifier
.align(Alignment.Center)
.alpha(1 - textAlpha)
) {
Icon(painter = painterResource(id = R.drawable.visual_pwd), contentDescription = "star", tint = Color.White)
Spacer(modifier = Modifier.width(2.dp))
Text(
text = "已选择",
fontSize = 20.sp,
fontWeight = FontWeight.W900,
color = Color.White
)
}
}
}
}
17. 自定义主题方案
18. 手势识别
当需要更大灵活性时,您可以通过
pointerInput
修饰符提供点按手势检测器
Image(
painter = painterResource(id = R.drawable.car2),
contentDescription = null,
modifier = Modifier.size(300.dp).pointerInput(Unit){
detectTapGestures(
onPress = {
Log.i("lgf","onPress")
},
onDoubleTap = {Log.i("lgf","onDoubleTap")},
onTap = {Log.i("lgf","onTap")},
onLongPress = {Log.i("lgf","onLongPress")}
)
}
)
对于长按点击、双击等复合类点击手势,我们可以使用
CombinedClickable
修饰符来实现手势监听。与 Clickable 修饰符一样,他同样也可以监听单击手势,并且也会为被点击的组件施加一个波纹涟漪效果动画的蒙层。
val enableState by remember {
mutableStateOf<Boolean>(true)
}
Image(
painter = painterResource(id = R.drawable.car2),
contentDescription = null,
modifier = Modifier
.size(300.dp)
.combinedClickable(enabled = enableState, onLongClick = {
Log.i("lgf","onLongClick")
}, onDoubleClick = {
Log.i("lgf","onDoubleClick")
}) {
Log.i("lgf","onClick")
}
)
个人感觉双击有点问题
2.如何获取context
LocalContext.current
3.类似RecycleView的item点击事件处理
函数类型参数传递到Item中