如何处理<OnClick>和 MotionLayout 中的 onClickListener 类似 Youtube [英] How to handle <OnClick> and onClickListener in MotionLayout similar to Youtube

查看:25
本文介绍了如何处理<OnClick>和 MotionLayout 中的 onClickListener 类似 Youtube的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试了解 MotionLayout 的工作原理,经过一些尝试后,我对 OnClick 对视图的工作方式有疑问.

我从

I have been trying to understand how MotionLayout works and after some trying I have a question as to how OnClick works for a View.

I have something that I tried from official examples. I tried something similar to the youtube swiping.

scene_24.xml

<Transition
    motion:constraintSetEnd="@+id/end"
    motion:constraintSetStart="@+id/start"
    motion:duration="1000"
    motion:motionInterpolator="linear">

    <OnSwipe
        motion:dragDirection="dragUp"
        motion:touchAnchorSide="bottom"
        motion:touchRegionId="@+id/top_image_container" />

    <ConstraintSet android:id="@id/start">

        <Constraint
            android:id="@id/top_image_container"
            android:layout_width="0dp"
            android:layout_height="320dp"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />

        <Constraint
            android:id="@id/top_image"
            android:layout_width="0dp"
            android:layout_height="0dp"
            motion:layout_constraintBottom_toBottomOf="@id/top_image_container"
            motion:layout_constraintEnd_toEndOf="@id/top_image_container"
            motion:layout_constraintStart_toStartOf="@id/top_image_container"
            motion:layout_constraintTop_toTopOf="@id/top_image_container" />

        <Constraint
            android:id="@id/recyclerview_container"
            android:layout_width="0dp"
            android:layout_height="0dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toBottomOf="@id/top_image_container" />

        <Constraint
            android:id="@id/recyclerview_front"
            android:layout_width="0dp"
            android:layout_height="0dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toBottomOf="@id/top_image_container" />

        <Constraint android:id="@+id/image_play">
            <PropertySet motion:alpha="0" />
        </Constraint>

        <Constraint android:id="@+id/image_clear">
            <PropertySet motion:alpha="0" />
        </Constraint>

        <Constraint
            android:id="@id/bottom_nav"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            motion:layout_constraintLeft_toLeftOf="parent"
            motion:layout_constraintRight_toRightOf="parent"
            motion:layout_constraintTop_toBottomOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@id/end">

        <Constraint
            android:id="@id/top_image_container"
            android:layout_width="0dp"
            android:layout_height="52dp"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            motion:layout_constraintBottom_toTopOf="@id/bottom_nav"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />

        <Constraint
            android:id="@id/top_image"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginTop="2dp"
            android:layout_marginBottom="2dp"
            motion:layout_constraintBottom_toBottomOf="@id/top_image_container"
            motion:layout_constraintDimensionRatio="H,1:2.5"
            motion:layout_constraintStart_toStartOf="@id/top_image_container"
            motion:layout_constraintTop_toTopOf="@id/top_image_container" />

        <Constraint
            android:id="@id/recyclerview_container"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            motion:layout_constraintBottom_toTopOf="@id/bottom_nav"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toBottomOf="@id/top_image_container" />

        <Constraint
            android:id="@id/recyclerview_front"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:alpha="0"
            motion:layout_constraintBottom_toBottomOf="@id/top_image_container"
            motion:layout_constraintEnd_toEndOf="@id/top_image_container"
            motion:layout_constraintStart_toStartOf="@id/top_image_container"
            motion:layout_constraintTop_toBottomOf="@id/top_image_container" />

        <Constraint android:id="@+id/image_play">
            <PropertySet motion:alpha="1" />
        </Constraint>

        <Constraint android:id="@id/image_clear">
            <PropertySet motion:alpha="1" />
        </Constraint>


        <Constraint
            android:id="@id/bottom_nav"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="?android:attr/windowBackground"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintLeft_toLeftOf="parent"
            motion:layout_constraintRight_toRightOf="parent" />
    </ConstraintSet>

    <KeyFrameSet>

        <KeyPosition
            motion:curveFit="linear"
            motion:framePosition="90"
            motion:motionTarget="@id/top_image"
            motion:percentWidth="0"
            motion:percentX="0" />

        <KeyPosition
            motion:curveFit="linear"
            motion:framePosition="90"
            motion:motionTarget="@id/top_image_container"
            motion:percentWidth="0" />

        <KeyPosition
            motion:curveFit="linear"
            motion:framePosition="90"
            motion:motionTarget="@id/recyclerview_container"
            motion:percentWidth="0" />

        <KeyAttribute
            android:alpha="0"
            motion:framePosition="75"
            motion:motionTarget="@id/recyclerview_front" />

        <KeyAttribute
            android:alpha="0.10"
            motion:framePosition="90"
            motion:motionTarget="@id/image_clear" />

        <KeyAttribute
            android:alpha="0.10"
            motion:framePosition="90"
            motion:motionTarget="@id/image_play" />
    </KeyFrameSet>
