Kotlin 返回imageView旋转位置,并在特定位置停止

Kotlin 返回imageView旋转位置,并在特定位置停止,kotlin,animation,rotation,imageview,position,Kotlin,Animation,Rotation,Imageview,Position,希望有人能帮忙。我正在创建一个应用程序,用户可以通过触摸一系列图像来旋转它们。我想做的事。是在用户旋转到特定位置后高亮显示图像 这可能吗?如果是这样,任何提示都非常感谢。编辑-好的,这里是一个示例 首先,根据您刚刚发布的代码示例,最简单的方法是: r1c1.setOnClickListener { r1c1.animate().apply{ duration = 100 rotationBy(270f) }.start() } 所以这里的问题是,当视图旋转到,比如说90度时,你想高亮显

希望有人能帮忙。我正在创建一个应用程序,用户可以通过触摸一系列图像来旋转它们。我想做的事。是在用户旋转到特定位置后高亮显示图像


这可能吗?如果是这样,任何提示都非常感谢。

编辑-好的,这里是一个示例

首先,根据您刚刚发布的代码示例,最简单的方法是:

r1c1.setOnClickListener {
    r1c1.animate().apply{ duration = 100 rotationBy(270f) }.start()
}
所以这里的问题是,当视图旋转到,比如说90度时,你想高亮显示视图,对吗?但它首先要完成一个动画。你真的有三个选择

  • 执行类似于
    if(r1c1.rotation+270f==90)
    的操作,并在动画开始时高亮显示,这可能看起来很奇怪
  • 现在执行该检查,但如果需要,使用来运行突出显示代码
  • 动画完成后,使用
    withEndAction
    进行检查和高亮显示
后者可能最有意义——在动画完成后,检查其显示状态是否需要更改。可能是这样的:

r1c1.animate().setDuration(100).rotationBy(270f).withEndAction {
    // need to do modulo so 720 == 360 == 0 etc
    if (r1c1.rotation % 360 == TARGET_ROTATION) highlight(r1c1)
}.start()
我假设您有一些突出显示
ImageView
s的方法,而您并没有要求这样做


不幸的是,这里的问题是,如果用户在动画的中间轻敲视图,它将取消该动画并启动一个新的动画,包括“代码”>旋转(270)< /代码> <强>从当前视图所发生的任何旋转在< /强>。双击,您将看到一个角度的视图,现在它几乎永远不会匹配90度的值!这就是为什么更容易保持状态,按固定的、有效的数量进行更改,然后告诉视图它应该是什么样子

因此,您应该为当前旋转设置一个值,更新该值,并将其用于高亮显示检查:

# var stored outside the click listener - this is your source of truth
viewRotation += 270f
# using rotation instead of rotationBy - we're setting a specific value, not an offset
r1c1.animate().setDuration(100).rotation(viewRotation).withEndAction {
    // checking our internal rotation state, not the view!
    if (viewRotation % 360 == TARGET_ROTATION) highlight(r1c1)
}.start()
我不是说有一个单独的旋转变量像那样挂着-你可以,但看到下一位-如果你有很多
ImageView
s要争论,它会很快变得混乱。但这只是为了演示基本思想-您持有自己的状态值,您可以控制它可以设置为什么,而
视图
只是反映了该状态,而不是相反


好的,所以组织-我从
r1c1
猜测,你有一个网格单元,所有单元都具有相同的一般行为。这意味着大量重复代码,除非您尝试将其概括并将其粘贴在一个地方—就像单击一次侦听器一样,这会做同样的事情,只需单击它所在的任何视图即可

(我知道你说你是一个初学者,我不喜欢一次给别人加载太多的概念,但从听起来你这样做可能会让人难以置信地臃肿,很难真正快速地工作,所以这很重要!)

基本上,'s
onClick
函数在被单击的视图中作为一个参数传递-基本上你可以按照我说的做,重用同一个单击侦听器,根据传递的内容做不同的事情。您可以在所有的
ImageView
上设置一个通用的单击侦听器函数,而不是lambda(在
{}
中的代码,基本上是您在一个地方使用的一个快速而肮脏的函数)

