Can we use OnSwipe and OnClick in the same

2020-06-29 02:16发布

问题:

I want to play animation when user clicks or swipes. But can we handle both behaviours in MotionLayout? They work separately perfectly, but if I add OnClick and OnSwipe in the same scene, only OnClick works. Is there any workarounds?

回答1:

Sure, just handle the onTouch event in your parent class. Then decide what you are doing with it and what to send it to.

onTouch(touchEvent){
    motionLayout.doClickIfYouWant(touchEvent)
    motionLayout.doSwipeIfYouWant(touchEvent)
}

Pseudo code, but you can send it to both if you catch it first and decide who gets it. Also don't forget to return handled boolean flag from onTouch callback to ensure it doesn't get handled twice. Lastly, if other items are touchable on the screen you may have to check the x,y of your touch to determine if it should go to the motionLayout or just return "not handled" and let the native behavior pass the touch on through.

Hope that helps. Also if the motionLayout class doesn't expose the methods you need to touch to send the correct touch event to more then one place, you can still get it using reflection. Of course reflection can be a little slower, so use with caution, but I've had to do it before for a layout class that had children images that I needed to move around, and controlled the touch at a parent level to decide if the image gets it or not, but it was not publicly available, so I looked at the code and touched it via reflection with no issues. Treat that as a last resort though, and maybe everything you need is exposed.

Also be aware some engineer despise reflection lol, so code with caution.



回答2:

Yes, you can work around this by removing the onClick behavior from your MotionScene and implement the click yourself by extending the MotionLayout and overriding dispatchTouchEvent.

In this function, you decide if the touch event is a click inside the 'target area' where you want the onClick behavior to occur.

override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        if (touchEventInsideTargetView(clickableArea, ev)) {
            when (ev.action) {
                MotionEvent.ACTION_DOWN -> {
                    startX = ev.x
                    startY = ev.y
                }
                MotionEvent.ACTION_UP   -> {
                    val endX = ev.x
                    val endY = ev.y
                    if (isAClick(startX!!, endX, startY!!, endY)) {
                        if (doClickTransition()) {
                            return true
                        }
                    }
                }
            }
        }
 return super.dispatchTouchEvent(ev)
}

A post on this and a full code example can be found here: https://medium.com/vrt-digital-studio/picture-in-picture-video-overlay-with-motionlayout-a9404663b9e7