【问题标题】:Drag and drop ImageView into a container for verification将 ImageView 拖放到容器中进行验证
【发布时间】:2020-02-11 00:57:56
【问题描述】:

为了更好地理解它,请阅读以下内容:

First game :

Skate QuestionMark
Archery QuestionMark
Swim QuestionMark

---------------------------
Water Bow Wheel

If user drags Water to Skate or Archery QuestionMark it will animate to the list (because it is not correct)

If user drags twice incorrect (it will mark the one that is correct from the answer list)

If user still fail in the third try it will drag to the incorrect one and then it will highlight or just change the color doesn't matter to red.

If user drags to the correct one it will highlight green and replace QuestionMark with the correct one (I do not want to be draggable anymore that image)

------

Game 2 (is more or less the same...)

There's no QuestionMark column, there's only :

Skate
Swim
Archery
--------------
(Lot of answers)

Now the way to play is the same (about the fails and etc) the thing is now when I drag any answer to the correct one it won't replace the correct one, it will just disappear and if it fails instead of highlighting all the corrects one it will highlight the correct answer (for instance; if I drag wheel to Swim once, it doesn't happen anything just animate to the place where it was, if I do it twice it will highlight the Skate one, and if it fails at third one it just drag wherever he did and highlight with red)

我正计划构建一个执行简单检查的应用程序,我正在调用一个端点,我会得到一些参数,然后我会知道屏幕上将显示多少个ImageView . 这就像一个谜题,看起来像这样:

所以我有不同的选择,其中仅包含一个正确答案,我正在计划实现这一目标的方法,可以将“弓”拖到“滑板”前面的问号上,然后说不正确,然后将其拖到“射箭”之一,并从底部替换包含“箭头”一词的ImageView的问号。

布局应该包含一列问题(这应该是运动),然后在问题前面的另一列应该是答案 一个,那么它们下面应该包含 Options 一个。

清楚吗?否则请告诉我,我会尽量详细解释一下。

编辑

我认为有一个包含 Answers 列表的类,或者只是创建如下:

RightList : (id:1,id:2,id:3)

LeftList : (id:1, id:2, id:3)

DownList : (Bow = id:2),(Skate = id:1), (Ball = id:3)

然后在DragEvent.ACTION_DROP或者DragEvent.ACTION_DRAG_ENDED不知道是哪一个的时候做拖拽的事情,检查一下(下面是伪代码)

if(imageDragged.id==location.id) then replace the question mark image for imageDragged
else animate the image to the place where it comes

我不知道是否创建一个实现 onDragListener() 或类似的类,我希望它具有通用性,以便我可以在不同的游戏中使用它,例如:

滑板(id:1) 射箭(id:2) 足球(id:3)

答案:表(CA id:1)弓(CA id:2)草(CA id:3)目标(CA id:3)球(CA id:3)箭头(CA id:2)轴(CA id:1) 轮子(CA id:1)

因此,如果我将例如 BOW 拖放到 FOOTBALL,那么它应该显示为不好,否则说它是好的。

【问题讨论】:

  • 您的问题是您想要做的事情对没有经验的用户是否有意义,或者您是否希望我们建议如何实现您在上面描述的内容?
  • 一个建议,游戏是这样的。请。
  • 作为一种完全不同的方式,我建议bubbles-for-android。 (它们基于Facebook Chatheads)见my answer

标签: java android android-layout kotlin drag-and-drop


【解决方案1】:

示例 1/3

