Android Compose LazyColum 嵌套 LazyVerticalGrid解决冲突 ,TvLazyColum 嵌套 TvLazyVerticalGrid解决冲突

一、起因:

在开发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()
                }
            }
        }

    }
}

解决后的效果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值