</Transition>

motion_layout_anim:

<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/motionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#444"
    app:layoutDescription="@xml/scene_24"
    tools:ignore="contentDescription"
    >

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/top_image_container"
        android:layout_width="match_parent"
        android:layout_height="320dp"
        android:background="?android:attr/windowBackground"
        app:layout_constrainedWidth="true"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <com.google.android.youtube.player.YouTubePlayerView
        android:id="@+id/top_image"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="@id/top_image_container"
        app:layout_constraintBottom_toBottomOf="@id/top_image_container"
        app:layout_constraintStart_toStartOf="@id/top_image_container"
        app:layout_constraintEnd_toEndOf="@id/top_image_container" />
<!--    <ImageView
        android:id="@+id/image_play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        app:srcCompat="@drawable/ic_play_arrow_gray_32dp"
        android:alpha="0"
        app:layout_constraintEnd_toStartOf="@id/image_clear"
        app:layout_constraintTop_toTopOf="@id/top_image_container"
        app:layout_constraintBottom_toBottomOf="@id/top_image_container"
        />

    <ImageView
        android:id="@+id/image_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        app:srcCompat="@drawable/ic_clear_gray_32dp"
        android:alpha="0"
        app:layout_constraintEnd_toEndOf="@id/top_image_container"
        app:layout_constraintBottom_toBottomOf="@id/top_image_container"
        app:layout_constraintTop_toTopOf="@id/top_image_container"
        />-->

    <FrameLayout
        android:id="@+id/recyclerview_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/top_image_container"
        />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview_front"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/top_image_container" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?android:attr/windowBackground"
        app:layout_constraintTop_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu"
        />
</androidx.constraintlayout.motion.widget.MotionLayout>

Coming to the point now, I have three questions:

  • if I use youtube player and if I place those play icon and close, my player does not work as I get this. How does Youtube work then (provided I took this example from the official documentation)?

