What I am trying to do is the following:
I have a fragment that has scrollview with a video on top. What I am a trying to achieve is having the video to float when I scroll.
Similar behavior to this link: https://www.independentarabia.com/jsonfeed/api/v2/node/34291
I looked into picture in picture mode but with no luck
Can anyone give me an idea of how this behavior can be achieved?
In case someone was looking to do something like this:
I referred to the jw player library:
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
}
Related
I'm making a app with some on screen widgets to give game player some advantages, users need to click my widgets while they have a finger on movement controller of the game under the overlay, else my app will be a disadvantage because they unable to control the game while interacting my widget.
Xposed is allowed, but I don't know where's the code in AOSP controlling this limit.
Here's my code, and its not working
#SuppressLint("ClickableViewAccessibility")
override fun onServiceStarted() {
val windowManager = MyApplication.instance.getSystemService(VpnService.WINDOW_SERVICE) as WindowManager
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
params.gravity = Gravity.TOP or Gravity.END
params.x = 0 // Initial Position of window
params.y = 100 // Initial Position of window
val layout = LinearLayout(ctx)
val imageView = ImageView(ctx)
imageView.setImageResource(R.mipmap.ic_launcher_round)
imageView.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
var dragPosX = 0f
var dragPosY = 0f
var pressDownTime = System.currentTimeMillis()
imageView.setOnClickListener {
toggle(windowManager, ctx)
}
imageView.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
dragPosX = event.rawX
dragPosY = event.rawY
pressDownTime = System.currentTimeMillis()
true
}
MotionEvent.ACTION_UP -> {
if (System.currentTimeMillis() - pressDownTime < 500) {
v.performClick()
}
true
}
MotionEvent.ACTION_MOVE -> {
if (System.currentTimeMillis() - pressDownTime < 500) {
false
} else {
params.x += -((event.rawX - dragPosX)).toInt()
params.y += (event.rawY - dragPosY).toInt()
dragPosX = event.rawX
dragPosY = event.rawY
windowManager.updateViewLayout(layout, params)
true
}
}
else -> false
}
}
layout.addView(imageView)
this.layoutView = layout
windowManager.addView(layout, params)
startRenderLayer(windowManager)
}
I have heard TYPE_PHONE could fix but this limited to system only.
And I'm expecting my overlay being clickable while user have a finger controlling the gamer under.
I want to rotate my view by dragging a helper button on the edge of the view.
Here Image Here is video
In this case, when the view is standing still, only the change on event.Y should be affected. As the view becomes horizontal, the event.X change should increase and only the event.X change should affect the view when the view is fully horizontal
Can anyone know how to do this?
current code is, but this worked incorrectly:
emojiBinding.btnRotate.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
boolArray[0] = false
boolArray[2] = false
startPositionOfRotation.x = event.x
startPositionOfRotation.y = event.y
}
MotionEvent.ACTION_MOVE -> {
val degree = getRotationDegree(emojiBinding, event.x, event.y)
val rotState = emojiBinding.root.rotation
var mult = 0f
if (abs(rotState)%90 < 45 ){
mult = if (event.x >=0)1f else -1f
}
else{
mult = if (event.y >=0)1f else -1f
}
emojiBinding.root.rotation += mult * degree
Timber.d("Degree $degree Rotation ${emojiBinding.root.rotation}")
}
MotionEvent.ACTION_UP -> {
startPositionOfRotation.x = 0f
startPositionOfRotation.y = 0f
boolArray[0] = true
boolArray[2] = true
}
}
boolArray[1]
}
I am using "Draw over other aps" to show a chat head like view.
I need to position it relatively and show animation while dismissing it.
Please see first video/gif of google:
Please note:
a) In first video: the view can be position relative to screen blocks designed by system.
b) The movement is smooth.
c) While dismissing/closing view an animation cross is displayed.
Please see second video/gif of my app:
The movement is not that smooth, its plain and no animation.
Below is my code:
floatingView.setOnTouchListener(object : View.OnTouchListener {
private var initialX = 0
private var initialY = 0
private var initialTouchX = 0f
private var initialTouchY = 0f
override fun onTouch(v: View, event: MotionEvent): Boolean {
when (event.action) {
ACTION_UP -> {
overlayView.visibility = INVISIBLE
if (v.isOverlap(overlayView)) {
stopSelf()
}
return false
}
ACTION_MOVE -> {
overlayView.visibility = View.VISIBLE
layoutParams.x = (initialX + (event.rawX - initialTouchX).toInt())
layoutParams.y = (initialY + (event.rawY - initialTouchY).toInt())
windowManager.updateViewLayout(floatingView, layoutParams)
return false
}
ACTION_DOWN -> {
initialX = layoutParams.x
initialY = layoutParams.y
initialTouchX = event.rawX
initialTouchY = event.rawY
return false
}
}
return false
}
}
How should I tweak it to achieve the first video ?
I am using WindowManager.LayoutParams
var floatingView = LayoutInflater.from(this).inflate(R.layout.chat, null)
var windowManager: WindowManager getSystemService(WINDOW_SERVICE) as WindowManager
var layoutParams: WindowManager.LayoutParams = WindowManagerLayoutParams(WRAP_CONTENT, WRAP_CONTENT, LAYOUT_FLAG, FLAG_NOT_FOCUSABLE, TRANSLUCENT).apply {
gravity = TOP or START
x = 0
y = 100
}
windowManager.addView(floatingView, layoutParams)
Please try below code and check if it's not working then tell me.
#SuppressLint("ClickableViewAccessibility")
private fun onTouchListener()
: View.OnTouchListener {
return View.OnTouchListener { view, event ->
val x = event.rawX.toInt()
val y = event.rawY.toInt()
when (event.action and MotionEvent.ACTION_MASK) {
MotionEvent.ACTION_DOWN -> {
val lParams = view.layoutParams as RelativeLayout.LayoutParams
xDelta = x - lParams.leftMargin
yDelta = y - lParams.topMargin
}
MotionEvent.ACTION_UP -> {
}
MotionEvent.ACTION_MOVE -> {
val layoutParams = view
.layoutParams as RelativeLayout.LayoutParams
layoutParams.leftMargin = x - xDelta
layoutParams.topMargin = y - yDelta
layoutParams.rightMargin = 0
layoutParams.bottomMargin = 0
view.layoutParams = layoutParams
}
}
your_view.invalidate()
true
}
}
Is there any way to show PopupWindow.showAtLocation() in exact same place near view on different devices?
My show method:
fun PopupWindow.showAtLocationForEditProfile(anchor: View) {
if (!isShowing) {
val location = IntArray(2)
anchor.postDelayed({
anchor.getLocationInWindow(location)
val isFromTop: Boolean
val y =
if (location[1] - anchor.context.convertDpToPixel(175f + 56) < 0
) {
isFromTop = false
location[1]
} else {
isFromTop = true
location[1] - anchor.context.convertDpToPixel(24f)
}
showAtLocation(
anchor,
if (!isFromTop) Gravity.TOP else Gravity.BOTTOM,
0,
y
)
}, 300)
}
}
fun Context.convertDpToPixel(dp: Float): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
Resources.getSystem().displayMetrics).toInt()
}
i have a problem with rotating when i touch the rotate button and swipe right and left like normal rotate it will work fine but if you move your finger inside the layout container it will keep rotating as a fan i have been trying to fix this problem since 5 days but i got nothing if you have any solution would be great
here is the code
btnrot.setOnTouchListener(OnTouchListener { v, event ->
if (!freeze) {
layoutParams = layGroup.layoutParams as LayoutParams
layBg = v.parent as RelativeLayout
val arrayOfInt = IntArray(2)
layBg!!.getLocationInWindow(arrayOfInt)
var mX = event.rawX.toInt() - arrayOfInt[0]
var mY = event.rawY.toInt() - arrayOfInt[1]
when (event.action) {
MotionEvent.ACTION_DOWN -> {
layGroup.invalidate()
startDegree = layGroup.rotation
pivx = layoutParams.leftMargin + v.width / 2
pivy = layoutParams.topMargin + v.height / 2
basex = mX - pivx
basey = pivy - mY
}
MotionEvent.ACTION_MOVE -> {
val k = pivx
val m = pivy
mY = (Math.toDegrees(
atan2(
basey.toDouble(),
basex.toDouble()
)
) - Math.toDegrees(atan2(m - mY.toDouble(), mX - k.toDouble()))).toInt()
mX = mY
if (mY < 0) {
mX = mY + 360
}
val km = event.y.toInt()
// if (km in 0..1000) {
layGroup.rotation = (startDegree + mX) % 360f
// }
}
}
return#OnTouchListener true
}
freeze
})