0

I want image to respond to 3 actions:

image pressed(action down) - image becomes large image unpressed(action up) - image becomes normal size again double tap on image - image moves somewhere

I have been trying to do it this way:

public class Working_gestures extends Activity {
ImageView sample ;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    sample = (ImageView)findViewById(R.id.sample);

    Gestures x = new Gestures(sample);

}
 //inner class
private class Gestures extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener{

    ImageView view ;
    public Gestures(ImageView v) {
        view = v;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        //must return true for doubleTap to work, but onDown() "blocks" onTouch
        return true ;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e){
         //do something on image
         return true ;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                //image increases in size and stays large
                Log.wtf("x", "action down");
                break ;
            case MotionEvent.ACTION_UP:
                //image comes back to normal size
                Log.wtf("x", "action up!");
                break ;
        }
        return true ;
    }
}

}

But onTouch is never triggered! Because onDown (aka MotionEvent.ACTION_DOWN) fires up onDoubleTap and others - singletap, fling etc.

I also tried to override onShowPress() - but it only recognizes action down. single tap up, singleTapconfirmed() did not help either.

ERJAN
  • 23,696
  • 23
  • 72
  • 146

2 Answers2

1

The problem is that you are returning true from onTouch, which will eat up the event and no further listeners will be called.

If you use OnLongClickListener for image press instead of ACTION_DOWN event you will be able to intercept other events.

Additionally, you will have to return true only inside the ACTION_UP event of onTouch and false otherwise. also do not return true from onDown so events will not be eaten up.

change your onTouch like this:

@Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_UP:
                //image comes back to normal size
                Log.wtf("x", "action up!");
                return true;
        }
        return false;
    }

and use OnLongClickListener for press event.

Rahul Tiwari
  • 6,851
  • 3
  • 49
  • 78
  • then what should I do? i m actually changing my code now - i think i m getting it – ERJAN Oct 08 '15 at 06:33
  • i can not even get to onTouch method - the first thing that is executed is onDown()! all other gestures start with onDown - if ondown is false, no gestures will be recognized, listened to – ERJAN Oct 08 '15 at 06:40
  • then you should not return true from `onDown`. why you need to do that? also check updated answer. – Rahul Tiwari Oct 08 '15 at 06:43
  • i need to return true from onDown, because i also want to RECOGNIZE singletap or double tap – ERJAN Oct 08 '15 at 06:52
  • you need not to do that for single tap and double tap. use `onSingleTapConfirmed` for single tap. use `onDoubleTap` for double tap. – Rahul Tiwari Oct 08 '15 at 06:58
  • i have been struggling with writing class, could you assist me writing some pseudocode? – ERJAN Oct 08 '15 at 08:33
  • have you tried my suggestions? if yes post your latest code and problems. – Rahul Tiwari Oct 08 '15 at 08:37
  • yes, i m doing it now, let me show you my code in chat – ERJAN Oct 08 '15 at 08:38
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91711/discussion-between-erjan-and-rahul-tiwari). – ERJAN Oct 08 '15 at 08:39
  • you confused the hell out of me, i dont' understand anything now – ERJAN Oct 08 '15 at 09:13
  • how do I attach those 3 methods - onDoubleTap, onsingleTapconfirmed , on doubletapEvent? they need a separate GestureDetector object, – ERJAN Oct 08 '15 at 09:16
  • you have done everything correct apart from returning `true` and `false` at places. i made comments on how to correct them. – Rahul Tiwari Oct 08 '15 at 09:18
  • but i dont' know how to call those onDoubleTap , onSingleTap methods - where do I call them from? – ERJAN Oct 08 '15 at 09:26
  • oh you forgot to add gesturelistener to your image. – Rahul Tiwari Oct 08 '15 at 09:29
  • check this http://stackoverflow.com/questions/6715915/how-to-implement-doubletap-on-imageviews-onclick – Rahul Tiwari Oct 08 '15 at 09:36
1

after struggling so much with gesture listener and its methods - onFling, onLongPress etc I decided to write my own, my idea is not that different from recording the time of of each press, there is similar solution on SO.

I understand what my problem was: if you use onTouch - all your touches are intercepted and interpreted through it, but simpleGestureListener processes its own events through onDown, so onTouch is never called; in this situation I had to write pretty basic logic:

  • on ACTION_DOWN, launch count down timer for 300 miliseconds or so - after it ticks around 290, check again if the event is still action down
  • if event is action down - it is essentially long press and my image responds accordingly - becomes larger, if not - just do nothing
  • on ACTION_UP: check if it was long press, if it was - the user unpressed his hold, and image becomes smaller, but otherwise - it was quick tap!

Code below:

public class DoubleTapWorking1 extends Activity implements View.OnTouchListener {
ImageView sample;
boolean still_down ;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    sample = (ImageView) findViewById(R.id.sample);
    sample.setOnTouchListener(this);
    still_down = false ;

}

