如何在MotionLayout中处理与YouTube类似的<OnClick>和onClickListener

时间:2019-09-06 10:08:04

标签: android youtube-api android-motionlayout

我一直试图了解MotionLayout的工作方式,经过一番尝试之后,我对OnClick如何为View产生了疑问。

我从official examples尝试过一些东西。我尝试过类似youtube刷卡的操作。

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>

现在,我有三个问题:

  • 如果我使用youtube播放器,并且放置了这些播放图标并关闭,则播放器无法正常工作。然后,Youtube如何工作(前提是我从官方文档中借鉴了此示例)?
  

W / YouTubeAndroidPlayerAPI:由于播放器顶部的未授权覆盖,导致YouTube视频播放停止。 android.widget.ImageView {3ae28d60 V.ED .... ........ 704,320-704,320#7f09009f app:id / image_play}遮住了YouTubePlayerView。遮挡视图位于播放器视图的内部区域内。遮挡视图的每个边缘与相应的内部区域边缘之间的距离(px)为:左:704,上:320,右:64,下:320。

  • 当我最小化视频时,即使用OnSwipe时,视频停止播放,播放器变小。我试图了解this,但我只是想知道他们如何在YouTube官方应用中播放它。
  

W / YouTubeAndroidPlayerAPI:由于播放器的视图过小,导致YouTube视频播放停止。 YouTubePlayerView的宽度为384dp(最小为200dp),高度为87dp(最小为110dp)。

  • 最后但并非最不重要和最重要的一点是,当我使用motion:touchRegionId="@+id/top_image_container"时,如何使Youtube播放器暂停/播放并使用其他控件,或者播放器变得无法点击/无法对焦甚至使用touchRegionId后,只能从下面的空白处向玩家刷卡(为什么)。

PS:尽管没有用,但我已经测试过并尝试过。

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

1 个答案:

答案 0 :(得分:0)

Youtube官方应用uses ExoPlayer inside it,据我了解,他们不使用自己的Youtube SDK :)因此,ExoPlayer没有限制:宽度/高度/覆盖。

我遇到了与您相同的问题,并且我使用了这个库-android-youtube-player来播放youtube视频。

关于屏幕触摸,当您触摸VideoView(youtube)时,它会拦截TouchEvent,因此,我们需要在VideoView捕获它之前先拦截TouchEvent。我们需要了解这是什么类型的事件。如果是Swipe->,我们将在父视图中拦截事件。如果点击->,我们不会拦截此事件。

我从this article获得的自定义MotionLayout示例。它仅捕获所选视图中的触摸。代码示例:

<?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 enter image description here