如何将 Click 事件从父 XML 视图传递到 Jetpack Compose 内部

问题描述 投票:0回答:2

我有一个使用 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。

我找不到任何有关如何实现此目标的文档。

我尝试实现接口回调,但不成功

android kotlin android-jetpack-compose android-jetpack
2个回答
0
投票

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 的上下文中发生 @可组合


0
投票

我能想到的唯一可行的解决方案是使用共享 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 来更新状态。

© www.soinside.com 2019 - 2024. All rights reserved.