Android 中的浮动视频视图
Floating Video View in Android
我想做的是:
我有一个带有滚动视图且顶部有视频的片段。我想要实现的是让视频在我滚动时浮动。
与此 link 类似的行为:https://www.independentarabia.com/jsonfeed/api/v2/node/34291
我查看了画中画模式,但没有成功
谁能告诉我如何实现这种行为?
万一有人想做这样的事情:
我参考了jw播放器库:
scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { v, _, scrollY, _, oldScrollY ->
x = 0
if (scrollY > 200) {
if (!mPlayerContainer.isMovable) {
movable = false
x = 2
} else {
x = 0
val momentView = v.getChildAt(v.childCount - 1)
val diff = (momentView.bottom - (scroll.height + scroll
.scrollY))
if (diff < 50) {
val layoutParamsNew =
RelativeLayout.LayoutParams(mPlayerContainer.width, mPlayerContainer.height)
layoutParamsNew.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
layoutParamsNew.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
val displayMetrics = resources.displayMetrics
layoutParamsNew.setMargins(
0,
0,
(displayMetrics.density * 16).roundToInt(),
(displayMetrics.density * 16).roundToInt()
)
mPlayerContainer.layoutParams = layoutParamsNew
} else {
val layoutParamsNew =
RelativeLayout.LayoutParams(mPlayerContainer.width, mPlayerContainer.height)
layoutParamsNew.addRule(RelativeLayout.CENTER_VERTICAL)
layoutParamsNew.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
val displayMetrics = resources.displayMetrics
layoutParamsNew.setMargins(
0,
0,
(displayMetrics.density * 16).roundToInt(),
(displayMetrics.density * 16).roundToInt()
)
mPlayerContainer.layoutParams = layoutParamsNew
}
}
} else if (scrollY < 200 && mPlayerContainer.isMovable) {
movable = true
x = 1
}
if (x != 0) {
toggleMovablePlayer()
}
})
private fun toggleMovablePlayer() {
if (!movable) {
// Set the player container to movable, in order to intercept touch events.
mPlayerContainer.isMovable = true
// Disable fullscreen rotation handling on the JW Player.
mPlayerView!!.setFullscreen(mPlayerView!!.fullscreen, false)
// Disable controls.
mPlayerView!!.controls = false
if (mPlayerState != PlayerState.PLAYING && mPlayerState != PlayerState.BUFFERING) {
// Start playback in case the user hasn't done this yet, since we don't want to have
// a movable player that does not play anything...
mPlayerView!!.play()
}
// Scale the player.
mInitialLayoutParams = mPlayerContainer.layoutParams
val newWidth = (mPlayerContainer.width / SCALING_FACTOR)
val newHeight = (mPlayerContainer.height / SCALING_FACTOR)
val layoutParams = RelativeLayout.LayoutParams(newWidth.toInt(), newHeight.toInt())
// Position the player in the right bottom corner.
mPlayerContainer.layoutParams = getInitialMovablePlayerLayoutParams(layoutParams)
// Set an onTouchListener on the player which handles MotionEvents.
mPlayerContainer.setOnTouchListener(View.OnTouchListener { v, event ->
if (v.id == R.id.player_container) {
val layoutParams = v.layoutParams as RelativeLayout.LayoutParams
when (event.action) {
MotionEvent.ACTION_DOWN ->
// Notify the MovablePlayerLayout that we started consuming
// events in order to receive ACTION_MOVE events.
return@OnTouchListener true
MotionEvent.ACTION_MOVE -> {
var topMargin = event.rawY.toInt() - v.height
var leftMargin = event.rawX.toInt() - v.width / 2
// Make sure that the view can not go "out of bounds"
if (topMargin < 0) {
// Out of bounds: TOP
topMargin = 0
}
if (topMargin > mContentContainer.height - mPlayerContainer.height) {
// Out of bounds: BOTTOM
topMargin = mContentContainer.height - mPlayerContainer.height
}
if (leftMargin < 0) {
// Out of bounds: LEFT
leftMargin = 0
}
if (leftMargin > mContentContainer.width - mPlayerContainer.width) {
// Out of bounds: RIGHT
leftMargin = mContentContainer.width - mPlayerContainer.width
}
layoutParams.topMargin = topMargin
layoutParams.leftMargin = leftMargin
// Make sure the align rules have been removed.
layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
layoutParams.removeRule(RelativeLayout.CENTER_VERTICAL)
layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT)
layoutParams.rightMargin = 0
layoutParams.bottomMargin = 0
// Set the new layout parameters
v.layoutParams = layoutParams
return@OnTouchListener true
}
}
}
false
})
} else {
// Disable the movable property of the MovableViewLayout.
mPlayerContainer.isMovable = false
// Restore the initial layout parameters.
mPlayerContainer.layoutParams = mInitialLayoutParams
// Remove the onTouchListener.
mPlayerContainer.setOnTouchListener(null)
// Re-enable the controls.
mPlayerView!!.controls = true
// Re-enable fullscreen rotation handling, and go to fullscreen if we're in landscape mode.
mPlayerView!!.setFullscreen(
resources.configuration.orientation === Configuration.ORIENTATION_LANDSCAPE,
true
)
}
}
private fun setInitialLayoutParams() {
val displayMetrics = resources.displayMetrics
if (resources.configuration.orientation === Configuration.ORIENTATION_PORTRAIT) {
/*mPlayerContainer.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, displayMetrics.widthPixels / 16 * 9
) // 16:9*/
mPlayerContainer.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
200f,
resources.displayMetrics
).toInt()
)
} else {
// We need to use height to calculate a 16:9 ratio since we're in landscape mode.
mPlayerContainer.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, displayMetrics.heightPixels / 16 * 9
) // 16:9
// Toggle fullscreen, since we're in landscape mode.
mPlayerView!!.setFullscreen(true, true)
}
}
/**
* Positions the movable player to the right bottom corner.
*
* @param layoutParams
* @return
*/
private fun getInitialMovablePlayerLayoutParams(layoutParams: RelativeLayout.LayoutParams): RelativeLayout.LayoutParams {
layoutParams.addRule(RelativeLayout.CENTER_VERTICAL)
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
val displayMetrics = resources.displayMetrics
layoutParams.setMargins(0, 0, Math.round(displayMetrics.density * 16), Math.round(displayMetrics.density * 16))
return layoutParams
}
我想做的是:
我有一个带有滚动视图且顶部有视频的片段。我想要实现的是让视频在我滚动时浮动。
与此 link 类似的行为:https://www.independentarabia.com/jsonfeed/api/v2/node/34291
我查看了画中画模式,但没有成功
谁能告诉我如何实现这种行为?
万一有人想做这样的事情: 我参考了jw播放器库:
scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { v, _, scrollY, _, oldScrollY ->
x = 0
if (scrollY > 200) {
if (!mPlayerContainer.isMovable) {
movable = false
x = 2
} else {
x = 0
val momentView = v.getChildAt(v.childCount - 1)
val diff = (momentView.bottom - (scroll.height + scroll
.scrollY))
if (diff < 50) {
val layoutParamsNew =
RelativeLayout.LayoutParams(mPlayerContainer.width, mPlayerContainer.height)
layoutParamsNew.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
layoutParamsNew.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
val displayMetrics = resources.displayMetrics
layoutParamsNew.setMargins(
0,
0,
(displayMetrics.density * 16).roundToInt(),
(displayMetrics.density * 16).roundToInt()
)
mPlayerContainer.layoutParams = layoutParamsNew
} else {
val layoutParamsNew =
RelativeLayout.LayoutParams(mPlayerContainer.width, mPlayerContainer.height)
layoutParamsNew.addRule(RelativeLayout.CENTER_VERTICAL)
layoutParamsNew.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
val displayMetrics = resources.displayMetrics
layoutParamsNew.setMargins(
0,
0,
(displayMetrics.density * 16).roundToInt(),
(displayMetrics.density * 16).roundToInt()
)
mPlayerContainer.layoutParams = layoutParamsNew
}
}
} else if (scrollY < 200 && mPlayerContainer.isMovable) {
movable = true
x = 1
}
if (x != 0) {
toggleMovablePlayer()
}
})
private fun toggleMovablePlayer() {
if (!movable) {
// Set the player container to movable, in order to intercept touch events.
mPlayerContainer.isMovable = true
// Disable fullscreen rotation handling on the JW Player.
mPlayerView!!.setFullscreen(mPlayerView!!.fullscreen, false)
// Disable controls.
mPlayerView!!.controls = false
if (mPlayerState != PlayerState.PLAYING && mPlayerState != PlayerState.BUFFERING) {
// Start playback in case the user hasn't done this yet, since we don't want to have
// a movable player that does not play anything...
mPlayerView!!.play()
}
// Scale the player.
mInitialLayoutParams = mPlayerContainer.layoutParams
val newWidth = (mPlayerContainer.width / SCALING_FACTOR)
val newHeight = (mPlayerContainer.height / SCALING_FACTOR)
val layoutParams = RelativeLayout.LayoutParams(newWidth.toInt(), newHeight.toInt())
// Position the player in the right bottom corner.
mPlayerContainer.layoutParams = getInitialMovablePlayerLayoutParams(layoutParams)
// Set an onTouchListener on the player which handles MotionEvents.
mPlayerContainer.setOnTouchListener(View.OnTouchListener { v, event ->
if (v.id == R.id.player_container) {
val layoutParams = v.layoutParams as RelativeLayout.LayoutParams
when (event.action) {
MotionEvent.ACTION_DOWN ->
// Notify the MovablePlayerLayout that we started consuming
// events in order to receive ACTION_MOVE events.
return@OnTouchListener true
MotionEvent.ACTION_MOVE -> {
var topMargin = event.rawY.toInt() - v.height
var leftMargin = event.rawX.toInt() - v.width / 2
// Make sure that the view can not go "out of bounds"
if (topMargin < 0) {
// Out of bounds: TOP
topMargin = 0
}
if (topMargin > mContentContainer.height - mPlayerContainer.height) {
// Out of bounds: BOTTOM
topMargin = mContentContainer.height - mPlayerContainer.height
}
if (leftMargin < 0) {
// Out of bounds: LEFT
leftMargin = 0
}
if (leftMargin > mContentContainer.width - mPlayerContainer.width) {
// Out of bounds: RIGHT
leftMargin = mContentContainer.width - mPlayerContainer.width
}
layoutParams.topMargin = topMargin
layoutParams.leftMargin = leftMargin
// Make sure the align rules have been removed.
layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
layoutParams.removeRule(RelativeLayout.CENTER_VERTICAL)
layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT)
layoutParams.rightMargin = 0
layoutParams.bottomMargin = 0
// Set the new layout parameters
v.layoutParams = layoutParams
return@OnTouchListener true
}
}
}
false
})
} else {
// Disable the movable property of the MovableViewLayout.
mPlayerContainer.isMovable = false
// Restore the initial layout parameters.
mPlayerContainer.layoutParams = mInitialLayoutParams
// Remove the onTouchListener.
mPlayerContainer.setOnTouchListener(null)
// Re-enable the controls.
mPlayerView!!.controls = true
// Re-enable fullscreen rotation handling, and go to fullscreen if we're in landscape mode.
mPlayerView!!.setFullscreen(
resources.configuration.orientation === Configuration.ORIENTATION_LANDSCAPE,
true
)
}
}
private fun setInitialLayoutParams() {
val displayMetrics = resources.displayMetrics
if (resources.configuration.orientation === Configuration.ORIENTATION_PORTRAIT) {
/*mPlayerContainer.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, displayMetrics.widthPixels / 16 * 9
) // 16:9*/
mPlayerContainer.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
200f,
resources.displayMetrics
).toInt()
)
} else {
// We need to use height to calculate a 16:9 ratio since we're in landscape mode.
mPlayerContainer.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, displayMetrics.heightPixels / 16 * 9
) // 16:9
// Toggle fullscreen, since we're in landscape mode.
mPlayerView!!.setFullscreen(true, true)
}
}
/**
* Positions the movable player to the right bottom corner.
*
* @param layoutParams
* @return
*/
private fun getInitialMovablePlayerLayoutParams(layoutParams: RelativeLayout.LayoutParams): RelativeLayout.LayoutParams {
layoutParams.addRule(RelativeLayout.CENTER_VERTICAL)
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
val displayMetrics = resources.displayMetrics
layoutParams.setMargins(0, 0, Math.round(displayMetrics.density * 16), Math.round(displayMetrics.density * 16))
return layoutParams
}