一、起因:
在开发Android TV,有个场景需要使用TvLazyColum 嵌套 TvLazyVerticalGrid。需要判断焦点,然后滑动到指定位置并改变背景图片实现高斯模糊效果。直接嵌套会运行会报 IllegalStateException异常。
异常如下:
java.lang.IllegalStateException: Vertically scrollable component was measured with an infinity
maximum height constraints, which is disallowed. One of the common reasons is nesting layouts
like LazyColumn and Column(Modifier.verticalScroll()). If you want to add a header before the
list of items please add a header as a separate item() before the main items() inside the LazyColumn
scope. There are could be other reasons for this to happen: your ComposeView was added into a
LinearLayout with some weight, you applied Modifier.wrapContentSize(unbounded = true)
or wrote a custom layout. Please try to remove the source of infinite constraints in
the hierarchy above the scrolling container.
二、根据异常提示2种修复方式。(都不能解决)
2.1 第一种修复方式:在Modifier.wrapContentSize(unbounded=true)
2.2 第二种修复方式: TvLazyColum添加了(Modifier.verticalScroll()
三、自定义view修复
代码如下 :
package com.trim.tv.ui.components
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.animateScrollBy
import androidx.compose.foundation.gestures.rememberScrollableState
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.tv.foundation.lazy.grid.TvGridCells
import androidx.tv.foundation.lazy.grid.TvLazyGridScope
import androidx.tv.foundation.lazy.grid.TvLazyGridState
import androidx.tv.foundation.lazy.grid.TvLazyVerticalGrid
import androidx.tv.foundation.lazy.grid.rememberTvLazyGridState
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyListScope
import androidx.tv.foundation.lazy.list.TvLazyListState
import androidx.tv.foundation.lazy.list.rememberTvLazyListState
import kotlinx.coroutines.launch
/**
* @author 小强
*
* @time 2023/11/21 11:57
*
* @desc TvLazyColumn 嵌套 TvLazyGrid
*
*
* @param modifier Modifier 调节器
* @param topState TvLazyListState 顶部视图状态
* @param bottomState TvLazyGridState 底部视图状态
* @param fixedCount Int 网格一行展示几个
* @param contentPadding PaddingValues 网格间距
* @param horizontalArrangement Arrangement.Horizontal 网格横向item间距
* @param verticalArrangement Arrangement.Vertical 网格众向item间距
* @param topContent TvLazyListScope.() -> Unit 顶部视图
* @param bottomContent TvLazyGridScope.() -> Unit 底部状态
*/
@Composable
fun NestedTvLazyColumnGrid(
modifier: Modifier = Modifier,
topState: TvLazyListState = rememberTvLazyListState(),
bottomState: TvLazyGridState = rememberTvLazyGridState(),
fixedCount: Int = 6,
contentPadding: PaddingValues = PaddingValues(0.dp),
horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(40.dp),
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(52.dp),
topContent: TvLazyListScope.() -> Unit,
bottomContent: TvLazyGridScope.() -> Unit,
) {
val scope = rememberCoroutineScope()
val innerFirstVisibleItemIndex by remember {
derivedStateOf {
bottomState.firstVisibleItemIndex
}
}
BoxWithConstraints(
modifier = modifier.scrollable(
state = rememberScrollableState {
scope.launch {
val toDown = it <= 0
if (toDown) {
if (topState.run { firstVisibleItemIndex == layoutInfo.totalItemsCount - 1 }) {
bottomState.scrollBy(-it)
} else {
topState.scrollBy(-it)
}
} else {
if (innerFirstVisibleItemIndex == 0 && bottomState.firstVisibleItemScrollOffset == 0) {
topState.scrollBy(-it)
} else {
bottomState.scrollBy(-it)
}
}
}
it
},
Orientation.Vertical,
)
) {
TvLazyColumn(
userScrollEnabled = false, state = topState, modifier = Modifier.heightIn(maxHeight)
) {
// 顶部内容
topContent()
// 底部内容
item {
TvLazyVerticalGrid(
columns = TvGridCells.Fixed(fixedCount),
state = bottomState,
userScrollEnabled = false,
modifier = Modifier.height(maxHeight),
contentPadding = contentPadding,
horizontalArrangement = horizontalArrangement,
verticalArrangement = verticalArrangement
) {
bottomContent()
}
}
}
}
}