gpt4 book ai didi

java - 有 subview 时,Android onInterceptTouchEvent 不会执行操作

转载 作者:太空狗 更新时间:2023-10-29 16:18:07 27 4
gpt4 key购买 nike

我有父 View v extends 线性布局。子项一是 LinearLayout,子项二是 ScrollView

我想让 MyParent View 拦截垂直 MotionEvent.ACTION_MOVE(仅向下方向,子 scrollview.getScrollY()==0)并在父 View 中处理它,并且其他 MotionEvent 由 child 处理

这是MyView.xml

  <?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<LinearLayout
android:id="@+id/child_linear>
android:height="50dp"
android:width="50dp">
...something...
</LinearLayout>
<ScrollView
android:id="@+id/child_scrollview>
<LinearLayout/>
</LinearLayout>
</ScrollView>
</merge>

下面是我的代码

public class MyCustomView extends LinearLayout{
public MyCustomView(Context context) {
super(context);
init();
}
private void init(){
setOrientation(LinearLayout.VERTICAL);
LayoutInflater inflater =
(LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.MyView, this, true);


}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
final int action = event.getAction();
Log.d(log,"onInterceptTouchEvent : "+action);
if (action == MotionEvent.ACTION_CANCEL || action ==
MotionEvent.ACTION_UP) {
mIsBeingDragged = false;
return false;
}
if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) {
return true;
}

switch (action) {
case MotionEvent.ACTION_MOVE: {
if (isReadyForPull()) {
final float y = event.getY(), x =
event.getX();
final float diff, oppositeDiff, absDiff;
diff = y - mLastMotionY;
oppositeDiff = x - mLastMotionX;
absDiff = Math.abs(diff);
ViewConfiguration config =
ViewConfiguration.get(getContext());

if (absDiff > config.getScaledTouchSlop() &&
absDiff > Math.abs(oppositeDiff) && diff >= 1f) {
mLastMotionY = y;
mLastMotionX = x;
mIsBeingDragged = true;
Log.d(log,"Flag setting");
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
if (isReadyForPull()) {
mLastMotionY = mInitialMotionY = event.getY();
mLastMotionX = event.getX();
mIsBeingDragged = false;
}
break;
}
}
return mIsBeingDragged;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
final int action=event.getAction();
Log.d(log,"onTouchEvent : "+action);
if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE: {
Log.d(log,"ACTION MOVE RECEIVE");
if (mIsBeingDragged) {
mLastMotionY = event.getY();
mLastMotionX = event.getX();
pullEvent();
return true;
}
break;
}

case MotionEvent.ACTION_DOWN: {
if (isReadyForPull()) {
mLastMotionY = mInitialMotionY = event.getY();
return true;
}
break;
}

case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
if (mIsBeingDragged) {
mIsBeingDragged = false;

if (mState == State.RELEASE_TO_REFRESH ) {
setState(State.REFRESHING);
return true;
}
if (isRefreshing()) {
smoothScrollTo(-mHeaderHeight , null);
return true;
}

setState(State.RESET);
return true;
}
break;
}
}
return false;
}

isReadyForPull() 函数只检查这个

    private boolean isReadyForPull(){
return mScrollView.getScrollY()==0;
}

我的代码运行良好。

如果我向下移动我的子 ScrollView ,onInterceptTouchEvent 首先获取 MotionEvent.ACTION_DOWN 并初始化值,然后依次获取 MotionEvent.ACTION_MOVE 如此设置mIsBeingDragged 标记为 true 并返回 true。所以我可以在我的 ParentViewonTouchEvent 中处理事件。

否则,如果我向上移动子 ScrollView ,则 onInterceptTouchEvent 返回 false,我的子 ScrollView 获取 MotionEvent 并向下滚动。

这是预期的工作。好。

但是,当我触摸我的子线性布局时,它不起作用!

如果我触摸并拖动我的子线性布局,我的 CustomView 的 onInterceptTouchEvent 获得 MotionEvent.ACTION_DOWN,但无法获得第二个 MotionEvent.ACTION_MOVE .

为什么这不适用于子线性布局?

注意:我测试了几次,知道(默认)可触摸 View 或 View 组(如按钮、 ScrollView 等)适用于我的代码,而(默认)不可触摸 View 或小部件(如 ImageView 、框架布局)不适用于我的代码。

最佳答案

解决方案涉及this回答,因为它是标准 MotionEvent 处理的结果。

在我的代码中,当我触摸子 LinearLayout 时,父 CustomViewGroup 不会拦截 MotionEvent,因为它返回 false,但是我的 child LinearLayout 也不使用 MotionEvent,所以 MotionEvent 返回给父级的 onTouchEvent,而不是onInterceptTouchEvent

另一方面,当我触摸我的 child ScrollView 时,无论滚动是启用还是禁用,它都会消耗 MotionEvent

==> 我认为是因为 Android 不会再次生成 MotionEvent 直到原始事件被消耗或完成,所以父级 CustomViewGroup 没有通过 onInterceptTouchEvent 获取 ACTION_MOVE MotionEvent,而是在 child 没有获取时通过管道传输到 onTouchEvent '使用 MotionEvent

我找到了两个解决方案

解决方案一

强行让我的 LinearLayout 使用 MotionEvent。只有当子 LinearLayout 没有可触摸的 ViewViewGroupWidget 时,此解决方案才可用。像这样:

LinearLayout mLinearLayout = (LinearLayout)findViewById(R.id.child_linear);
mLinearLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});

方案二

在我的 CustomViewGrouponTouchEvent 中处理从子项返回的 MotionEvent。像这样:(只需在 onTouchEvent 中添加 else if case)。

case MotionEvent.ACTION_MOVE: {
if (mIsBeingDragged) {
mLastMotionY = event.getY();
mLastMotionX = event.getX();
pullEvent();
return true;
}
else if (isReadyForPull()) {
final float y = event.getY(), x = event.getX();
final float diff, oppositeDiff, absDiff;
diff = y - mLastMotionY;
oppositeDiff = x - mLastMotionX;
absDiff = Math.abs(diff);
ViewConfiguration config = ViewConfiguration.get(getContext());

if (absDiff > config.getScaledTouchSlop() && absDiff >
Math.abs(oppositeDiff) && diff >= 1f) {
mLastMotionY = y;
mLastMotionX = x;
mIsBeingDragged = true;
}
}
break;
}

虽然解决方案 1 是针对某些情况的快速解决方案,但解决方案二是最灵活和可靠的。

关于java - 有 subview 时,Android onInterceptTouchEvent 不会执行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21953833/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com