W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is obscured by android.widget.ImageView{3ae28d60 V.ED.... ........ 704,320-704,320 #7f09009f app:id/image_play}. The obscuring view is inside the player view's interior zone. The distance (px) between each edge of the obscuring view and each corresponding interior zone edge is: left: 704, top: 320, right: 64, bottom: 320. .

  • My video stops when I minimize i.e, use the OnSwipe and the player becomes smaller. I tried to understand this but I just wonder how they play it in the official Youtube app.

W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to the player's view being too small. The YouTubePlayerView is 384dp wide (minimum is 200dp) and 87dp high (minimum is 110dp).

  • Last but not the least and the most important how exactly do I make the Youtube player to pause/play and use any other controls when I use motion:touchRegionId="@+id/top_image_container" when I use it either the player becomes unclickable/unfocussable or even after using the touchRegionId the player can only be swiped down from the empty place below(why though).

P.S: What I have tested and tried, though doesn't work.

  1. MotionLayout: MotionScene OnClick overrides setOnClickListener
  2. Can we use OnSwipe and OnClick in the same <Transition> for Android MotionLayout?

解决方案

Official Youtube application uses ExoPlayer inside it, and as I understand they don't use their Youtube SDK :) So, ExoPlayer hasn't restrictions: width/height/overlays.

I faced the same problem as yours, and I used this library - android-youtube-player for playing a youtube video.

Regarding screen touches, when you touch VideoView(youtube) it intercepts the TouchEvent, so, we need to intercept TouchEvent before VideoView catch it. We need to understand what kind of event it is. If it's Swipe -> we intercept event in parent view. If it Click -> we don't intercept this event.

Example of custom MotionLayout I got from this article. It catches touches only from the selected view. Code sample:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@+id/start"
        motion:duration="1000"
        motion:motionInterpolator="linear">

        <OnSwipe
            motion:touchAnchorId="@+id/top_image_container"
            motion:touchAnchorSide="bottom"
            motion:dragDirection="dragUp" />

        <ConstraintSet android:id="@id/start">

            <Constraint
                android:id="@id/top_image_container"
                android:layout_width="0dp"
                android:layout_height="233dp"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"  />

            <Constraint
                android:id="@id/top_image"
                android:layout_width="0dp"
                android:layout_height="0dp"
                motion:layout_constraintTop_toTopOf="@id/top_image_container"
                motion:layout_constraintBottom_toBottomOf="@id/top_image_container"
                motion:layout_constraintStart_toStartOf="@id/top_image_container"
                motion:layout_constraintEnd_toEndOf="@id/top_image_container"
                />

            <Constraint
                android:id="@id/recyclerview_container"
                android:layout_width="0dp"
                android:layout_height="0dp"
                motion:layout_constraintTop_toBottomOf="@id/top_image_container"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent" />

            <Constraint
                android:id="@id/recyclerview_front"
                android:layout_width="0dp"
                android:layout_height="0dp"
                motion:layout_constraintTop_toBottomOf="@id/top_image_container"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent"/>

            <Constraint android:id="@id/image_play" >
                <PropertySet motion:alpha="0" />
            </Constraint>

            <Constraint android:id="@id/image_clear" >
                <PropertySet motion:alpha="0" />
            </Constraint>

        </ConstraintSet>

        <ConstraintSet android:id="@id/end">

            <Constraint
                android:id="@id/top_image_container"
                android:layout_width="0dp"
                android:layout_height="80dp"
                android:layout_marginBottom="56dp"
                android:layout_marginStart="0dp"
                android:layout_marginEnd="0dp"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent" />

            <Constraint
                android:id="@+id/close"
                android:layout_width="28dp"
                android:layout_height="28dp"
                android:layout_marginRight="16dp"
                motion:layout_constraintTop_toTopOf="@+id/playerContainer"
                motion:layout_constraintRight_toRightOf="@+id/playerContainer"
                motion:layout_constraintBottom_toBottomOf="@+id/playerContainer"/>

            <Constraint
                android:id="@id/top_image"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_marginTop="0dp"
                android:layout_marginBottom="0dp"
                motion:layout_constraintTop_toTopOf="@id/top_image_container"
                motion:layout_constraintBottom_toBottomOf="@id/top_image_container"
                motion:layout_constraintStart_toStartOf="@id/top_image_container"
                motion:layout_constraintDimensionRatio="H,1:1.8"
                />

            <Constraint
                android:id="@id/recyclerview_container"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_marginBottom="56dp"
                android:layout_marginStart="0dp"
                android:layout_marginEnd="0dp"
                motion:layout_constraintTop_toBottomOf="@id/top_image_container"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent" />

            <Constraint
                android:id="@id/recyclerview_front"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:alpha="0"
                motion:layout_constraintTop_toBottomOf="@id/top_image_container"
                motion:layout_constraintBottom_toBottomOf="@id/top_image_container"
                motion:layout_constraintEnd_toEndOf="@id/top_image_container"
                motion:layout_constraintStart_toStartOf="@id/top_image_container"
                />

            <Constraint android:id="@id/image_play" >
                <PropertySet motion:alpha="1" />
            </Constraint>

            <Constraint android:id="@id/image_clear" >
                <PropertySet motion:alpha="1" />
            </Constraint>
        </ConstraintSet>

        <KeyFrameSet>

            <KeyPosition
                motion:motionTarget="@id/top_image"
                motion:framePosition="90"
                motion:percentWidth="0"
                motion:percentX="0"
                motion:curveFit="linear"
                />

            <KeyPosition
                motion:motionTarget="@id/top_image_container"
                motion:framePosition="90"
                motion:percentWidth="0"
                motion:curveFit="linear"
                />

            <KeyPosition
                motion:motionTarget="@id/recyclerview_container"
                motion:framePosition="90"
                motion:percentWidth="0"
                motion:curveFit="linear"
                />

            <KeyAttribute
                android:alpha="0"
                motion:framePosition="75"
                motion:motionTarget="@id/recyclerview_front" />

            <KeyAttribute
                android:alpha="0.10"
                motion:framePosition="90"
                motion:motionTarget="@id/image_clear" />

            <KeyAttribute
                android:alpha="0.10"
                motion:framePosition="90"
                motion:motionTarget="@id/image_play" />

            <KeyAttribute
                android:alpha="0"
                motion:framePosition="95"
                motion:motionTarget="@id/close" />
        </KeyFrameSet>
    </Transition>

</MotionScene>

SingleViewTouchableMotionLayout.kt

import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import androidx.constraintlayout.motion.widget.MotionLayout
import com.example.android.R

class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeSet? = null) : MotionLayout(context, attributeSet) {

