如何在父视图中处理子视图的触摸事件
How to handle touch event for child view in parent view
我正在制作一个自定义日历视图,它扩展了 LinearLayout 并且每个日期都有子视图。我想做的是处理滑动和点击,正如你想象的那样,滑动是为了改变月份,点击是为了选择一个日期并显示新的activity。为此,我在 CalendarView 上使用 GestureDetector 并可以使其适用于滑动。但是要处理点击事件,我不知道如何找到发生点击的子视图。
- 有没有人知道如何解决这个问题?
- OnScroll(MotionEvent) 上 return true 和 false 有什么区别?
以下是我的部分代码。
public class MonthView extends LinearLayout implements GestureDetector.OnGestureListener {
public MonthView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
gestureDetector = new GestureDetector(this);
initDateViews();
}
//other codes here
....
private void initDateViews() {
for(int i = 0; i < 42; i++) {
DateView view = new DateView();
//init date views and add to calendar view.
....
calendar.Add(view);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Logger.debug(TAG, ">>> MonthView.onTouchEvent()");
return gestureDetector.onTouchEvent(event);
}
@Override
public boolean OnSingleTapUp(MotionEvent event) {
// how can I find a child view to handle click event?
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// right to left
if (e1.getX() - e2.getX() > minSwipeDistance) {
this.prevMonth();
}
// left to right
else if(e2.getX() - e1.getX() > minSwipeDistance) {
this.nextMonth();
}
// bottom to top
else if(e1.getY() - e2.getY() > minSwipeDistance) {
this.prevMonth();
}
//top to bottom
else if(e2.getY() - e1.getY() > minSwipeDistance) {
this.nextMonth();
}
return false;
}
....
}
on[GestureEvent]
回调的布尔值return表示回调函数是否消费了事件。也就是说,在您的 onScroll
实施中,您会 return 为真,因为您正在处理这些事件。
但是,onSingleTapUp
应该 return false 以指示您希望将事件传递给子视图。
然后您应该注册一个 OnClickListener
能够处理每个子视图的实际日期:
private void initDateViews() {
for(int i = 0; i < 42; i++) {
DateView view = new DateView();
//init date views and add to calendar view.
....
// register onClickListener for e.g. date
view.setOnCLickListener(new DateOnClickListner(date))
calendar.Add(view);
}
}
使用 OnclickListener
实现方式
class DateOnClickListner(Date date) extends View.OnClickListener {
public void onClick(View v) {
...
}
}
我通过覆盖 MonthView 上的 'onInterceptTouchEvent()' 解决了这个问题,并发布了解决方案以帮助遇到同样问题的人。
我实现了 GestureDetector 来更改 'onFling()' 的月份,如下面的代码所示。
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean result = gestureDetector.onTouchEvent(event);
return result;
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// right to left
if (e1.getX() - e2.getX() > minSwipeDistance) {
nextMonth();
}
// left to right
else if(e2.getX() - e1.getX() > minSwipeDistance) {
prevMonth();
}
// bottom to top
else if(e1.getY() - e2.getY() > minSwipeDistance) {
nextMonth();
}
//top to bottom
else if(e2.getY() - e1.getY() > minSwipeDistance) {
prevMonth();
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
我正在制作一个自定义日历视图,它扩展了 LinearLayout 并且每个日期都有子视图。我想做的是处理滑动和点击,正如你想象的那样,滑动是为了改变月份,点击是为了选择一个日期并显示新的activity。为此,我在 CalendarView 上使用 GestureDetector 并可以使其适用于滑动。但是要处理点击事件,我不知道如何找到发生点击的子视图。
- 有没有人知道如何解决这个问题?
- OnScroll(MotionEvent) 上 return true 和 false 有什么区别?
以下是我的部分代码。
public class MonthView extends LinearLayout implements GestureDetector.OnGestureListener {
public MonthView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
gestureDetector = new GestureDetector(this);
initDateViews();
}
//other codes here
....
private void initDateViews() {
for(int i = 0; i < 42; i++) {
DateView view = new DateView();
//init date views and add to calendar view.
....
calendar.Add(view);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Logger.debug(TAG, ">>> MonthView.onTouchEvent()");
return gestureDetector.onTouchEvent(event);
}
@Override
public boolean OnSingleTapUp(MotionEvent event) {
// how can I find a child view to handle click event?
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// right to left
if (e1.getX() - e2.getX() > minSwipeDistance) {
this.prevMonth();
}
// left to right
else if(e2.getX() - e1.getX() > minSwipeDistance) {
this.nextMonth();
}
// bottom to top
else if(e1.getY() - e2.getY() > minSwipeDistance) {
this.prevMonth();
}
//top to bottom
else if(e2.getY() - e1.getY() > minSwipeDistance) {
this.nextMonth();
}
return false;
}
....
}
on[GestureEvent]
回调的布尔值return表示回调函数是否消费了事件。也就是说,在您的 onScroll
实施中,您会 return 为真,因为您正在处理这些事件。
但是,onSingleTapUp
应该 return false 以指示您希望将事件传递给子视图。
然后您应该注册一个 OnClickListener
能够处理每个子视图的实际日期:
private void initDateViews() {
for(int i = 0; i < 42; i++) {
DateView view = new DateView();
//init date views and add to calendar view.
....
// register onClickListener for e.g. date
view.setOnCLickListener(new DateOnClickListner(date))
calendar.Add(view);
}
}
使用 OnclickListener
实现方式
class DateOnClickListner(Date date) extends View.OnClickListener {
public void onClick(View v) {
...
}
}
我通过覆盖 MonthView 上的 'onInterceptTouchEvent()' 解决了这个问题,并发布了解决方案以帮助遇到同样问题的人。 我实现了 GestureDetector 来更改 'onFling()' 的月份,如下面的代码所示。
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean result = gestureDetector.onTouchEvent(event);
return result;
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// right to left
if (e1.getX() - e2.getX() > minSwipeDistance) {
nextMonth();
}
// left to right
else if(e2.getX() - e1.getX() > minSwipeDistance) {
prevMonth();
}
// bottom to top
else if(e1.getY() - e2.getY() > minSwipeDistance) {
nextMonth();
}
//top to bottom
else if(e2.getY() - e1.getY() > minSwipeDistance) {
prevMonth();
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}