add function to subtitle layer
This commit is contained in:
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.GestureDetector
|
import android.view.GestureDetector
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewConfiguration
|
import android.view.ViewConfiguration
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.media3.ui.PlayerView
|
import androidx.media3.ui.PlayerView
|
||||||
@@ -123,6 +124,26 @@ class OralTrainerPlayerView @JvmOverloads constructor(
|
|||||||
verticalSwipeListener = listener
|
verticalSwipeListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Forwards touches from an overlay (for example a subtitle layer) as player gestures. */
|
||||||
|
fun forwardGestureFrom(source: View, event: MotionEvent): Boolean {
|
||||||
|
if (controller == null || !gestureControls.enabled) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val sourceLocation = IntArray(2).also(source::getLocationOnScreen)
|
||||||
|
val playerLocation = IntArray(2).also(::getLocationOnScreen)
|
||||||
|
val playerEvent = MotionEvent.obtain(event).apply {
|
||||||
|
offsetLocation(
|
||||||
|
(playerLocation[0] - sourceLocation[0]).toFloat(),
|
||||||
|
(playerLocation[1] - sourceLocation[1]).toFloat(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
handleLongPressSpeed(playerEvent) || gestureDetector.onTouchEvent(playerEvent)
|
||||||
|
} finally {
|
||||||
|
playerEvent.recycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
|
return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.graphics.drawable.GradientDrawable
|
|||||||
import android.graphics.drawable.InsetDrawable
|
import android.graphics.drawable.InsetDrawable
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -166,7 +167,28 @@ internal class PlayerChrome(
|
|||||||
addView(createPlayerView())
|
addView(createPlayerView())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val subtitleContainer = LinearLayout(activity).apply {
|
val subtitleContainer = object : LinearLayout(activity) {
|
||||||
|
private var forwardTouchToPlayer = false
|
||||||
|
|
||||||
|
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||||
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||||
|
forwardTouchToPlayer = !isTouchOverInteractiveControl(this, event)
|
||||||
|
}
|
||||||
|
val forwarded = if (forwardTouchToPlayer) {
|
||||||
|
bindings.playerView.forwardGestureFrom(this, event)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
val handled = forwarded || super.dispatchTouchEvent(event)
|
||||||
|
if (event.actionMasked == MotionEvent.ACTION_UP ||
|
||||||
|
event.actionMasked == MotionEvent.ACTION_CANCEL
|
||||||
|
) {
|
||||||
|
forwardTouchToPlayer = false
|
||||||
|
}
|
||||||
|
return handled
|
||||||
|
}
|
||||||
|
|
||||||
|
}.apply {
|
||||||
orientation = LinearLayout.VERTICAL
|
orientation = LinearLayout.VERTICAL
|
||||||
layoutParams = FrameLayout.LayoutParams(
|
layoutParams = FrameLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
@@ -503,4 +525,33 @@ internal class PlayerChrome(
|
|||||||
}
|
}
|
||||||
view.startAnimation(animation)
|
view.startAnimation(animation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Lets controls own their touches while the subtitle background drives player gestures. */
|
||||||
|
private fun isTouchOverInteractiveControl(root: View, event: MotionEvent): Boolean =
|
||||||
|
hasInteractiveTouchTarget(root, event.rawX, event.rawY)
|
||||||
|
|
||||||
|
private fun hasInteractiveTouchTarget(view: View, screenX: Float, screenY: Float): Boolean {
|
||||||
|
if (view.visibility != View.VISIBLE || !view.isEnabled) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (view.isClickable || view.isLongClickable || view.isContextClickable) {
|
||||||
|
val location = IntArray(2).also(view::getLocationOnScreen)
|
||||||
|
if (screenX >= location[0] &&
|
||||||
|
screenX < location[0] + view.width &&
|
||||||
|
screenY >= location[1] &&
|
||||||
|
screenY < location[1] + view.height
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (view !is ViewGroup) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (index in view.childCount - 1 downTo 0) {
|
||||||
|
if (hasInteractiveTouchTarget(view.getChildAt(index), screenX, screenY)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user