diff --git a/compose/src/main/java/org/zhiwei/compose/model/Screen.kt b/compose/src/main/java/org/zhiwei/compose/model/Screen.kt index 4920a89..bb34d85 100644 --- a/compose/src/main/java/org/zhiwei/compose/model/Screen.kt +++ b/compose/src/main/java/org/zhiwei/compose/model/Screen.kt @@ -19,6 +19,7 @@ import org.zhiwei.compose.screen.basic.material3.Widget_Screen import org.zhiwei.compose.screen.gesture.Clickable_Screen import org.zhiwei.compose.screen.gesture.SwipeScroll_Screen import org.zhiwei.compose.screen.gesture.TapDragGestures_Screen +import org.zhiwei.compose.screen.gesture.TouchImage_Screen import org.zhiwei.compose.screen.gesture.TransformGestures_Screen import org.zhiwei.compose.screen.layout_state.ConstraintLayout_Screen import org.zhiwei.compose.screen.layout_state.Constraints_Screen @@ -178,6 +179,10 @@ internal object GestureScreenUIs { "SwipeScrollable", "Modifier的一些其他操作手势,侧滑,滚动等。" ) { SwipeScroll_Screen(modifier) }, + CourseItemModel( + "TouchOnImage", + "从图片的点击位置,获取触控点的颜色。" + ) { TouchImage_Screen(modifier) }, ) } diff --git a/compose/src/main/java/org/zhiwei/compose/screen/gesture/SwipeScrollable.kt b/compose/src/main/java/org/zhiwei/compose/screen/gesture/SwipeScrollable.kt index c336f4f..ca8730f 100644 --- a/compose/src/main/java/org/zhiwei/compose/screen/gesture/SwipeScrollable.kt +++ b/compose/src/main/java/org/zhiwei/compose/screen/gesture/SwipeScrollable.kt @@ -7,6 +7,8 @@ import androidx.compose.foundation.gestures.AnchoredDraggableState import androidx.compose.foundation.gestures.DraggableAnchors import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.anchoredDraggable +import androidx.compose.foundation.gestures.rememberScrollableState +import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column @@ -16,9 +18,12 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.FractionalThreshold import androidx.compose.material.Slider @@ -26,11 +31,13 @@ import androidx.compose.material.SwipeProgress import androidx.compose.material.Text import androidx.compose.material.rememberSwipeableState import androidx.compose.material.swipeable +import androidx.compose.material3.Button import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -39,6 +46,8 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch import org.zhiwei.compose.ui.widget.Title_Desc_Text import org.zhiwei.compose.ui.widget.Title_Sub_Text import org.zhiwei.compose.ui.widget.Title_Text @@ -54,13 +63,24 @@ import kotlin.math.roundToInt */ @Composable internal fun SwipeScroll_Screen(modifier: Modifier = Modifier) { - Column(modifier.fillMaxSize()) { + Column( + modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + ) { Title_Text(title = "Swipeable") Title_Sub_Text(title = "1. 侧滑事件的简单实现,swipeable操作符,以及替代方式的演示。") Title_Desc_Text(desc = "swipeable的使用,设置fraction的位置不同,滑动切换的临界点就不一样。") UI_Swipeable() Title_Desc_Text(desc = "替代swipeable,使用推荐的新的api,AnchoredDraggable实现相同效果。") UI_AnchoredDraggable() + Title_Sub_Text(title = "2. 使用Modifier的滑动相关的操作符。") + Title_Desc_Text(desc = "scrollable滑动操作符的使用,简单看一下滚动状态和偏移量变化。") + ScrollableModifierSample() + Title_Desc_Text(desc = "scrollable操作符的scrollable的state可以控制滑动的位置。") + ScrollExample() + //滚动可以嵌套,还有水平,竖直滑动的单独操作符函数。 + } } @@ -143,7 +163,7 @@ private fun UI_Swipeable() { } //使用AnchoredDraggable代替swipeable实现侧滑效果 -@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class) @Composable private fun UI_AnchoredDraggable() { var fraction by remember { mutableFloatStateOf(0.3f) } @@ -204,7 +224,75 @@ private fun UI_AnchoredDraggable() { } } -private enum class DragValue { Start, Center, End } +@Composable +private fun ScrollableModifierSample() { + var offset by remember { mutableFloatStateOf(0f) } + Box( + Modifier + .fillMaxWidth() + .height(200.dp) + .scrollable( + orientation = Orientation.Vertical, + state = rememberScrollableState { delta -> + offset += delta + delta + } + ) + .background(Color.LightGray), + contentAlignment = Alignment.Center + ) { + Text(offset.toString()) + } +} + +@Composable +private fun ScrollExample() { + + Column(modifier = Modifier + .fillMaxWidth() + .height(400.dp)) { + val coroutineScope = rememberCoroutineScope() + + // Smoothly scroll 100px on first composition + val state = rememberScrollState() + + Column( + modifier = Modifier + .background(Color.LightGray) + .fillMaxWidth() + .weight(1f) + .padding(horizontal = 8.dp) + .verticalScroll(state) + ) { + repeat(30) { + Text("Item $it", modifier = Modifier.padding(2.dp), fontSize = 20.sp) + } + } + + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { + coroutineScope.launch { + state.animateScrollTo(100) + } + } + ) { + Text(text = "Smooth Scroll to top") + } + + + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { + coroutineScope.launch { + state.scrollTo(100) + } + }) { + Text(text = "Scroll to top") + } + } +} + @Preview diff --git a/compose/src/main/java/org/zhiwei/compose/screen/gesture/TouchImage.kt b/compose/src/main/java/org/zhiwei/compose/screen/gesture/TouchImage.kt new file mode 100644 index 0000000..1f72343 --- /dev/null +++ b/compose/src/main/java/org/zhiwei/compose/screen/gesture/TouchImage.kt @@ -0,0 +1,134 @@ +package org.zhiwei.compose.screen.gesture + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asAndroidBitmap +import androidx.compose.ui.graphics.isUnspecified +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.res.imageResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.toSize +import org.zhiwei.compose.R +import org.zhiwei.compose.ui.widget.Title_Sub_Text +import org.zhiwei.compose.ui.widget.Title_Text + +/** + * 作者: iOrchid + * 主页: [Github](https://github.com/iOrchid) + * 日期: 2024年05月18日 13:50 + * 签名: 天行健,君子以自强不息;地势坤,君子以厚德载物。 + * You never know what you can do until you try ! + */ +@Composable +internal fun TouchImage_Screen(modifier: Modifier = Modifier) { + Column(modifier.fillMaxSize()) { + Title_Text(title = "ColorPicker") + Title_Sub_Text(title = "从图片Image中,获取触控点的颜色值") + TouchOnImageExample() + } +} + +@Composable +private fun TouchOnImageExample() { + + val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.sexy_girl) + + val bitmapWidth = imageBitmap.width + val bitmapHeight = imageBitmap.height + + var offsetX by remember { mutableFloatStateOf(0f) } + var offsetY by remember { mutableFloatStateOf(0f) } + var imageSize by remember { mutableStateOf(Size.Zero) } + + // These are for debugging + var text by remember { mutableStateOf("") } + var colorAtTouchPosition by remember { mutableStateOf(Color.Unspecified) } + + val imageModifier = Modifier + .background(Color.LightGray) + .fillMaxWidth() + // 限定宽高比 + .aspectRatio(3f / 4) + .pointerInput(Unit) { + detectTapGestures { offset: Offset -> + // Touch coordinates on image + offsetX = offset.x + offsetY = offset.y + + // Scale from Image touch coordinates to range in Bitmap + val scaledX = (bitmapWidth / imageSize.width) * offsetX + val scaledY = (bitmapHeight / imageSize.height) * offsetY + + try { + val pixel: Int = + imageBitmap + .asAndroidBitmap() + .getPixel(scaledX.toInt(), scaledY.toInt()) + + + val red = android.graphics.Color.red(pixel) + val green = android.graphics.Color.green(pixel) + val blue = android.graphics.Color.blue(pixel) + + text = "图片触控 offsetX:$offsetX, offsetY: $offsetY\n" + + "图片宽: ${imageSize.width}, 高: ${imageSize.height}\n" + + "位图 宽: ${bitmapWidth}, 高: $bitmapHeight\n" + + "scaledX: $scaledX, scaledY: $scaledY\n" + + "red: $red, green: $green, blue: $blue\n" + + colorAtTouchPosition = Color(red, green, blue) + } catch (e: Exception) { + println("Exception e: ${e.message}") + } + } + } + .onSizeChanged { imageSize = it.toSize() } + + Image( + bitmap = imageBitmap, + contentDescription = null, + modifier = imageModifier.border(2.dp, Color.Red), + contentScale = ContentScale.Crop + ) + Text(text = text) + Box( + modifier = Modifier + .then( + if (colorAtTouchPosition.isUnspecified) { + Modifier + } else { + Modifier.background(colorAtTouchPosition) + } + ) + .size(100.dp) + ) +} + +@Preview +@Composable +private fun PreviewTouchImage() { + TouchImage_Screen() +} \ No newline at end of file