我有一个使用 XML 和 Kotlin 制作的现有应用程序。更新时,我想学习 Jetpack Compose,因此我使用 ComposeView 在父 XML 屏幕中添加了一个 HorizontalPager。
在 XML 中
<androidx.compose.ui.platform.ComposeView
android:id="@+id/my_composable"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
然后在 Kotlin 中我做到了
binding.value.myComposable.setContent {
IntroPager()
}
我的撰写功能
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun IntroPager(){
val pagerState = rememberPagerState(pageCount = {
3
})
Box(modifier = Modifier.fillMaxSize()) {
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize()
) { page ->
when (page){
0-> Page1("")
1-> Page2("")
2-> Page3("")
else -> Page1(" from else $page")
}
}
Row(
Modifier
.wrapContentHeight()
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(bottom = 8.dp),
horizontalArrangement = Arrangement.Center
) {
repeat(pagerState.pageCount) { iteration ->
val color =
if (pagerState.currentPage == iteration) Color(R.color.theme_color_secondary) else Color(R.color.dark_grey)
Box(
modifier = Modifier
.padding(2.dp)
.clip(CircleShape)
.background(color)
.size(16.dp)
)
}
}
}
}
现在,基于屏幕 XML 部分中的一些用户交互,我想从 XML onClickListener 传递单击事件,以转到 Compose 中 HorizontalPager 中的下一页。基本上将 XML clickEvent 传递给 Compose。
我找不到任何有关如何实现此目标的文档。
我尝试实现接口回调,但不成功
在
pagerState
的开头定义setContent
并将其作为参数发送给IntroPager
。
var pagerState = rememberPagerState(pageCount = { 3 })
fun IntroPager(pagerState: PagerState)
用它进行页面切换
val scope = rememberCoroutineScope()
scope.launch {
pagerState.scrollToPage(value)
}
您必须在
setContent
之后添加 xml clickListener。否则你会得到这个错误。
@Composable 调用只能在 a 的上下文中发生 @可组合
我能想到的唯一可行的解决方案是使用共享 ViewModel。这是我所做的:
我创建了一个 ViewModel 类,其中包含增加页面索引的函数:
class PagerViewModel : ViewModel() {
val page = mutableIntStateOf(0)
fun nextPage(){
if (page.value<=2)
page.value++
}
}
然后我在我的父 Activity 中链接了这个 ViewModel。对于 XML 中的点击事件,我调用了
pagerViewModel.nextPage()
函数。
然后在我的 Compose 代码中:
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun IntroPager(pagerViewModel: PagerViewModel){
val pagerState = rememberPagerState(pageCount = {
3
})
Box(modifier = Modifier.fillMaxSize()) {
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize()
) { page ->
Log.d("IntroPager", "IntroPager: "+pagerViewModel.page.value)
when (page){
0-> {
Page1("")
}
1-> {
Page2("")
}
2-> {
Page3("")
}
else -> Page1(" from else $page")
}
}
Row(
Modifier
.wrapContentHeight()
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(bottom = 8.dp),
horizontalArrangement = Arrangement.Center
) {
repeat(pagerState.pageCount) { iteration ->
val color =
if (pagerState.currentPage == iteration) Color(R.color.theme_color_secondary) else Color(R.color.dark_grey)
Box(
modifier = Modifier
.padding(2.dp)
.clip(CircleShape)
.background(color)
.size(16.dp)
)
}
}
LaunchedEffect(pagerViewModel.page.value) {
pagerState.animateScrollToPage( pagerViewModel.page.value)
}
LaunchedEffect(pagerState){
snapshotFlow { pagerState.currentPage }.collect { page ->
pagerViewModel.page.intValue = page
}
}
}
}
这会将 ViewModel 页面索引链接到 HorizontalPager 状态。
LaunchedEffect(pagerViewModel.page.value) {}
每当 pageIndex 的值发生变化时启动协程,它会以动画方式滚动到该页面。
我想要一种直接的方法来连接 XML 和 Compose 之间的单击事件。但我找不到简单的解决方案,所以我求助于使用共享 ViewModel 来更新状态。