    private val viewRect = Rect()
    private var touchStarted = false

    private val viewToDetectTouch by lazy {
        findViewById<View>(R.id.top_image_container)
    }

    private val gestureListener by lazy {
        object : GestureDetector.SimpleOnGestureListener() {
            override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
                viewToDetectTouch.getHitRect(viewRect)
                return viewRect.contains(e1.x.toInt(), e1.y.toInt())
            }
        }
    }

    private val  gestureDetector by lazy {
        GestureDetector(context, gestureListener)
    }

    init {
        setTransitionListener(object : MotionLayout.TransitionListener {
            override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {

            }

            override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {

            }

            override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
            }

            override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {
                touchStarted = false
            }
        })

    }


    override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
        return gestureDetector.onTouchEvent(event)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.actionMasked) {
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                touchStarted = false
                return super.onTouchEvent(event)
            }
        }
        if (!touchStarted) {
            viewToDetectTouch.getHitRect(viewRect)
            touchStarted = viewRect.contains(event.x.toInt(), event.y.toInt())
        }
        return touchStarted && super.onTouchEvent(event)
    }
}

fragment_video_new.kt

<?xml version="1.0" encoding="utf-8"?>
<com.example.android.android.features.music.SingleViewTouchableMotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/motionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/scene_24"
    tools:ignore="contentDescription">

    <FrameLayout
        app:layout_constraintTop_toTopOf="@+id/top_image_container"
        app:layout_constraintBottom_toBottomOf="@+id/recyclerview_container"
        android:id="@+id/playerContainer"
        android:layout_width="match_parent"
        android:layout_height="0dp"/>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/top_image_container"
        android:layout_width="match_parent"
        android:layout_height="320dp"
        android:background="?android:attr/windowBackground"
        app:layout_constrainedWidth="true"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
        android:id="@+id/top_image"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="@id/top_image_container"
        app:layout_constraintBottom_toBottomOf="@id/top_image_container"
        app:layout_constraintStart_toStartOf="@id/top_image_container"
        app:layout_constraintEnd_toEndOf="@id/top_image_container" />

    <ImageView
        android:id="@+id/image_play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:alpha="0"
        app:layout_constraintEnd_toStartOf="@id/image_clear"
        app:layout_constraintTop_toTopOf="@id/top_image_container"
        app:layout_constraintBottom_toBottomOf="@id/top_image_container"
        />

    <ImageView
        android:id="@+id/image_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:alpha="0"
        app:layout_constraintEnd_toEndOf="@id/top_image_container"
        app:layout_constraintBottom_toBottomOf="@id/top_image_container"
        app:layout_constraintTop_toTopOf="@id/top_image_container" />

    <FrameLayout
        android:id="@+id/recyclerview_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/top_image_container" />


    <ImageView
        android:id="@+id/close"
        android:layout_width="28dp"
        android:layout_height="28dp"
        android:alpha="0"
        app:layout_constraintTop_toTopOf="@+id/playerContainer"
        app:layout_constraintRight_toRightOf="@+id/playerContainer"
        app:layout_constraintBottom_toBottomOf="@+id/playerContainer"
        app:srcCompat="@drawable/ic_close" />

    <com.revolut.rxdiffadapter.AsyncDiffRecyclerView
        android:id="@+id/recyclerview_front"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/top_image_container" />
</com.example.android.android.features.music.SingleViewTouchableMotionLayout>

gif

这篇关于如何处理&lt;OnClick&gt;和 MotionLayout 中的 onClickListener 类似 Youtube的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