Как заставить imageView реагировать на двойное касание и распознавать, когда imageView нажат, не нажат (действие вниз, вверх)?

Я хочу, чтобы изображение реагировало на 3 действия:

изображение нажата (действие вниз) - изображение становится большим; изображение не нажато (действие вверх) - изображение снова становится нормального размера, дважды нажмите на изображение - изображение куда-то перемещается

Я пытался сделать это так:

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

}

Но onTouch никогда не срабатывает! Потому что onDown (он же MotionEvent.ACTION_DOWN) запускаетDoubleTap и другие - singleap, fling и т. Д.

Я также попытался переопределить onShowPress () - но он распознает только действие вниз. однократное нажатие, singleTapconfirmed () тоже не помогло.


person ERJAN    schedule 08.10.2015    source источник


Ответы (2)


Проблема в том, что вы возвращаете true из onTouch, что поглотит событие, и дальнейшие прослушиватели не будут вызываться.

Если вы используете OnLongClickListener для печати изображения вместо события ACTION_DOWN, вы сможете перехватывать другие события.

Кроме того, вам нужно будет вернуть true только внутри события ACTION_UP onTouch и false в противном случае. также не возвращают истину из onDown, так что события не будут съедены.

измените свой onTouch вот так:

@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;
    }

и используйте OnLongClickListener для пресс-конференции.

person Rahul Tiwari    schedule 08.10.2015
comment
тогда что мне делать? я действительно меняю свой код сейчас - я думаю, я получаю это - person ERJAN; 08.10.2015
comment
Я даже не могу добраться до метода onTouch - первое, что выполняется, это onDown ()! все остальные жесты начинаются с onDown - если ondown ложно, никакие жесты не будут распознаваться, прослушиваться - person ERJAN; 08.10.2015
comment
тогда вы не должны возвращать истину из onDown. зачем тебе это нужно? также проверьте обновленный ответ. - person Rahul Tiwari; 08.10.2015
comment
мне нужно вернуть истину из onDown, потому что я также хочу РАСПОЗНАВАТЬ одиночное или двойное нажатие - person ERJAN; 08.10.2015
comment
вам не нужно делать это для одиночного и двойного касания. используйте onSingleTapConfirmed для однократного нажатия. используйте onDoubleTap для двойного нажатия. - person Rahul Tiwari; 08.10.2015
comment
Я боролся с классом письма, не могли бы вы помочь мне написать какой-нибудь псевдокод? - person ERJAN; 08.10.2015
comment
вы пробовали мои предложения? если да, опубликуйте свой последний код и проблемы. - person Rahul Tiwari; 08.10.2015
comment
да, я делаю это сейчас, позвольте мне показать вам свой код в чате - person ERJAN; 08.10.2015
comment
Позвольте нам продолжить это обсуждение в чате. - person ERJAN; 08.10.2015
comment
ты запутал меня, черт возьми, теперь я ничего не понимаю - person ERJAN; 08.10.2015
comment
как мне подключить эти 3 метода - onDoubleTap, onsingleTapconfirmed, на doubletapEvent? им нужен отдельный объект GestureDetector, - person ERJAN; 08.10.2015
comment
вы сделали все правильно, за исключением того, что вернули true и false на местах. я прокомментировал, как их исправить. - person Rahul Tiwari; 08.10.2015
comment
но я не знаю, как вызывать эти методы onDoubleTap, onSingleTap - откуда мне их вызывать? - person ERJAN; 08.10.2015
comment
о, вы забыли добавить к своему изображению жев-слушателя. - person Rahul Tiwari; 08.10.2015
comment
проверьте этот stackoverflow.com/questions / 6715915 / - person Rahul Tiwari; 08.10.2015

После того, как я так долго боролся с прослушивателем жестов и его методами - onFling, onLongPress и т.д., я решил написать свою собственную, моя идея не сильно отличается от записи времени каждого нажатия, на SO есть аналогичное решение.

Я понимаю, в чем была моя проблема: если вы используете onTouch - все ваши прикосновения перехватываются и интерпретируются через него, но simpleGestureListener обрабатывает свои собственные события через onDown, поэтому onTouch никогда не вызывается; в этой ситуации мне пришлось написать довольно простую логику:

  • на ACTION_DOWN запустите таймер обратного отсчета на 300 миллисекунд или около того - после того, как он тикает около 290, проверьте еще раз, является ли событие по-прежнему действием вниз
  • если событие не действует - это по сути долгое нажатие, и мое изображение реагирует соответствующим образом - становится больше, если нет - просто ничего не делайте
  • на ACTION_UP: проверьте, было ли долгое нажатие, если было - пользователь отжал удержание, и изображение стало меньше, но в противном случае - это было быстрое нажатие!

Код ниже:

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

}

РЕДАКТИРОВАТЬ: еще одно лучшее решение.

У меня были проблемы с таймером обратного отсчета - он почему-то не отсчитывал до конца. Я применил старую идею - различать долгий щелчок и щелчок с помощью двух слушателей - LongClickListener, ClickListener. Это сработало намного лучше, чем решение выше.

Код ниже:

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

}

Приведенное выше решение подходит мне.

person ERJAN    schedule 09.10.2015