IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【Android Compose】实现宜家 双联列表 -> 正文阅读

[移动开发]【Android Compose】实现宜家 双联列表

效果图

请添加图片描述

!

实现宜家 双联列表

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

代码


/**
 * 双联动列表
 * @param leftList List<String> 左侧条目
 * @param scrollToItem Function1<Int, Int> 右侧滑动影响左侧位置
 * @param itemToScroll Function1<Int, Int> 左侧滑动影响右侧位置,与上者互为反函数
 * @param content [@kotlin.ExtensionFunctionType] Function1<LazyListScope, Unit> 右侧内容填充物
 */
@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. 其他讨论脱离文章范畴,不赘述。
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:53:18  更:2022-10-08 20:54:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 3:25:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码