Disable 2 finger taps on button - android

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)
}
}

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 to dismiss Bottom Sheet fragment when click outside in Kotlin?

I make bottom sheet fragment like this:
val bottomSheet = PictureBottomSheetFragment(fragment)
bottomSheet.isCancelable = true
bottomSheet.setListener(pictureListener)
bottomSheet.show(ac.supportFragmentManager, "PictureBottomSheetFragment")
But its not dismiss when I touch outside. and dismiss or isCancelable not working.
try this
behavior.setState(BottomSheetBehavior.STATE_HIDDEN));
You can override method and indicate, for example, in onViewCreated what you need:
class ModalDialogSuccsesDataPatient : ModalDialog() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
isCancelable = false //or true
}
}
Let's try to design reusable functions to solve this problem and similar ones if the need arises.
We can create extension functions on View that tell whether a point on the screen is contained within the View or not.
fun View.containsPoint(rawX: Int, rawY: Int): Boolean {
val rect = Rect()
this.getGlobalVisibleRect(rect)
return rect.contains(rawX, rawY)
}
fun View.doesNotContainPoint(rawX: Int, rawY: Int) = !containsPoint(rawX, rawY)
Now we can override the dispatchTouchEvent(event: MotionEvent) method of Activity to know where exactly the user clicked on the screen.
private const val SCROLL_THRESHOLD = 10F // To filter out scroll gestures from clicks
private var downX = 0F
private var downY = 0F
private var isClick = false
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
when (event.action and MotionEvent.ACTION_MASK) {
MotionEvent.ACTION_DOWN -> {
downX = event.x
downY = event.y
isClick = true
}
MotionEvent.ACTION_MOVE -> {
val xThreshCrossed = abs(downX - event.x) > SCROLL_THRESHOLD
val yThreshCrossed = abs(downY - event.y) > SCROLL_THRESHOLD
if (isClick and (xThreshCrossed or yThreshCrossed)) {
isClick = false
}
}
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
if (isClick) onScreenClick(event.rawX, event.rawY)
}
else -> { }
}
return super.dispatchTouchEvent(event)
}
private fun onScreenClick(rawX: Float, rawY: Float) { }
Now, you can simply use the above-defined functions to achieve the required result
private fun onScreenClick(rawX: Float, rawY: Float) {
if (bottomSheet.doesNotContainPoint(rawX.toInt(), rawY.toInt())) {
// Handle bottomSheet state changes
}
}
What more? If you have a BaseActivity which is extended by all your Activities then you can add the click detection code to it. You can make the onScreenClick an protected open method so that it can be overridden by the sub-classes.
protected open fun onScreenClick(rawX: Float, rawY: Float) { }
Usage:
override fun onScreenClick(rawX: Float, rawY: Float) {
super.onScreenClick(rawX, rawY)
if (bottomSheet.doesNotContainPoint(rawX.toInt(), rawY.toInt())) {
// Handle bottomSheet state changes
}
}

how to detect when a button is held?

I want to perform the actions when the button is pressed not just clicked
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var ib:ImageView=findViewById(R.id.imageView4) as ImageView
var final=MediaPlayer.create(this,R.raw.`m1`)
var anim=AnimationUtils.loadAnimation(this,R.anim.rotate)
ib.setOnTouchListener(){
textView.text="rip"
final.start();
ib.startAnimation(anim);
}
}
}
I want the actions to be performed when the button is held and stop when they are not .
this seems to be working fine but the compiler gives a warning
ib.setOnTouchListener(View.OnTouchListener { view, motionEvent ->
when (motionEvent.action){
MotionEvent.ACTION_DOWN -> {
textView4.text="IGNORING"
ib.startAnimation(anim)
final.setLooping(true)
final.start()
}
MotionEvent.ACTION_UP -> {
textView4.text="IGNORE"
ib.clearAnimation()
final.pause()
}
}
return#OnTouchListener true
})

Kotlin edittxt.onKeyListener with emulator keyboard

I'm trying to reset a button to become clickable once a key on the keyboard is pressed. It works with the hardware keyboard but not with the emulator keyboard. How would one implement this?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.log_in_button)
val email = findViewById<EditText>(R.id.email_field)
button.isClickable = false
button.alpha = .5f
email.setOnKeyListener(object : View.OnKeyListener {
override fun onKey(v: View, keyCode: Int, event: KeyEvent): Boolean {
if(event.action == KeyEvent.ACTION_DOWN) {
button.isClickable = true
button.alpha = 1f
return true
}
return false
}
})
}

Categories

Resources