如何从 onScrollPositionChanged 回调中更改 VerticalScroller 的 scrollerPosition?
How can I alter VerticalScroller's scrollerPosition from onScrollPositionChanged callback?
正如下面的代码所示,我有一个回调,我想在其中收集 VerticalScroller
的位置,但如果我这样做,VerticalScrollers 小部件将不再滚动,因为在源代码中 VerticalScroller
,初始回调调用了 VerticalScroller
的 scrollerPosition
。无法从我要使用它的回调中访问该值。有没有快速调用 scrollerPosition
或使滚动行为继续的方法? (不创建递归 "race" 条件?)
@Composable
fun StationsScreen(deviceLocation: LocationData, openDrawer: () -> Unit)
{
var scrollPosition = ScrollPosition(0.px,0.px)
FlexColumn {
inflexible {
TopAppBar(
title = {Text(text = "Stations")},
navigationIcon = {
VectorImageButton(id = R.drawable.ic_baseline_menu_24) {
openDrawer()
}
}
)
}
inflexible {
Column (
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
LocationWidget(deviceLocation)
}
}
inflexible {
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
PushWidget(){
deviceLocation.lat++
deviceLocation.lng++
}
}
}
inflexible{
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
) {
ScrollPosWidget(scrollPosition = scrollPosition)
}
}
flexible(flex = 1f)
{
VerticalScroller (onScrollPositionChanged = { px: Px, px1: Px ->
scrollPosition.posX = px
scrollPosition.maxX = px1
}){
Column {
for(i in 0..20) {
HeightSpacer(16.dp)
imageBank.forEach { imageItem: ImageItem ->
Text(text = imageItem.title ?: "<Empty>")
Divider()
}
}
}
}
}
}
}
--- compose源码中VerticalScroller Widget的定义:
@Composable
fun VerticalScroller(
scrollerPosition: ScrollerPosition = +memo { ScrollerPosition() },
onScrollPositionChanged: (position: Px, maxPosition: Px) -> Unit = { position, _ ->
scrollerPosition.value = position
},
isScrollable: Boolean = true,
@Children child: @Composable() () -> Unit
) {
Scroller(scrollerPosition, onScrollPositionChanged, true, isScrollable, child)
}
实际上我找到了解决问题的方法...(我有时被教导要跳出框框思考...)所以...
在我的 @Compose
函数中,我实际上需要创建自己的 scrollerPosition
实例,并在调用 VerticalScroller
时使用它来更改位置。我担心这会导致递归 "race" 调用情况,但这取决于在 Scroller
的逻辑中何时调用 onScrolledPostionChanged
。如果在 scrollerPosition.position
改变值时调用 onScrolledPositionChanged
,您可能会得到递归的 "race" 条件。但显然不是。
所以我的改动基本是这样的:
@Composable
fun StationsScreen(deviceLocation: LocationData, openDrawer: () -> Unit)
{
var scrollPosition = ScrollPosition(0.px,0.px)
var myScrollerPosition = +memo{ ScrollerPosition ()} //<--- make my own scrollerPosition
FlexColumn {
inflexible {
TopAppBar(
title = {Text(text = "Stations")},
navigationIcon = {
VectorImageButton(id = R.drawable.ic_baseline_menu_24) {
openDrawer()
}
}
)
}
inflexible {
Column (
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
LocationWidget(deviceLocation)
}
}
inflexible {
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
PushWidget(){
deviceLocation.lat++
deviceLocation.lng++
}
}
}
inflexible{
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
) {
ScrollPosWidget(scrollPosition = scrollPosition)
}
}
flexible(flex = 1f)
{
VerticalScroller (
scrollerPosition = myScrollerPosition,
onScrollPositionChanged = { px: Px, px1: Px ->
scrollPosition.posX = px
scrollPosition.maxX = px1
myScrollerPosition.value = px //<-- remember to set the new value here
// You can now use the difference of maxX and posX to load
// new items into the list...
}){
Column {
for(i in 0..20) {
HeightSpacer(16.dp)
imageBank.forEach { imageItem: ImageItem ->
Text(text = imageItem.title ?: "<Empty>")
Divider()
}
}
}
}
}
}
}
@Composable
fun LocationWidget(locationData: LocationData){
Surface {
Padding(padding = 8.dp) {
Text(text = "${locationData.lat}, ${locationData.lng}")
}
}
}
@Composable
fun PushWidget(action: () -> Unit){
Surface {
Padding(padding = 8.dp) {
Button(text = "Click Me!", onClick = action)
}
}
}
@Composable
fun ScrollPosWidget(scrollPosition: ScrollPosition){
Surface {
Padding(padding = 8.dp) {
Text(text = "posX=${scrollPosition.posX}, maxX=${scrollPosition.maxX}")
}
}
}
RG
正如下面的代码所示,我有一个回调,我想在其中收集 VerticalScroller
的位置,但如果我这样做,VerticalScrollers 小部件将不再滚动,因为在源代码中 VerticalScroller
,初始回调调用了 VerticalScroller
的 scrollerPosition
。无法从我要使用它的回调中访问该值。有没有快速调用 scrollerPosition
或使滚动行为继续的方法? (不创建递归 "race" 条件?)
@Composable
fun StationsScreen(deviceLocation: LocationData, openDrawer: () -> Unit)
{
var scrollPosition = ScrollPosition(0.px,0.px)
FlexColumn {
inflexible {
TopAppBar(
title = {Text(text = "Stations")},
navigationIcon = {
VectorImageButton(id = R.drawable.ic_baseline_menu_24) {
openDrawer()
}
}
)
}
inflexible {
Column (
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
LocationWidget(deviceLocation)
}
}
inflexible {
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
PushWidget(){
deviceLocation.lat++
deviceLocation.lng++
}
}
}
inflexible{
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
) {
ScrollPosWidget(scrollPosition = scrollPosition)
}
}
flexible(flex = 1f)
{
VerticalScroller (onScrollPositionChanged = { px: Px, px1: Px ->
scrollPosition.posX = px
scrollPosition.maxX = px1
}){
Column {
for(i in 0..20) {
HeightSpacer(16.dp)
imageBank.forEach { imageItem: ImageItem ->
Text(text = imageItem.title ?: "<Empty>")
Divider()
}
}
}
}
}
}
}
--- compose源码中VerticalScroller Widget的定义:
@Composable
fun VerticalScroller(
scrollerPosition: ScrollerPosition = +memo { ScrollerPosition() },
onScrollPositionChanged: (position: Px, maxPosition: Px) -> Unit = { position, _ ->
scrollerPosition.value = position
},
isScrollable: Boolean = true,
@Children child: @Composable() () -> Unit
) {
Scroller(scrollerPosition, onScrollPositionChanged, true, isScrollable, child)
}
实际上我找到了解决问题的方法...(我有时被教导要跳出框框思考...)所以...
在我的 @Compose
函数中,我实际上需要创建自己的 scrollerPosition
实例,并在调用 VerticalScroller
时使用它来更改位置。我担心这会导致递归 "race" 调用情况,但这取决于在 Scroller
的逻辑中何时调用 onScrolledPostionChanged
。如果在 scrollerPosition.position
改变值时调用 onScrolledPositionChanged
,您可能会得到递归的 "race" 条件。但显然不是。
所以我的改动基本是这样的:
@Composable
fun StationsScreen(deviceLocation: LocationData, openDrawer: () -> Unit)
{
var scrollPosition = ScrollPosition(0.px,0.px)
var myScrollerPosition = +memo{ ScrollerPosition ()} //<--- make my own scrollerPosition
FlexColumn {
inflexible {
TopAppBar(
title = {Text(text = "Stations")},
navigationIcon = {
VectorImageButton(id = R.drawable.ic_baseline_menu_24) {
openDrawer()
}
}
)
}
inflexible {
Column (
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
LocationWidget(deviceLocation)
}
}
inflexible {
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
){
PushWidget(){
deviceLocation.lat++
deviceLocation.lng++
}
}
}
inflexible{
Column(
mainAxisSize = LayoutSize.Expand,
crossAxisSize = LayoutSize.Expand
) {
ScrollPosWidget(scrollPosition = scrollPosition)
}
}
flexible(flex = 1f)
{
VerticalScroller (
scrollerPosition = myScrollerPosition,
onScrollPositionChanged = { px: Px, px1: Px ->
scrollPosition.posX = px
scrollPosition.maxX = px1
myScrollerPosition.value = px //<-- remember to set the new value here
// You can now use the difference of maxX and posX to load
// new items into the list...
}){
Column {
for(i in 0..20) {
HeightSpacer(16.dp)
imageBank.forEach { imageItem: ImageItem ->
Text(text = imageItem.title ?: "<Empty>")
Divider()
}
}
}
}
}
}
}
@Composable
fun LocationWidget(locationData: LocationData){
Surface {
Padding(padding = 8.dp) {
Text(text = "${locationData.lat}, ${locationData.lng}")
}
}
}
@Composable
fun PushWidget(action: () -> Unit){
Surface {
Padding(padding = 8.dp) {
Button(text = "Click Me!", onClick = action)
}
}
}
@Composable
fun ScrollPosWidget(scrollPosition: ScrollPosition){
Surface {
Padding(padding = 8.dp) {
Text(text = "posX=${scrollPosition.posX}, maxX=${scrollPosition.maxX}")
}
}
}
RG