如何使 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;
}
}
上面的解决方案对我来说效果很好。
我希望图像响应 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;
}
}
上面的解决方案对我来说效果很好。