How to Stop Event's While Animation is in process? - android

I am working on Animating my view where i animate the translation and scaling of View.
Problem:
If my animation duration is for 2000 ms (2 Sec) i don't want any user event's to interfere in between animation.
Example if Double Tap on View Trigger's the Scaling Animation and scrolling trigger's Translation Animation.Both animation duration is 2 seconds,But if i double tap and scroll one after another it create's weird result.
So i want to stop event's when animation is going on.
Is there any easy solution without maintaining the state of OnGoing animation and overriding the onTouchEvent to disable events?

Lock UI from events:
private void lockUI() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
Unlock UI:
private void unlockUI() {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}

Solution that i used:
Created a State of Animation
private var isAnimationOnGoing: Boolean = false
Setting the State in Animation Listener
translationAnimation.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
isAnimationOnGoing = false
}
override fun onAnimationStart(animation: Animation?) {
isAnimationOnGoing = true
}
})
Use dispatchTouchEvent(ev: MotionEvent?) . to prevent event's to be received by the ViewGroup or by children's of ViewGroup
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
val dispatchTouchEvent = super.dispatchTouchEvent(ev)
if (isAnimationOnGoing) {
return false
}
return dispatchTouchEvent
}

Related

Motion Event - press duration

How can I get a hold time for an item? I would like to show dialog not on every touch but on a continuous touch for example 2s. Something similar to Long Click.
My listener:
holder.itemView.setOnTouchListener(object: View.OnTouchListener{
val fragment = PodgladFragment()
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when(event?.action){
MotionEvent.ACTION_DOWN -> {
fragment.show((context as FragmentActivity).supportFragmentManager, "Dialog")
}
MotionEvent.ACTION_UP -> {
if(fragment.isAdded)
fragment.dismiss()
}
}
return true
}
})

GestureDetector not registering double taps

I am having trouble implementing a touchListener to my recyclerview items that listens for Single taps and double taps.
Here is my code:
val gDetector = GestureDetector(root.context, object : SimpleOnGestureListener() {
override fun onDoubleTap(e: MotionEvent?): Boolean {
Log.i(TAG,"Double tapped")
return super.onDoubleTap(e)
}
override fun onShowPress(e: MotionEvent?) {
Log.i(TAG,"Show Press")
super.onShowPress(e)
}
override fun onSingleTapUp(e: MotionEvent?): Boolean {
Log.i(TAG,"Single tap up")
return super.onSingleTapUp(e)
}
override fun onDoubleTapEvent(e: MotionEvent?): Boolean {
Log.i(TAG,"Double tapped event")
return super.onDoubleTapEvent(e)
}
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
Log.i(TAG,"single tap confirmed")
return super.onSingleTapConfirmed(e)
}
override fun onLongPress(e: MotionEvent?) {
Log.i(TAG,"Long press")
super.onLongPress(e)
}
})
root.setOnTouchListener { view, event ->
gDetector.onTouchEvent(event)
}
I am using GestureDetector with onTouchListener but only onShowPress and onLongPress get called when I test it out. onLongPress gets called even when I do a quick tap on an item... onShowPress gets called everytime I tap no matter what.
I was unable to find examples online that combine both GestureDetector with onTouchListener on a view with Kotlin.
any ideas on how to get onDoubleTap and onSingleTapConfirmed to work?
tried removing supers and returning true (this does not work)
I am trying to implement 'GestureDetector.onDoubleTapListener' but I am getting this error:
Try delete super methods. And return false where you don't need to register event.
Return true only where you need to register that event happened.

How can I handle view animation in android?