仅供参考,总结一切。这是一个 100 行代码,在单个 Activity 和导入中,即使使用简单的动画也能代表所有这些行为。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bind()
    }

    private fun bind() {
        addQuestions()
        addAnswers()
    }

    @SuppressLint("InflateParams")
    private fun addQuestions() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..8) {
            val view = inflater.inflate(R.layout.item_question, null)
            view.setOnDragListener(DragListener())
            questionContainer.addView(view)
        }
    }


    @SuppressLint("InflateParams")
    private fun addAnswers() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..8) {
            val view = inflater.inflate(R.layout.item_answer, null)
            view.setOnTouchListener(DragItemTouchListener())
            answerContainer.addView(view)
        }
    }

    private inner class DragItemTouchListener : OnTouchListener {

        override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
            return if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                dragMultiple(view)
                true
            } else {
                false
            }
        }

        private fun dragMultiple(view : View) {
            val data = ClipData.newPlainText("", "")
            val shadowBuilder = DragShadowBuilder(
                view
            )
            val parent = view.parent as ViewGroup

            view.startDragAndDrop(data, shadowBuilder, view, 0)
            parent.removeView(view)
        }
    }


    private inner class DragListener : OnDragListener {

        override fun onDrag(v: View, event: DragEvent): Boolean {
            when (event.action) {
                DragEvent.ACTION_DRAG_STARTED -> {

                }
                DragEvent.ACTION_DRAG_ENTERED -> {

                }
                DragEvent.ACTION_DRAG_EXITED -> {

                }
                DragEvent.ACTION_DROP -> {
                    animateDropEffect(v as ViewGroup, event.localState as View)
                }
                DragEvent.ACTION_DRAG_ENDED -> {

                }
                else -> {
                }
            }
            return true
        }

        private fun animateDropEffect(into: ViewGroup, view: View) {
            into.addView(view)
            val params = (view.layoutParams as FrameLayout.LayoutParams)
                .apply {
                    gravity = Gravity.END
                }
            view.layoutParams = params
        }
    }
}

已使用所有 Xml。以下所有示例的 xml 下方。

/* activity_main.xml */
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    android:id="@+id/mainContainer"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">


        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="500dp"
            android:animateLayoutChanges="true">

            <LinearLayout
                android:id="@+id/questionContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:orientation="vertical">

            </LinearLayout>
        </ScrollView>

        <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:animateLayoutChanges="true">

            <LinearLayout
                android:id="@+id/answerContainer"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:orientation="horizontal">

            </LinearLayout>
        </HorizontalScrollView>

    </LinearLayout>
</FrameLayout>


/* item_question.xml */
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:padding="5dp">

    <View
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="start"
        android:background="@android:color/holo_blue_bright">

    </View>

    <View
        android:id="@+id/questionView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="end"
        android:background="@android:color/holo_orange_light">

    </View>

</FrameLayout>


/* item_answer.xml */
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="5dp"
    android:tag="Test">


    <LinearLayout
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center"
        android:background="@android:color/darker_gray">

    </LinearLayout>

</FrameLayout>

示例 2/3

用同样的方法拖拽几个元素也不成问题。这是一个有点蹩脚但简单的例子。

第二个示例的修改代码。 Xml 保持不变。

class MainActivity : AppCompatActivity() {