fun spin(view: View) {
    // we need to store and look up a rotation for each view, like in a Map
    rotations[view] = rotations[view] + 270f
    // no explicit references like r1c1 now, it's "whatever view was passed in"
    view.animate().setDuration(100).rotation(rotations[view]).withEndAction {
        // Probably need a different target rotation for each view too?
        if (rotations[view] % 360 == targetRotations[view]) highlight(view)
    }.start()
}
然后单击侦听器设置如下

r1c1.setOnClickListener { spin(it) }
或者您可以将其作为函数引用传递(这已经太长了,无法解释,但在这种情况下可以使用它,因此您可以在需要时使用它)

我建议您在查找所有
ImageView
单元格时生成一个列表(有几种方法可以处理这类事情),但拥有一个集合可以让您执行以下操作

allCells.forEach { it.setOnClickListener(::spin) }
rotatables = cells.map { RotatableImageView(it) }
现在,所有单击侦听器都设置为同一个函数,该函数将处理单击的任何视图及其关联的状态。明白了吗


所以你的基本结构是

// maybe not vals depending on how you initialise things!
val rotations: MutableMap<View, Float>
val targetRotations: Map<View, Float>
val allCells: List<ImageView>

// or onCreateView or whatever
fun onCreate() {
    ...
    allCells.forEach { it.setOnClickListener(::spin) }
}

fun spin(view: View) {
    rotations[view] = rotations[view] + 270f
    view.animate().setDuration(100).rotation(rotations[view]).withEndAction {
        val highlightActive = rotations[view] % 360 == targetRotations[view] 
        highlight(view, highlightActive)
    }.start()
}

fun highlight(view: View, enable: Boolean) {
    // do highlighting on view if enable is true, otherwise turn it off
}
//可能不是VAL,这取决于您初始化的方式!
val旋转:可变映射
val目标:地图
val所有单元格:列表
//或者onCreateView或者其他什么
fun onCreate(){
...
allCells.forEach{it.setOnClickListener(::spin)}
}
趣味旋转(视图:视图){
旋转[视图]=旋转[视图]+270f
view.animate().setDuration(100).旋转(旋转[视图]).withEndAction{
val highlightActive=旋转[视图]%360==目标定位[视图]
高亮显示(视图,高亮显示活动)
}.start()
}
趣味突出显示(视图:视图,启用:布尔值){
//如果启用为true,则在视图上高亮显示,否则将其关闭
}

我没有进入“保存所有状态的
ImageView
包装类”的整个过程,这可能是一个更好的方法,但我不想走得太远,让事情复杂化。这已经是一个愚蠢的长度。我可能会做一个快速的回答,作为一个演示或其他什么

另一个答案足够长,但下面是我关于封装东西的意思

class RotatableImageView(val view: ImageView, startRotation: Rotation, val targetRotation: Rotation)  {

    private var rotation = startRotation.degrees

    init {
        view.rotation = rotation
        view.setOnClickListener { spin() }
        updateHighlight()
    }

    private fun spin() {
        rotation += ROTATION_AMOUNT
        view.animate().setDuration(100).rotation(rotation)
            .withEndAction(::updateHighlight).start()
    }

    private fun updateHighlight() {
        val highlightEnabled = (rotation % 360f) == targetRotation.degrees
        // TODO: highlighting!
    }

    companion object {
        const val ROTATION_AMOUNT = 90f
    }
}

enum class Rotation(var degrees: Float) {
    ROT_0(0f), ROT_90(90f), ROT_180(180f), ROT_270(270f);

    companion object {
        // just avoids creating a new array each time we call random()
        private val rotations = values()
        fun random() = rotations.random()
    }
}
基本上,没有将
视图
s映射到当前旋转值,也没有将
视图
s映射到目标值等,而是将每个
视图
的所有状态绑定到一个对象中。一切都在内部处理,您只需从外部找到布局中的
ImageView
s,并将它们传递到
RotatableImageView
构造函数中。这将设置一个单击侦听器并处理高亮显示其
ImageView
,如果需要,您不需要做任何其他事情

enum
只是创建表示有效值的类型的一个示例-当您创建
RotatableImageView
时,必须传入其中一个值,并且唯一可能的值是有效的旋转量。您也可以为它们提供默认值(如果需要,可以是
Rotation.random()
),这样构造函数调用就可以是
RotatableImageView(imageView
val cells = findViewById<ViewGroup>(R.id.grid).children.filterIsInstance<ImageView>()
rotatables = cells.map { RotatableImageView(it) }