android视图可以有一个触摸委托来增加元素的可点击区域,而不增加它的填充。jetpack compose中是否有类似的东西?我找不到可以做到这一点的修饰符。
我正在寻找一个更简洁的解决方案,无意中发现了ViewConfiguration类。所以基本上clickable modifier依靠< code > localview configuration . current 来提供默认实现。如果您已经知道您想要增加触摸区域的大小,您可以只提供这个类的自定义实现,并覆盖< code > minimumtuchtargetsize 来提供更新的大小。以下是视图配置的子类别示例
class CustomViewConfiguration(
private val viewConfiguration: android.view.ViewConfiguration,
private val size: Dp
) : ViewConfiguration {
override val longPressTimeoutMillis: Long
get() =
android.view.ViewConfiguration.getLongPressTimeout().toLong()
override val doubleTapTimeoutMillis: Long
get() =
android.view.ViewConfiguration.getDoubleTapTimeout().toLong()
override val doubleTapMinTimeMillis: Long
get() = 40
override val touchSlop: Float
get() = viewConfiguration.scaledTouchSlop.toFloat()
override val minimumTouchTargetSize: DpSize
get() = DpSize(size, size)
}
定义好后,您可以使用CompositionLocalProider
将其提供给您的可组合程序
CompositionLocalProvider(
LocalViewConfiguration provides CustomViewConfiguration(
android.view.ViewConfiguration.get(
LocalContext.current
),
size.dp
)
) {
// Your composable here that needs an increased size
}
如果您事先不知道增加的大小,您可以使用< code>BoxWithConstraints或任何其他< code>SubComposeLayout来度量组件并在约束中提供它们供您使用。
这是实现我建立,我没有反驳任何错误的计算,但如果你做评论或希望它可以帮助你建立更好的基于这个答案。
1-)创建数据类以增加或减少触摸区域的dp大小
@Immutable
data class DelegateRect(
val left: Dp = 0.dp,
val top: Dp = 0.dp,
val right: Dp = 0.dp,
val bottom: Dp = 0.dp
) {
companion object {
val Zero = DelegateRect()
}
}
@Immutable
data class RectF(
val left: Float = 0f,
val top: Float = 0f,
val right: Float = 0f,
val bottom: Float = 0f
)
2-)创建一个合成修改器来恢复或记忆其状态
fun Modifier.touchDelegate(
dpRect: DelegateRect = DelegateRect.Zero,
onClick: () -> Unit
) =
composed(
inspectorInfo = {
name = "touchDelegate"
properties["dpRect"] = dpRect
properties["onClick"] = onClick
},
factory = {
val density = LocalDensity.current
var initialSize by remember {
mutableStateOf(IntSize.Zero)
}
val updatedRect = remember(dpRect) {
with(density) {
RectF(
left = dpRect.left.toPx(),
top = dpRect.top.toPx(),
right = dpRect.right.toPx(),
bottom = dpRect.bottom.toPx(),
)
}
}
val scale = remember(initialSize, updatedRect) {
getScale(initialSize, updatedRect)
}
Modifier
.graphicsLayer {
scaleX = scale.x
scaleY = scale.y
this.translationX = -updatedRect.left
this.translationY = -updatedRect.top
transformOrigin = TransformOrigin(0f, 0f)
}
.clickable {
onClick()
}
.graphicsLayer {
val scaleX = if (scale.x == 0f) 1f else 1 / scale.x
val scaleY = if (scale.y == 0f) 1f else 1 / scale.y
this.scaleX = scaleX
this.scaleY = scaleY
this.translationX = (updatedRect.left) * scaleX
this.translationY = (updatedRect.top) * scaleY
transformOrigin = TransformOrigin(0f, 0f)
}
.onSizeChanged {
initialSize = it
}
}
)
让我一步一步解释
3-)Modifier.graphicsLayer{}
可以缩放、转换或旋转我们的Composable图层。它的顺序很重要,如果我们在Modifier.clickable之前设置它,它会增加可点击区域和Composable缩放。顶部的Modifier.graphicsLayer{}
的职责是缩放触摸区域和Composable,以缩放并转换回原始位置,第二个Modifier.graphicsLayer{}
是必需的。
4-)基本上,我们随着新添加的dp大小进行缩放,并向左和向上平移,因为我们的变换原点通常居中,但计算平移更困难。
5-)翻译回来时,我们需要考虑比例的反转。
6-)为了获得准确的缩放,我们需要从Modifier.onSizeChanged{}
获得的Composable的大小
7-)缩放函数,使用初始非零大小和通过矩形添加触摸偏移后的大小创建缩放
private fun getScale(initialSize: IntSize, updatedRect: RectF): Offset =
if (initialSize.width == 0 ||
initialSize.height == 0
) {
Offset(1f, 1f)
} else {
val initialWidth = initialSize.width
val initialHeight = initialSize.height
val scaleX =
((updatedRect.left + updatedRect.right + initialWidth) / initialWidth)
.coerceAtLeast(0f)
val scaleY =
((updatedRect.top + updatedRect.bottom + initialHeight) / initialHeight)
.coerceAtLeast(0f)
Offset(scaleX, scaleY)
}
使用
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.landscape1),
contentDescription = null,
contentScale = ContentScale.FillBounds,
modifier = Modifier
.size(200.dp)
.clickable { }
)
Spacer(modifier = Modifier.height(40.dp))
Image(
painter = painterResource(id = R.drawable.landscape1),
contentDescription = null,
contentScale = ContentScale.FillBounds,
modifier = Modifier
.size(200.dp)
.touchDelegate(
DelegateRect(
left = 50.dp,
top = 40.dp,
right = 70.dp,
bottom = 90.dp
)
) {
}
)
}
后果
将状态移至父级
@Composable
fun ViewScreen() {
var scale by remember { mutableStateOf(1f) }
var offset by remember { mutableStateOf(Offset.Zero) }
var rotation by remember { mutableStateOf(0f) }
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
// touch event
.pointerInput(Unit) {
detectTransformGestures(
onGesture = { _, pan, gestureZoom, gestureRotate ->
scale *= gestureZoom
offset = offset.plus(pan)
rotation += gestureRotate
}
)
}
.fillMaxSize()
) {
Cube(scale, offset, rotation)
}
}
@Composable
fun Cube(scale: Float, offset: Offset, rotation: Float) {
Box(
Modifier
.graphicsLayer(
scaleX = scale,
scaleY = scale,
rotationZ = rotation,
translationX = offset.x,
translationY = offset.y
)
.background(Color.Blue)
.size(256.dp)
)
}
请注意,我使用以下代码得到了相同的结果: 所以问题是,fooObservable直到订阅了PublishSubject之后才订阅PublishSubject, 是否有一种方法可以在第一次订阅FooObservable之后立即运行代码? 如果请求与已经订阅的请求匹配,那么observable应该在订阅时立即提供最新的匹配值。 当没有订阅者时,我需要取消我包装的服务的订阅。
问题内容: 使用以下代码: 我得到以下html: 我怎样才能没有任何标签?是否有InnerText等效项? 问题答案: 所有你需要的是:
问题内容: 尝试在Java / Swing中构建GUI应用程序。我主要习惯于使用VB之类的工具在Windows方面“绘画” GUI(或更准确地说,是Gupta SQLWindows …想知道有多少人知道那是什么;-)。 我在Swing中找不到等效的Group Box … 使用组框,您将在几个相关小部件周围有一个方形框(通常带有标题)。一个示例是围绕几个单选按钮的分组框(标题说明了单选按钮的含义,例
问题内容: 我们需要查看对象在Javascript中具有哪些方法/字段。 问题答案: 正如其他人所说,您可以使用Firebug,这将使您在Firefox上无后顾之忧。Chrome和Safari都具有内置的开发人员控制台,该控制台具有与Firebug控制台几乎相同的界面,因此您的代码应可跨这些浏览器移植。对于其他浏览器,有Firebug Lite 。 如果您不适合使用Firebug,请尝试以下简单脚
问题内容: 一些数据库支持以下命令: 本质上,我需要提取前10条记录,然后提取10条记录,然后提取10条记录,等等。也许有另一种方式可以做到这一点,但是在过去,对于支持“ START AT”的数据库,我已经像上面那样完成了。 问题答案: 哪个版本的SQL Server? 在SQL Server 2000中,这确实是一个痛苦(尽管可以使用诸如stingyjack发布的丑陋技巧)。 在2005年及之后
ChromeAPI提供了一个获取当前窗口(返回包含当前正在执行的代码的窗口)的方法。Safari有等效的方法吗?