    var activeOneDrag : Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bind()
    }

    private fun bind() {
        addQuestions()
        addAnswers()
    }

    fun getRandomColor(): Int {
        return Color.argb(255, Random.nextInt(255),
            Random.nextInt(255), Random.nextInt(255))
    }

    @SuppressLint("InflateParams")
    private fun addQuestions() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..8) {
            val view = inflater.inflate(R.layout.item_question, null)
            view.setOnDragListener(DragListener())
            questionContainer.addView(view)
        }
    }


    @SuppressLint("InflateParams")
    private fun addAnswers() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..8) {
            val view = inflater.inflate(R.layout.item_answer, null)
            (view as ViewGroup).getChildAt(0).setBackgroundColor(getRandomColor())
            view.setOnTouchListener(DragItemTouchListener())
            answerContainer.addView(view)
        }
    }


    private inner class DragItemTouchListener : OnTouchListener {

        override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
            return if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                dragMultiple(view)
                true
            } else {
                false
            }
        }

        private fun dragMultiple(view : View) {
            val parent = view.parent as ViewGroup
            parent.removeView(view)
            /**
             * Some other logic with selective multiple View.
             * Just getting neighbor in our case
             */

            var anotherView : View? = null
            if (!activeOneDrag) {
                anotherView = parent.getChildAt(
                    parent.indexOfChild(view) + 1)
                parent.removeView(anotherView)
            }
            activeOneDrag = !activeOneDrag

            /**
             * As you can see, there is postDelay here.
             * But only for our case with animateLayoutChanges,
             * with delays removing View! In your samples, you could remove it
             * with listener on your own animation, if any!
             */
            parent.postDelayed({

                val layout = LinearLayout(this@MainActivity)
                val params = FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT)
                params.gravity = Gravity.BOTTOM
                layout.layoutParams = params
                layout.orientation = LinearLayout.HORIZONTAL


                layout.addView(view)
                if (anotherView != null) {
                    layout.addView(anotherView)
                }
                layout.visibility = INVISIBLE
                mainContainer.addView(layout)

                parent.post {
                    layout.startDragAndDrop(
                        ClipData.newPlainText("", ""),
                        DragShadowBuilder(layout), layout, 0)
                }

            }, 400)

        }
    }


    private inner class DragListener : OnDragListener {

        override fun onDrag(v: View, event: DragEvent): Boolean {
            when (event.action) {
                DragEvent.ACTION_DRAG_STARTED -> {

                }
                DragEvent.ACTION_DRAG_ENTERED -> {

                }
                DragEvent.ACTION_DRAG_EXITED -> {

                }
                DragEvent.ACTION_DROP -> {
                    val view = event.localState as View
                    (view.parent as ViewGroup).removeView(view)
                    view.visibility = VISIBLE
                    animateDropEffect(v as ViewGroup, event.localState as View)
                }
                DragEvent.ACTION_DRAG_ENDED -> {

                }
                else -> {
                }
            }
            return true
        }

        private fun animateDropEffect(into: ViewGroup, view: View) {
            into.addView(view)
            val params = (view.layoutParams as FrameLayout.LayoutParams)
                .apply {
                    gravity = Gravity.END
                }
            view.layoutParams = params
        }
    }
}

示例 3/3

正如我所见,尚不清楚如何使用动画或拖动聆听区域来更改简单动作。这是执行所有操作的另一个简单示例

class MainActivity : AppCompatActivity() {

    @Volatile
    var state : State = State.INACTIVE

    enum class State {
        ACTIVE, INACTIVE, HANDLED
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bind()
    }

    private fun bind() {
        addQuestions()
        addAnswers()
    }

    private fun getRandomColor(): Int {
        return Color.argb(255, Random.nextInt(255),
            Random.nextInt(255), Random.nextInt(255))
    }

    @SuppressLint("InflateParams")
    private fun addQuestions() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..8) {
            val view = inflater.inflate(R.layout.item_question, null)
            view.findViewById<View>(R.id.questionView)
                .setOnDragListener(DragListener())
            questionContainer.addView(view)
        }
    }


    @SuppressLint("InflateParams")
    private fun addAnswers() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..8) {
            val view = inflater.inflate(R.layout.item_answer, null)
            (view as ViewGroup).getChildAt(0).setBackgroundColor(getRandomColor())
            view.setOnTouchListener(DragItemTouchListener())
            answerContainer.addView(view)
        }
    }

    private inner class DragItemTouchListener : OnTouchListener {
        val ITEM_INDEX_D = "Index-From"

        override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
            return if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                createDrag(view)
                true
            } else {
                false
            }
        }

        private fun createDrag(view : View) {
            val parent = view.parent as ViewGroup
            view.tag = Pair(ITEM_INDEX_D,
                parent.indexOfChild(view))

            view.startDragAndDrop(ClipData.newPlainText("", ""),
                DragShadowBuilder(view), view, 0)
            parent.removeView(view)
            parent.setBackgroundColor(Color.WHITE)
        }
    }

    private inner class DragListener : OnDragListener {

        override fun onDrag(parent: View, event: DragEvent): Boolean {
            val view = event.localState as View

            when (event.action) {
                DragEvent.ACTION_DRAG_STARTED -> {
                    state = State.ACTIVE
                }
                DragEvent.ACTION_DRAG_ENTERED -> {
                }
                DragEvent.ACTION_DRAG_EXITED -> {

                }
                DragEvent.ACTION_DROP -> {
                    state = State.HANDLED
                    animateDropEffect(parent, view)
                    return true
                }
                DragEvent.ACTION_DRAG_ENDED -> {
                    if (state == State.ACTIVE) {
                        state = State.INACTIVE
                        animateMoveBack(view,
                            (view.tag as Pair<*, *>).second as Int)
                    }
                    return true
                }
                else -> {
                }
            }
            return true
        }

        private fun animateMoveBack(view: View, index : Int) {
            answerContainer.addView(view, index)
        }

        private fun animateDropEffect(into: View, view: View) {
            val parent = (into.parent as ViewGroup)
            parent.addView(view)

            val params = (view.layoutParams as FrameLayout.LayoutParams)
                .apply {
                    gravity = Gravity.END
                }
            view.layoutParams = params
            checkIsCorrect(parent)
        }

        private fun checkIsCorrect(parent : ViewGroup) {
            val correct = Random.nextBoolean()

            val colorFrom = Color.WHITE
            val colorTo : Int = if (correct) 0x8000ff00.toInt() else 0x80ff0000.toInt()
            ObjectAnimator.ofObject(
                parent,
                "backgroundColor",
                ArgbEvaluator(),
                colorFrom,
                colorTo
            )
                .setDuration(1000)
                .start()
        }
    }
}

