问题
I have a view that need to process onTouch gestures and onClick events. What is the proper way to achieve this?
I have an onTouchListener
and an onClickListener
set on the view. Whenever I do touch the view, first the onTouch
event is triggered and later the onClick
. However, from the onTouch
event handler I have to return either true
or false
. Returning true
means that the event is being consumed, so the android event system will not propagate the event any further.
Therefore, an onClick
event is never generated, atleast my onClick
listener is never triggered when I return true
in my onTouch
event handler. On the other hand, returning false
there is not an option, since this prevents the onTouch
listener from receiving any further events that are necessary in order to recognize a gesture. What's the usual way of solving this?
回答1:
In you GestureDetector, you can call callOnClick() directly. Note the View.callOnClick API requires API level 15. Just have a try.
// Create a Gesturedetector
GestureDetector mGestureDetector = new GestureDetector(context, new MyGestureDetector());
// Add a OnTouchListener into view
m_myViewer.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
return mGestureDetector.onTouchEvent(event);
}
});
private class MyGestureDetector extends GestureDetector.SimpleOnGestureListener
{
public boolean onSingleTapUp(MotionEvent e) {
// ---Call it directly---
callOnClick();
return false;
}
public void onLongPress(MotionEvent e) {
}
public boolean onDoubleTap(MotionEvent e) {
return false;
}
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
public void onShowPress(MotionEvent e) {
LogUtil.d(TAG, "onShowPress");
}
public boolean onDown(MotionEvent e) {
// Must return true to get matching events for this down event.
return true;
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, final float distanceX, float distanceY) {
return super.onScroll(e1, e2, distanceX, distanceY);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// do something
return super.onFling(e1, e2, velocityX, velocityY);
}
}
回答2:
if you use onTouchListener
, you don't have to use onClickListener
. in onClickListener
what it does is it get the touch event and check event actions and detect the click. so if you want to do some work when onClick
. you can do it in the onTouchListener
by filtering the action.
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//this is touch
}
if (event.getAction() == MotionEvent.ACTION_UP) {
//this is click
}
return false;
}
回答3:
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
layOutParams.x = initialX + (int) (event.getRawX() - initialTouchX);
layOutParams.y = initialY + (int) (event.getRawY() - initialTouchY);
break;
case MotionEvent.ACTION_DOWN:
initialX = layOutParams.x;
initialY = layOutParams.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
if (initialTouchX == event.getRawX() && initialTouchY == event.getRawY()) {
return false;// to handle Click
}
break;
case MotionEvent.ACTION_UP:
if (initialTouchX == event.getRawX() && initialTouchY == event.getRawY()) {
return false;// to handle Click
}
break;
}
return true;
}
};
回答4:
isMove = false;
case MotionEvent.ACTION_DOWN:
//Your stuff
isMove = false;
case MotionEvent.ACTION_UP:
if (!isMove || (Xdiff < 10 && Ydiff < 10 ) {
view.performClick; //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little
even when you just click it
}
case MotionEvent.ACTION_MOVE:
isMove = true;
Another way is to use threads. That is on Action_Down start a thread to increment a counter. In case of Action_UP : stop/interrupt the thread. look for counter if it is less than 2 (say or threshold as per your application) or !isMove then invoke click function
回答5:
we can use flag based implementation. where swipe/dragging we can handle in Action_Up and make the flag true and return the same. In Case of click or Tap same handle in Action_Down and set the flag false and return.
touchAndSwipe=false;
switch(e.getAction()){
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_DOWN:
x1 = e.getX();
break;
case MotionEvent.ACTION_UP:
x2 = e.getX();
float diff= x2-x1;
if(Math.abs(delta)>100){
// Swipe
touchAndSwipe=true;
}else{
touchAndSwipe=false;
}
break;
}
return touchAndSwipe;
回答6:
I've been able to implement OnClick and OnTouch together in a custom keyboard I'm building. You can take a look at this code and modify it according to your context since you didn't include a code sample to work from.
If you post a sample of your code I can modify this sample of mine to accomplish the same outcome for your use. Context is everything when it comes to Android Development. Take a look at this code snippet and see if it helps. Otherwise post a sample of your own and I'll make the modifications and reply back.
View DefaultphaseLay() {
LinearLayout mViewFirstPhase = (LinearLayout) getLayoutInflater().inflate(R.layout.layout_default_phase, parent);
ksOne_btn_LiLay = (LinearLayout) mViewFirstPhase.findViewById(R.id.ksOne_btn_LiLay);
ksOne_btn = (Button) mViewFirstPhase.findViewById(R.id.ksOne_btn);
ksOne_btn.setOnClickListener(mCorkyListener);
ksOne_btn.setFocusableInTouchMode(true);
ksOne_btn.setFocusable(true);
ksOne_btn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
playClick(keyCode);
//v.startAnimation(animScale);
//key_sound.start();
xkeys_lay.setVisibility(View.GONE);
numkeys_lay.setVisibility(View.GONE);
if (Constants.HapticFeedbackConstant) {
myVib.vibrate(Constants.vibration_duration);
}
} else if (event.getAction() == MotionEvent.ACTION_UP) {
ksOne_btn.setFocusable(false); //Check This Added This In Attempt to Kill Selector on Action_Up
//playClick(-100);
//key_sound.pause();
}
return false;
}
});
ChangeKeyBackgroundMehods.initChange_Key_Background(ksOne_btn_LiLay);
ChangeFontStyle.initChange_fontStyle(ksOne_btn, getApplicationContext());
ChangeFont_size.initChange_fontSize(ksOne_btn, getApplicationContext());
This works for the context of type alpha or numerical output, if the event is looking to send or consume some other context it would need to be modified.
回答7:
I agree with jdx, if you use onTouchlistener you dont need to use onclicklistener and viceversa, if you want to trigger an event on button,image,or textview click, then just fire onClicklistener. if you want some animations like dragging and spinning then use ontouchlistener to get the coordinates of the surface touched
来源:https://stackoverflow.com/questions/14480418/receiving-ontouch-and-onclick-events-with-android