【Android Compose】实现宜家 双联列表

双联列表

  • 效果图
  • 代码
    • 解析
      • 主要矛盾
    • 性能问题:
      • 次要矛盾

效果图

请添加图片描述

!

实现宜家 双联列表

00001.jpg?auth_key=4818491540-0-0-c8bbe27fc97f582aa0dd1b29a371a81f)(title-实现宜家 双联列表)]

代码


/**
 * 双联动列表
 * @param leftList List 左侧条目
 * @param scrollToItem Function1 右侧滑动影响左侧位置
 * @param itemToScroll Function1 左侧滑动影响右侧位置,与上者互为反函数
 * @param content [@kotlin.ExtensionFunctionType] Function1 右侧内容填充物
 */
@Composable
fun PartList(
		leftList : List<String>,
		scrollToItem : (Int) -> Int,
		itemToScroll : (Int) -> Int,
		content: LazyListScope.() -> Unit
)
{
	// 滑动状态
	val leftScrollState = rememberLazyListState()
	val rightScrollState = rememberLazyListState()

	// Remember a CoroutineScope to be able to launch
	val coroutineScope = rememberCoroutineScope()

	// 点击左侧的位置
	var onClickItem by remember {
		mutableStateOf(-1)
	}

	// 滑动右侧条目时,左侧联动
	// https://blog.csdn.net/vitaviva/article/details/121583183
	val getFirstVisibleItemIndex by remember {
		derivedStateOf {
			rightScrollState.firstVisibleItemIndex
		}
	}

	LaunchedEffect(Unit) {
		snapshotFlow { getFirstVisibleItemIndex }
				.collect {
					onClickItem = scrollToItem(it)
				}
	}

//	run {
		// 这里应该自行设计何处位置为标头
//		onClickItem = scrollToItem(rightScrollState.firstVisibleItemIndex)

		// todo positive
//		coroutineScope.launch {
//			leftScrollState.scrollToItem(onClickItem)
//		}
//	}


	Row(modifier = Modifier.fillMaxSize())
	{
		LazyColumn(
				state = leftScrollState,
				modifier = Modifier
						.fillMaxHeight()
						.background(IKEA_GRAY_LIGHT)
						.weight(2f)
		)
		{

			items(leftList.size)
			{

				Row(
						modifier = Modifier
								.fillMaxWidth()
								.height(40.dp)
								.background(if (onClickItem == it) white else IKEA_GRAY_LIGHT) // val IKEA_GRAY_LIGHT = Color(245, 245, 245)
								.clickable {
									// 点击左侧时设置跳转状态
									onClickItem = it
									coroutineScope.launch {
										rightScrollState.animateScrollToItem(itemToScroll(it))
									}
								},
						verticalAlignment = Alignment.CenterVertically,
						horizontalArrangement = Arrangement.Center
				) {
					Text(
							text = leftList[it],
							modifier = Modifier,
							color = if(onClickItem == it) Color.Blue else Color.Black,
							fontSize = 11.sp,
					)
				}

			}
		}

		Spacer(modifier = Modifier.weight(0.5f))

		LazyColumn(
				state = rightScrollState,
				modifier = Modifier
						.fillMaxHeight()
						.weight(8f),
				content = content
		)
	}
}


解析

主要矛盾

联动采用将两边滑动状态上提然后根据规则变动:

  1. 状态上提方法:
    通过rememberLazyListState来获取滑动状态
@Preview(showBackground = true, backgroundColor = 0xFFFFFFFF)
@Composable
fun PartList()
{
	// 滑动状态
	val leftScrollState = rememberLazyListState()
	val rightScrollState = rememberLazyListState()


	Row {
		// 左侧
		LazyColumn(
				state = leftScrollState,
				。。。
		)
		{
			。。。。
		}

		Spacer(modifier = Modifier.weight(0.5f))

		// 右侧
		LazyColumn(
				state = rightScrollState,
				。。。
		) {
			。。。。
		}
	}
}

  1. 点击 左侧,右侧滑动到相应位置:
    a. 点击右侧:左侧跳转到相应标头
    b. 滑动右侧到新的标头:左侧跟着跳转

a) 左侧只要监听点击事件,然后对右侧跳转即可:
我们以 左侧条目Modifier来进行点击事件监听:

.clickable {
        onClickItem = it // it 是思点击左侧的索引号
		// 点击左侧时设置跳转状态,这里跳转标头可以自己设定
		coroutineScope.launch {
			rightScrollState.animateScrollToItem(it * 3)
		}
}

b) 右侧滑动是实时监听的,所以只需要在函数内最上层写相关变化即可:

// 滑动右侧条目时,左侧联动
	run {
		// 这里应该自行设计何处位置为标头
		onClickItem = (rightScrollState.firstVisibleItemIndex / 3)

		coroutineScope.launch {
			leftScrollState.animateScrollToItem(onClickItem)
		}
	}

性能问题:

上文中,直接访问rememberLazyListStatefirstVisibleItemIndex 不是一个好选择,他会造成性能问题。

在使用 LazyColumn 或者 LazyRow 时,应该避免在 LazyListScope 中访问 LazyListState,这可能会造成隐藏的性能问题

因此,我们需要改进:将判断 list 滚动的逻辑抽象为一个 getFirstVisibleItemIndex 状态,然后通过 snapshotFlow 单独定义其变化,这样避免 LazyColumncontent 的重组。

val getFirstVisibleItemIndex by remember {
		derivedStateOf {
			rightScrollState.firstVisibleItemIndex
		}
	}

	LaunchedEffect(Unit) {
		snapshotFlow { getFirstVisibleItemIndex }
				.collect {
					onClickItem = scrollToItem(it)
				}
	}

次要矛盾

也就是尽可能符合宜家设计标准:

  1. 点击左侧,左侧跳转到指定位置,这里就引入onClickItem 和其他外观区别。
  2. 其他讨论脱离文章范畴,不赘述。

你可能感兴趣的:(android笔记,android,kotlin,android,jetpack)