简体   繁体   English

将触摸事件传递给父视图

[英]Passing touch events to the parent view

I have a custom ViewSwitcher in which I implemented touch events so I am able to scroll through screens using the touchscreen. 我有一个自定义ViewSwitcher ,我在其中实现了触摸事件,因此我可以使用触摸屏滚动屏幕。

My layout hierarchy looks like this: 我的布局层次结构如下所示:

<ViewSwitcher>

    <LinearLayout>
        <ListView />
    </LinearLayout>

    <LinearLayout>
        <ListView />
    </LinearLayout>

</ViewSwitcher>

Now, the problem is that the touch events are being consumed by the ListViews and I am not able to switch the views. 现在,问题是ListViews正在使用触摸事件,我无法切换视图。 It works fine when I don't have the ListViews . 当我没有ListViews时,它工作正常。 I need to be able to scroll through the views and scroll the ListView . 我需要能够滚动视图并滚动ListView

How do I solve this? 我该如何解决这个问题?

EDIT : I also need the ListView items to be clickable. 编辑 :我还需要ListView项目可点击。

Thanks in advance! 提前致谢!

Thank you everyone for answering the question. 谢谢大家回答这个问题。 But I was able to figure it out in a much simpler manner. 但我能够以更简单的方式解决这个问题。 Since my ViewSwitcher wasn't detecting the touch event, I intercepted the touch event, called the onTouchEvent() and returned false . 由于我的ViewSwitcher没有检测到触摸事件,我拦截了触摸事件,称为onTouchEvent()并返回false Here: 这里:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    onTouchEvent(ev);
    return false;
}

By overriding the onInterceptTouchEvent() , I was able to intercept the touch event in the activity. 通过重写onInterceptTouchEvent() ,我能够拦截活动中的触摸事件。 Then I called the onTouchEvent() in the ViewSwitcher which handles the switching of the ListViews . 然后我称为onTouchEvent()ViewSwitcher它处理的切换ListViews And finally by returning false , it makes sure that the ViewGroup doesn't consume the event. 最后返回false ,确保ViewGroup不消耗该事件。

The simplest way to pass child view's TouchEvent to parent view is by adding this to child view: 将子视图的TouchEvent传递给父视图的最简单方法是将其添加到子视图:

@Override
public boolean onTouchEvent(MotionEvent event) { 
    super.onTouchEvent(event);
    return false;
}

In my parent layout, the only way I have found to prevent the child from capturing the touch event is by overriding onInterceptTouchEvent to return true. 在我的父布局中,我发现阻止子进程捕获触摸事件的唯一方法是重写onInterceptTouchEvent以返回true。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    return true;
}

I don't think there is an easy way for you to do this. 我认为没有一种简单的方法可以做到这一点。

It's not that complicated, but you will need to create your own view that extends the ListView. 它并不复杂,但您需要创建自己的视图来扩展ListView。 Then you can override the onTouch handler and decide (depending on the touch event) whether you want to handle it (and return true) or pass it down to the parent View. 然后,您可以覆盖onTouch处理程序并决定(取决于触摸事件)是否要处理它(并返回true)或将其传递给父视图。

The problem also is that once a View handles a touch event, it is the one that will get all the remaining ones... 问题还在于,一旦View处理触摸事件,它就会获得所有剩余的事件......

From the Android documentation : Android文档

onTouch() - This returns a boolean to indicate whether your listener consumes this event. onTouch() - 返回一个布尔值,指示您的侦听器是否使用此事件。 The important thing is that this event can have multiple actions that follow each other. 重要的是这个事件可以有多个相互跟随的动作。 So, if you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. 因此,如果在收到向下操作事件时返回false,则表示您尚未使用该事件,并且对此事件的后续操作也不感兴趣。 Thus, you will not be called for any other actions within the event, such as a finger gesture, or the eventual up action event 因此,您不会在事件中调用任何其他操作,例如手指手势或最终的上行动作事件

