Как да накарам 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) задейства onDoubleTap и други - singletap, fling и т.н.

Също така се опитах да отменя onShowPress() - но той разпознава само действие надолу. едно докосване, singleTapconfirmed() също не помогна.


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


Отговори (2)


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

Ако използвате OnLongClickListener за натискане на изображение вместо ACTION_DOWN събитие, ще можете да прихващате други събития.

Освен това ще трябва да върнете true само в събитието ACTION_UP на onTouch и false в противен случай. също не връща true от 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
тогава не трябва да връщате true от onDown. защо трябва да го правиш? също проверете актуализирания отговор. - person Rahul Tiwari; 08.10.2015
comment
трябва да върна true от 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, on 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
о, забравихте да добавите gesturelistener към вашето изображение. - 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.
}

}

РЕДАКТИРАНЕ: друго по-добро решение.

Имах проблеми с таймера за обратно отброяване - не отброяваше до края по някаква причина. Приложих някаква стара идея - разграничете дълго щракване и щракване с помощта на 2 слушателя - 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