更新

来自 cmets 部分的最新更新。我认为这就足够了,当然你需要改变。因此,只需更改两个“if”语句以符合您的要求和动画。

class MainActivity : AppCompatActivity() {

    enum class State {
        ACTIVE, INACTIVE, HANDLED
    }

    var state : State = State.INACTIVE

    var failsCount = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bind()
    }

    private fun bind() {
        addQuestions()
        addAnswers()
    }

    private fun getRandomColor(): Int {
        return Color.argb(255, Random.nextInt(255),
            Random.nextInt(255), Random.nextInt(255))
    }

    @SuppressLint("InflateParams")
    private fun addQuestions() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..3) {
            val view = inflater.inflate(R.layout.item_question, null)
            view.findViewById<View>(R.id.questionView)
                .setOnDragListener(DragListener())
            questionContainer.addView(view)
        }
    }


    @SuppressLint("InflateParams")
    private fun addAnswers() {
        val inflater = getSystemService(
            Context.LAYOUT_INFLATER_SERVICE
        ) as LayoutInflater
        for (i in 1..3) {
            val view = inflater.inflate(R.layout.item_answer, null)
            (view as ViewGroup).getChildAt(0).setBackgroundColor(getRandomColor())
            view.setOnTouchListener(DragItemTouchListener())
            answerContainer.addView(view)
        }
    }

    private inner class DragItemTouchListener : OnTouchListener {
        val ITEM_INDEX_D = "Index-From"

        override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
            return if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                createDrag(view)
                true
            } else {
                false
            }
        }

        private fun createDrag(view : View) {
            val parent = view.parent as ViewGroup
            view.tag = Pair(ITEM_INDEX_D,
                parent.indexOfChild(view))

            view.startDragAndDrop(ClipData.newPlainText("", ""),
                DragShadowBuilder(view), view, 0)
            parent.removeView(view)
            parent.setBackgroundColor(Color.WHITE)
        }
    }

    private inner class DragListener : OnDragListener {

        val ANIM_DURATION_LONG = TimeUnit.SECONDS.toMillis(1)
        val ANIM_DURATION_SHORT = TimeUnit.MILLISECONDS.toMillis(500)

        val GREEN_ALPHA = 0x8000ff00.toInt()
        val RED_ALPHA = 0x80ff0000.toInt()
        val ANIM_COLOR = "backgroundColor"

            override fun onDrag(parent: View, event: DragEvent): Boolean {
            val view = event.localState as View

            when (event.action) {
                DragEvent.ACTION_DRAG_STARTED -> {
                    state = State.ACTIVE
                }
                DragEvent.ACTION_DRAG_ENTERED -> {
                }
                DragEvent.ACTION_DRAG_EXITED -> {

                }
                DragEvent.ACTION_DROP -> {
                    state = State.HANDLED
                    animateDropEffect(parent, view)
                    return true
                }
                DragEvent.ACTION_DRAG_ENDED -> {
                    if (state == State.ACTIVE) {
                        state = State.INACTIVE
                        animateMoveBack(view,
                            (view.tag as Pair<*, *>).second as Int)
                    }
                    return true
                }
                else -> {
                }
            }
            return true
        }

        private fun animateMoveBack(view: View, index : Int) {
            answerContainer.addView(view, index)
        }

        private fun animateDropEffect(into: View, view: View) {
            val parent = (into.parent as ViewGroup)
            parent.addView(view)

            val params = (view.layoutParams as FrameLayout.LayoutParams)
                .apply {
                    gravity = Gravity.END
                }
            view.layoutParams = params
            checkIsCorrect(parent)
        }

        private fun checkIsCorrect(parent : ViewGroup) {
            val correct = false
            if (correct) {
                animateColorChange(parent, true)
                return
            }
            if (++failsCount > Companion.MAX_FAIL_COUNT) {
                animateColorChange(parent, false)
                return
            }
            animateWrongAttempt(parent)
        }

        private fun animateWrongAttempt(parent: ViewGroup) {
            val questionMark = parent.findViewById<View>(R.id.questionView)
            questionMark.setBackgroundColor(Color.RED)

            val va = ValueAnimator.ofFloat(1f, 1.1f)
            va.interpolator = BounceInterpolator()

            va.duration = ANIM_DURATION_SHORT
            va.addUpdateListener { animation ->
                questionMark.scaleX = animation.animatedValue as Float
                questionMark.scaleY = animation.animatedValue as Float
            }
            va.start()

        }

        private fun animateColorChange(parent : ViewGroup, right : Boolean) {
            val colorFrom = Color.WHITE
            ObjectAnimator
                .ofObject(parent, ANIM_COLOR,
                    ArgbEvaluator(), colorFrom,
                    if (right) GREEN_ALPHA else RED_ALPHA)
                .setDuration(ANIM_DURATION_LONG)
                .start()
        }
    }

    companion object {
        const val MAX_FAIL_COUNT = 2
    }
}