@Override
public boolean onTouch(final View v,final MotionEvent e) {

     switch (e.getAction()){
         case MotionEvent.ACTION_DOWN:
             still_down =false;
             CountDownTimer timer = new CountDownTimer(500,10){
                 @Override
                 public void onTick(long millisUntilFinished) {
                     if((int)millisUntilFinished < 100 && e.getAction() == MotionEvent.ACTION_DOWN){
                         still_down = true ;
                     }
                 }
                 @Override
                 public void onFinish() {
                     if( still_down){                           
                         //code to make imageView larger
                     }
                 }
             }.start();
             break ;
         case MotionEvent.ACTION_UP:
             if(still_down) {
                 //your code to make image smaller
             }
             else{
                 action_on_single_tap(v);
             }
             break ;
     }

   return true;
  }

  private void action_on_single_tap(final View v){
      //your code to do with image on single tap - move somewhere else, make invisible etc.
}

}

EDIT: another better solution.

I had some problems with countdown timer - it did not count down to the end for some reason. I applied some old idea - distinguish between long click and click using 2 listeners - LongClickListener, ClickListener. This worked out much better than the solution above.

Code below:

private class Gestures_future implements View.OnClickListener, View.OnLongClickListener{

     int margin_long_press_x1;
     int margin_long_press_y1;
     int margin_long_press_x2;
     int margin_long_press_y2;
     RelativeLayout.LayoutParams params_generic = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
public Gestures_future(final int margin_long_press_x1,final int margin_long_press_y1,final int margin_long_press_x2,final int margin_long_press_y2
    ){
        params_generic.leftMargin = 30;
        params_generic.topMargin = 40;

        this.margin_long_press_x1 = margin_long_press_x1;
        this.margin_long_press_y1 = margin_long_press_y1;
        this.margin_long_press_x2 = margin_long_press_x2;
        this.margin_long_press_y2 = margin_long_press_y2;
    }
    @Override
    public void onClick(View v) {
        Log.wtf("x", "on click!");
        TextView d = (TextView)v;
        int current_id = v.getId();
       String answer_content = d.getText().toString();
        if (answers_player1_ids.contains(current_id)) {
        if (Battlefield.getStateOfAnswer1PlacePlayer1() == false) {
            d.setText("");
            Battlefield.answer1_place_busy_player1 = true;
            answer_place1_player1.setTextSize(20);
            answer_place1_player1.setText(answer_content);
            upper_layout_answer_counter++;
        } else if (Battlefield.getStateOfAnswer2PlacePlayer1() == false) {
            d.setText("");
            Battlefield.answer2_place_busy_player1 = true;
            answer_place2_player1.setTextSize(20);
            answer_place2_player1.setText(answer_content);
            upper_layout_answer_counter++;
            if (upper_layout_answer_counter == 2) {
                upper_layout_answer_counter = 0;
                see_answers1.performClick();
            }
        }
    }
        else if (answers_player2_ids.contains(current_id)) {
        if (Battlefield.getStateOfAnswer1Place() == false){
            d.setText("");
            Battlefield.answer1_place_busy = true;
            answer_place1.setTextSize(20);
            answer_place1.setText(answer_content);
            lower_layout_answer_counter++;
        } else if (Battlefield.getStateOfAnswer2Place() == false) {
            d.setText("");
            Battlefield.answer2_place_busy = true;
            answer_place2.setTextSize(20);
            answer_place2.setText(answer_content);
            lower_layout_answer_counter++;
            if (lower_layout_answer_counter == 2) {
                lower_layout_answer_counter = 0;
                see_answers2.performClick();
            }
        }
    }
}
    @Override
    public boolean onLongClick(View v){
        Log.wtf("x", "on long click!");
        final TextView d = (TextView)v;
        Log.wtf("x", d.getText().toString() +  " long clicked!" );
                    d.setTextSize(30);
                    RelativeLayout.LayoutParams x = new RelativeLayout.LayoutParams(350, 500);
                    x.setMargins(margin_long_press_x1, margin_long_press_y1, 0, 0);
                    d.setLayoutParams(x);
                    d.requestLayout();
        new CountDownTimer(3000,500){
            @Override
            public void onTick(long millisUntilFinished) {
            }
            @Override
            public void onFinish() {
                RelativeLayout.LayoutParams t1 = new RelativeLayout.LayoutParams(130, 170);
                t1.setMargins(margin_long_press_x2, margin_long_press_y2, 0, 0);
                d.setTextSize(10);
                d.setLayoutParams(t1);
                d.requestLayout();
            }
        }.start();
        return true;
    }

}

The solution above works well for me.

ERJAN
  • 23,696
  • 23
  • 72
  • 146