So, for example, if you want to have vertical move to scroll through the list and during the same touch event (without lifting your finger), you want horizontal move to switch the views, that's going to be quite challenging. 因此,例如,如果您希望垂直移动以滚动列表并在同一触摸事件期间(不抬起手指),您希望水平移动切换视图,这将是非常具有挑战性的。

But if you can use gestures for example or handle everything in your custom view and depending on what the MotionEvent is, send commands to the ViewSwitcher. 但是,如果您可以使用手势或处理自定义视图中的所有内容,并根据MotionEvent的内容,将命令发送到ViewSwitcher。

what i did is to set a toucheventlistener on the listview in the viewswitcher, handles the event, detects the fling action and call the metchod of viewswitcher. 我所做的是在viewswitcher的listview上设置toucheventlistener,处理事件,检测fling动作并调用viewswitcher的metchod。 it works. 有用。

You could also insert a call to handle the touchevent in dispatchTouchEvent , but in this case you have also to override onTouchEvent to return true, otherwise only the first MotionEvent DOWN of the gesture will be passed. 你也可以插入一个呼叫处理toucheventdispatchTouchEvent ,但在这种情况下,你必须也覆盖onTouchEvent返回true,否则只有第一个MotionEvent手势的DOWN将被传递。

This is the touchable wrapper container: 这是可触摸的包装容器:

<?xml version="1.0" encoding="utf-8"?>
<view xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.example.myapp.FragmentContainer$TouchableWrapper" />

And the class: 和班级:

public static class TouchableWrapper extends FrameLayout {
    private GestureDetector gestureDetector;
    public void setGestureDetector(GestureDetector gestureDetector) {
        this.gestureDetector = gestureDetector;
    }

    // these constructors for the XML inflater
    public TouchableWrapper(Context context) {
        super(context);
    }
    public TouchableWrapper(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public TouchableWrapper(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Log.d(TAG, "onInterceptTouchEvent " + event.toString());
        return false; // true for intercept, false è default and pass on to children View
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "dispatchTouchEvent " + event.toString());
        gestureDetector.onTouchEvent(event);
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent " + event.toString());
        return true; //return super.onTouchEvent(event); 
    }
}

This is the GestureDetector reference: 这是GestureDetector参考:

private GestureDetector gestureDetector;

This the GestureListener : 这是GestureListener

private GestureDetector.SimpleOnGestureListener sOGL = new GestureDetector.SimpleOnGestureListener() {
    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        goToRight(); // onSwipeRight();
                    } else {
                        goToLeft(); // onSwipeLeft();
                    }
                }
                result = true;
            } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                if (diffY > 0) {
                    // onSwipeBottom();
                } else {
                    // onSwipeTop();
                }
            }
            result = true;

        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result; // return false indicate event not handled
    }
};

Ant this to load the touchable container fragment and a contained fragment: 使用Ant来加载可触摸的容器片段和包含的片段:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView()");
    View view = inflater.inflate(R.layout.fragmentcontainer, container, false);

    gestureDetector = new GestureDetector(view.getContext(), sOGL);
    ((FragmentContainer.TouchableWrapper) view).setGestureDetector(gestureDetector);

    FragmentManager fm = this.getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.pager, frag).commit();

    return view;
}

It was necessary to handle the touch in the TextView in the parent view with the autoLink = "three" Did so: 有必要在父视图中使用autoLink =“三”来处理TextView中的触摸。这样做:

private LinearLayout mParentView;
private TextView mTextView;
private View.OnTouchListener mParentListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        ......
        return false;
    }
};
mParentView.setOnTouchListener(mParentListener);

mTextView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mParentListener.onTouch(mParentView, event);
        return false;
    }
};

Did you try setting the ListView items as non-clickable like this: listView.setClickable(false); 您是否尝试将ListView项设置为不可单击,如下所示:listView.setClickable(false); This should propogate the click event upwards. 这应该向上传播click事件。

If your view wants to pass the event up, make sure you return false in onTouchEvent. 如果您的视图想要传递事件,请确保在onTouchEvent中返回false。 Otherwise, the platform thinks you consumed the event and no further processing is needed. 否则,平台认为您使用了该事件,无需进一步处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM