前语
回顾下之前的内容,咱们已经完成了以下相关页内容,它们分别是:
Jetpack Compose 实战之仿微信UI -完成登陆页(一)
Jetpack Compose 实战之仿微信UI -完成首页(二)
Jetpack Compose 实战之仿微信UI -完成朋友圈(三)
在这一篇文章中,我将运用 Jetpack Compose 去完成微信朋友圈图片的预览。
功用拆分
微信朋友圈图片预览的功用首要包括:
(1)图片左右滑动
(2)页面指示器
(3)缩放
(4)双击扩大(然后再双击康复,反之)
(5)单击返回
功用完成
图片左右滑动
在完成首页的时分,咱们运用了 HorizontalPager 进行页面切换,所以咱们在这儿直接运用HorizontalPager作为图片左右切换的组件即可,完成的代码为:
HorizontalPager(
count = images.size,
state = pageState,
contentPadding = PaddingValues(horizontal = 0.dp),
modifier = Modifier.fillMaxSize()
) { page ->
ImagePageItem()
}
页面指示器
HorizontalPager给咱们封装了一个指示器组件 HorizontalPagerIndicator,咱们直接运用就能完成咱们的作用,完成代码为:
HorizontalPagerIndicator(
pagerState = pageState,
activeColor = Color.White, /*** 指示器选中的色彩 */
inactiveColor = Color(0xff888888), /*** 指示器未选中的色彩 */
indicatorHeight = 6.dp, /*** 指示器的高度 */
indicatorWidth = 6.dp, /*** 指示器的宽度 */
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(60.dp)
)
到这儿,咱们就完成了图片的切换以及指示器部分了,看下作用
缩放
缩放完成的中心是监听到手势的动作,然后拿到缩放份额值,平移偏移量等数据,经过查找材料,我发现官方给咱们供给了Modifier的拓宽函数 transformable,咱们看下transformable这个拓宽函数的结构:
Modifier.transformable(
state: TransformableState,
lockRotationOnZoomPan: Boolean = false,
enabled: Boolean = true
)
各特点的含义:
state: 监听手势改变
lockRotationOnZoomPan: 假如为true,则仅当在平移或缩放运动之前检测到旋转的接触倾斜时才答应旋转。否则,将检测到平移和缩放手势,但不会检测到旋转手势。假如为false,一旦达到接触斜率,将检测所有三个手势。
enabled: 是否启用手势缩放
所以,在这儿咱们经过state的监听就能够拿到缩放份额值,平移偏移量等数据,具体的代码为:
/*** 缩放份额 */
var scale by remember { mutableStateOf(1f) }
/*** 偏移量 */
var offset by remember { mutableStateOf(Offset.Zero) }
/*** 监听手势改变 */
val state = rememberTransformableState(onTransformation = { zoomChange, offsetChange, rotationChange ->
scale = (zoomChange * scale).coerceAtLeast(1f)
scale = if (scale > 4f) {
4f
} else {
scale
}
offset += offsetChange
})
其间 rotationChange 是旋转的改变,这儿咱们不需求,就不处理。4f 是咱们答应扩大的最大倍数,根据自己的需求自定义即可。
到这儿,咱们将 state 赋值到 Image 组件的 Modifier,就能够监听到图片的手势的缩放,平移等,具体代码为:
Image(
painter = rememberCoilPainter(
request = image
),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier.transformable(state = state)
)
但是,咱们拿到了手势改变的数据,怎样操控图片随着这些数据进行动画呢?官方供给了动画特点 Modifier.graphicsLayer,经过 GraphicsLayerScope 来操控缩放,平移,旋转,透明度,渐变等常用动画,具体的完成代码为:
Image(
painter = rememberCoilPainter(
request = image
),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier
.transformable(state = state) /** 检测手势元素的平移、缩放、旋转 */
.graphicsLayer{ /**缩放、旋转、移动变换 */
scaleX = scale /** 等比缩放 */
scaleY = scale /** 等比缩放 */
translationX = offset.x /** X轴位移量*/
translationY = offset.y /** Y轴位移量*/
/** 核算页面的当前偏移 */
val pageOffset = pagerScope.calculateCurrentOffsetForPage(page = page).absoluteValue
if (pageOffset == 1.0f) {
scale = 1.0f
}
)
这样,咱们监听手势的改变和运用动画就达到了图片缩放,平移的作用了。
双击,单击时事情的处理
咱们运用 pointerInput 来监听图片的单双击事情,具体的代码为:
pointerInput(Unit) {
detectTapGestures(
onDoubleTap = {
scale = if (scale <= 1f) {
2f
} else {
1f
}
offset = Offset.Zero
},
onTap = {
context.finish()
}
)
}
(1)单击的处理:比较简单,就是直接finish当前页面,假如是运用 navigation 导航的,运用navController.popBackStack()即可,我这儿是运用Activity。
(2)双击的处理:这儿的只有扩大和正常两种状况,当前状况为正常时,双击就扩大2倍(自定义,当然也能够扩大3倍),当前状况为扩大时,双击就将缩放倍数改为1倍,这样那就达到了咱们的作用。
完成的悉数代码为:
@OptIn(ExperimentalPagerApi::class)
@Composable
fun ImagePreviewScreen(images: ArrayList<String>, currentIndex: Int) {
rememberSystemUiController().setStatusBarColor(Color.Black, darkIcons = true)
/*** 界面状况改变 */
val pageState = rememberPagerState(initialPage = currentIndex)
Box {
/*** 图片部分 */
HorizontalPager(
count = images.size,
state = pageState,
contentPadding = PaddingValues(horizontal = 0.dp),
modifier = Modifier.fillMaxSize()
) { page ->
ImagePageItem(images[page], page, this)
}
/*** 指示器部分 */
HorizontalPagerIndicator(
pagerState = pageState,
activeColor = Color.White, /*** 指示器选中的色彩 */
inactiveColor = Color(0xff888888), /*** 指示器未选中的色彩 */
indicatorHeight = 6.dp, /*** 指示器的高度 */
indicatorWidth = 6.dp, /*** 指示器的宽度 */
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(60.dp)
)
}
}
@OptIn(ExperimentalPagerApi::class)
@Composable
fun ImagePageItem(
image: String,
page: Int = 0,
pagerScope: PagerScope
) {
val context = LocalContext.current as Activity
/*** 缩放份额 */
var scale by remember { mutableStateOf(1f) }
/*** 偏移量 */
var offset by remember { mutableStateOf(Offset.Zero) }
/*** 监听手势改变 */
val state = rememberTransformableState(onTransformation = { zoomChange, offsetChange, rotationChange ->
scale = (zoomChange * scale).coerceAtLeast(1f)
scale = if (scale > 4f) {
4f
} else {
scale
}
offset += offsetChange
})
Surface(
modifier = Modifier.fillMaxSize(),
color = Color.Black,
) {
Image(
painter = rememberCoilPainter(
request = image
),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier
.transformable(state = state) /** 检测手势元素的平移、缩放、旋转 */
.graphicsLayer{ /**缩放、旋转、移动变换 */
scaleX = scale /** 等比缩放 */
scaleY = scale /** 等比缩放 */
translationX = offset.x /** X轴位移量*/
translationY = offset.y /** Y轴位移量*/
/** 核算页面的当前偏移 */
val pageOffset = pagerScope.calculateCurrentOffsetForPage(page = page).absoluteValue
if (pageOffset == 1.0f) {
scale = 1.0f
}
}.pointerInput(Unit) {
detectTapGestures(
onDoubleTap = {
scale = if (scale <= 1f) {
2f
} else {
1f
}
offset = Offset.Zero
},
onTap = {
context.finish()
}
)
}
)
}
}
到这儿,咱们就完成了仿微信朋友圈图片的预览功用了,一起来看下悉数作用
总结
咱们这一期运用了 HorizontalPager 完成了图片切换,运用 HorizontalPagerIndicator 完成了指示器的功用,运用 transformable 监听手势的缩放,平移等动作,运用了 graphicsLayer 进行动画,运用 pointerInput 来监听图片的单双击事情。
项目地址:ComposeWechat,假如对你有用,别忘了给个star