如何使 imageView 响应双击并识别 imageView 何时被按下、未按下(动作向下、向上)?

How do I make imageView respond to double tap and recognize when imageView is pressed, unpressed(action down, up)?

我希望图像响应 3 个动作:

按下图像(向下操作)- 图像变大 image unpressed(action up) - 图像再次变为正常大小 双击图像 - 图像移动到某处

我一直在尝试这样做:

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() 也没有帮助。

问题是您正在从 onTouch 中 returning true,这将耗尽事件并且不会调用更多的侦听器。

如果您将 OnLongClickListener 用于图像按下而不是 ACTION_DOWN 事件,您将能够拦截其他事件。

此外,您必须仅在 onTouch 的 ACTION_UP 事件中 return true,否则为 false。也不要从 onDown return true 这样事件就不会被吃掉。

像这样改变你的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 进行新闻发布会。

在与手势侦听器及其方法-onFling、onLongPress 等进行了如此多的斗争之后,我决定自己编写,我的想法与记录每次按下的时间没有什么不同,SO 上有类似的解决方案。

我明白我的问题是什么:如果你使用 onTouch - 你所有的触摸都会被它拦截和解释,但是 simpleGestureListener 通过 onDown 处理它自己的事件,所以 onTouch 永远不会称为;在这种情况下,我不得不编写非常基本的逻辑:

  • 在 ACTION_DOWN,启动 300 毫秒左右的倒数计时器 - 在它 滴答 大约 290 之后,再次检查事件是否仍在动作
  • 如果事件是动作 - 它本质上是长按并且我的图像相应地响应 - 变大,如果不是 - 什么都不做
  • on 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;
    }

}

上面的解决方案对我来说效果很好。