还有新的 xml。

/* activity_main.xml */
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    android:id="@+id/mainContainer"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">


        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="500dp"
            android:animateLayoutChanges="true">

            <LinearLayout
                android:id="@+id/questionContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:orientation="vertical">

            </LinearLayout>
        </ScrollView>

        <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:animateLayoutChanges="true">

            <LinearLayout
                android:id="@+id/answerContainer"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:orientation="horizontal">

            </LinearLayout>
        </HorizontalScrollView>

    </LinearLayout>
</FrameLayout>



/* item_question.xml */
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:paddingTop="10dp">

    <View
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="start"
        android:layout_margin="5dp"
        android:background="@android:color/holo_blue_bright">

    </View>

    <View
        android:id="@+id/questionView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="end"
        android:layout_margin="5dp"
        android:background="@android:color/holo_orange_light">

    </View>

</FrameLayout>



/* item_answer.xml */
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="5dp"
    android:tag="Test">


    <LinearLayout
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center"
        android:background="@android:color/darker_gray">

    </LinearLayout>

</FrameLayout>

【讨论】:

  • 在这种情况下,如果我只想拖动一个项目,我想会起作用,但如果我错过了 xml,我还需要一些东西来将不同的图像多次拖动到同一个“滑板”上。这就是为什么我提出类似拥有一个 id 或一个实现 onDragListener 的类的原因,并且在其中有正确的 id 和它自己的 id。
  • @Skizo-ozᴉʞS 缺少 xml 是什么意思?运行时内置的所有项目。我没有得到你。并拖动一些您可以以相同方式执行的项目。
  • 什么是questionContainer,什么是answerContainer?只需分享 xml,让我检查它是否是我想要的。
  • Gansa 我不是这个意思,让我编辑问题,但你很接近......
  • @Skizo-ozᴉʞS 根据您的问题,我已经准确地创建了,您需要什么。您有 Questions MarksAnswers 行。 Answer 您可以拖动到 Question 标记的磁贴,并使用 Drag 上的侦听器为错误/正确的行为设置动画(有相关的回调与从开始 Drag 传递的数据)。