I'm in the process of learning Animation in android and I have several questions -
I have view that I animate based on some bool:
mainFab.setOnClickListener {
isOpen = ViewAnimations.rotate(binding.mainFab, !isOpen)
if (isOpen) {
ViewAnimations.apply {
showMenu(binding.shareFab)
}
} else {
ViewAnimations.apply {
hideMenu(binding.shareFab)
}}
}
ViewAnimations methods:
fun rotateFab(view: View, isFabOpen: Boolean): Boolean {
view.animate()
.rotation(if (isFabOpen) 1440f else 0f)
.setDuration(2000)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
Log.d(TAG, "onAnimationEnd: ")
}
})
return isFabOpen
}
fun showMenu(view: View) {
view.visibility = View.VISIBLE
view.alpha = 0f
view.animate()
.setDuration(2000)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
}
})
.alpha(1f)
.start()
}
fun hideMenu(view: View) {
view.animate()
.setDuration(2000)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
view.visibility = View.GONE
super.onAnimationEnd(animation)
}
}).alpha(0f)
.start()
My questions are:
In showMenu function, why my animation doesn't work properly without the empty listener?
It's working fine at the first time, but from the second time and on it does animate the view, but then set the alpha to 0/ view to gone.
Why the animation still working without .start()? Is it mandatory to use it?
if I start animation by calling showMenu and then at the half way I'm calling hideMenu it just hide the view in very ugly way, there is a way to "reverse" the animation in more elegant way?
All yours problem is from over engineering. What is doing the object ViewAnimations?
About question :
There is can not be problem in empty listener. There is a problem somewhere in your logic.
Without .start() animation can not be launched. If animation is starting so there again a problem somewhere in your logic.
ViewPropertyAnimator animation can perfect animate from semi-state to new state. I recommend you to start write animation from the beginning to be confident in all your steps.

GestureDetector: allow onScroll to be called, while not consuming the touch event

So I have a layout that's on all over the screen and suppose to catch scroll and fling event wherever they are. Problem is that you can't do it unless you consume the listener, thus, other views' touchListeners will never invoke, and this cannot happen.
An example code will be this:
private val onTouchListener = object : View.OnTouchListener {
override fun onTouch(v: View?, motionEvent: MotionEvent): Boolean {
//this block will be reached only once, even when you scroll
GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
//is never called
return false
}
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
//is never called
return false
}
})
return false //if this will be 'true', the block will be reached for as long as the touch continues, but touch events bellow it won't invoke
}
}
this is android's comment on this problem. It doesn't seem very fair, to be honest.
From: http://developer.android.com/guide/topics/ui/ui-events.html
onTouch() - This returns a boolean to indicate whether your listener
consumes this event. The important thing is that this event can have
multiple actions that follow each other. So, if you return false when
the down action event is received, you indicate that you have not
consumed the event and are also not interested in subsequent actions
from this event. Thus, you will not be called for any other actions
within the event, such as a finger gesture, or the eventual up action
event.
What can I do? thanks

Disable 2 finger taps on button

I want to prevent a button from intercepting 2 finger taps. I have a standard Android Activity with onTouchEvent and a standard button which occupies more or less the entire screen.
private const val DEBUG_TAG = "Gestures"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = this.findViewById<Button>(R.id.button2)
button.setOnClickListener { Log.d(DEBUG_TAG, "Button tapped")
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
Log.d(DEBUG_TAG, "onTouchEvent")
val action: Int = MotionEventCompat.getActionMasked(event)
val pointerCount = event.pointerCount;
if (pointerCount > 1) {
Log.d(DEBUG_TAG, "Multi-touch")
}
return super.onTouchEvent(event)
}
}
I want the button to intercept 1 finger taps but ignore 2 finger taps and propagate them to the onTouchEvent of the activity. Currently it intercepts even 2 finger taps.
I tried this in styles.xml but no luck.
<item name="android:windowEnableSplitTouch">false</item>
<item name="android:splitMotionEvents">false</item>
Ideally I would like to do that app-wide but still having onTouchEvent being able to detect 2 finger taps.
You need to block events you don't want to propagate:
override fun onTouchEvent(event: MotionEvent): Boolean {
val action: Int = MotionEventCompat.getActionMasked(event)
val pointerCount = event.pointerCount;
return when (pointerCount) {
1 -> {
// your logic
true //true means you consumed the event (stop propagation)
}
else -> super.onTouchEvent(event)
}
}

Categories

Resources