I am creating an android app in Java in which I have a lot of <TextView>
around the screen, all of them with onTouchListeners defined. They are wrapped in a <ScrollView>
because they occupy more space than available in the screen.
My problem is: when I scroll the app, up/down, by touching at the screen and moving my finger up/down, the scroll works as expected but the onTouchListener of the touched <TextView>
is also fired (which is probably expected as well) - I don't want that to happen though. I want the onTouchListener to be ignored when I'm touching the screen to scroll it.
How can I accomplish this? I don't want my function to run when the user is scrolling and "accidentally" fires the onTouchListener on a certain <TextView>
.
After searching more, I found this solution by Stimsoni. The idea is to check if the time between the ACTION_DOWN
and ACTION_UP
events is lower or higher than the value given by ViewConfiguration.getTapTimeout()
.
From the documentation:
[Returns] the duration in milliseconds we will wait to see if a touch event is a tap or a scroll. If the user does not move within this interval, it is considered to be a tap.
Code:
view.setOnTouchListener(new OnTouchListener() {
private long startClickTime;
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
startClickTime = System.currentTimeMillis();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (System.currentTimeMillis() - startClickTime < ViewConfiguration.getTapTimeout()) {
// Touch was a simple tap. Do whatever.
} else {
// Touch was a not a simple tap.
}
}
return true;
}
});
I had the same problem as you, and I solved it with ACTION_CANCEL
.
motionEvent.getActionMasked()
is equal to ACTION_CANCEL
when an action perceived previously (like ACTION_DOWN
in your case) is "canceled" now by other gestures like scrolling, etc. your code may be like this:
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent e) {
if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
// perceive a touch action.
} else if(e.getActionMasked() == MotionEvent.ACTION_UP ||
e.getActionMasked() == MotionEvent.ACTION_CANCEL) {
// ignore the perceived action.
}
}
I hope this helps.
I had a similar problem but with one TextView, search led me here. The text-content potentially takes up more space than available on screen. Simple working example: bpmcounter-android (Kotlin)
class MainActivity : AppCompatActivity() {
inner class GestureTap : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent?): Boolean {
// Do your buttonClick stuff here. Any scrolling action will be ignored
return true
}
}
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.textView)
textView.movementMethod = ScrollingMovementMethod()
val gestureDetector = GestureDetector(this, GestureTap())
textView.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
}
}
You can identify moving action like this:
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
}
return false;
}
});
来源:https://stackoverflow.com/questions/35293125/android-how-to-detect-a-touch-on-screen-is-a-scroll-touch