【解决方案2】:

我认为,有多种方法可以做到这一点。对我来说,将屏幕分成两个主要部分似乎很好。 a) 要拥有包含项目和连接到“问号”的单个垂直列表,请参阅下图。

垂直列表中的单行

因此,通过动态添加和删除简单的View,可以轻松更改从服务器检索的项目列表的大小。一旦正确的瓷砖放置在“问号”的顶部,您将更改此 View 顶部的新视图。 b) 要创建带有可能的“答案”的底部列表,将会有带有此项目的水平列表。正如你在我们的问题中提到的。

底部水平列表


说明

a) 我真的不喜欢使用像RecyclerView 这样的Android 小部件来执行此类任务。通过少量的项目,我们可以带来很多定制。对于第一个列表,我将使用 VerticalScrollViewLinearLayoutView(与您的任何布局)。

注意。您的最后一个布局可能是ConstraintLayout。前任。 1. 在这种情况下,您拖动的物品会粘在您居住的确切位置。如果它粘在超过一半大小的特定行上,您可以更改它的视图(变为绿色或红色)。 Ex 2. 也许更好的方法是动画从瓷砖所在的地方移动到最近的带有“属性动画”的“问号”

b) 要创建底部列表,我将使用与“Horizo​​ntalListView”相同的结构。这将有助于使用“属性动画”,而不仅仅是动画拖动,还可以使用您的分级移动对象轨迹。在具有简单视图的容器中使用动态添加的项目将反映底部或顶部列表的变化。


实施

1) 每个“答案”图块的初始侦听器。

// Assign the touch listener to your view which you want to move
findViewById(R.id.myimage1).setOnTouchListener(new MyTouchListener());

// This defines your touch listener
private final class MyTouchListener implements OnTouchListener {
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            ClipData data = ClipData.newPlainText("", "");
            DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
                view);
            view.startDrag(data, shadowBuilder, view, 0);
            view.setVisibility(View.INVISIBLE);
            return true;
        } else {
        return false;
        }
    }
}

2) 在顶部列表中定义每个目标Views

findViewById(R.id.bottomright).setOnDragListener(new MyDragListener());

class MyDragListener implements OnDragListener {
    Drawable enterShape = getResources().getDrawable(
            R.drawable.shape_droptarget);
    Drawable normalShape = getResources().getDrawable(R.drawable.shape);

    @Override
    public boolean onDrag(View v, DragEvent event) {
        int action = event.getAction();
        switch (event.getAction()) {
        case DragEvent.ACTION_DRAG_STARTED:
        // do nothing
            break;
        case DragEvent.ACTION_DRAG_ENTERED:
            v.setBackgroundDrawable(enterShape);
            break;
        case DragEvent.ACTION_DRAG_EXITED:
            v.setBackgroundDrawable(normalShape);
            break;
        case DragEvent.ACTION_DROP:
            // Dropped, reassign View to ViewGroup
            View view = (View) event.getLocalState();
            ViewGroup owner = (ViewGroup) view.getParent();
            owner.removeView(view);
            LinearLayout container = (LinearLayout) v;
            container.addView(view);
            view.setVisibility(View.VISIBLE);
            break;
        case DragEvent.ACTION_DRAG_ENDED:
            v.setBackgroundDrawable(normalShape);
            default:
            break;
        }
        return true;
    }
}

3) 那就是你需要创建拖动。只是为了在ActivityView 更改中进行另一个设置。

但是,您可以查看其他几个拖放实现的示例。但是由于您使用的是简单的 ViewsScrollable 容器,因此您可以对齐每个样本以使用您的列表。

【讨论】:

  • 我发现与您发布的其他答案中描述的问题相同。我应该有办法说好的,这是正确的 id,然后为图像分配一个 id 和正确的 id 或类似的东西。但我也在寻找不同的方法,但是按照你说的做,我无法弄清楚如何说一张图像中不止一张图像是正确的。
猜你喜欢
  • 2011-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-05
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多