Pass click event through the view android

2019-06-21 23:46发布

问题:

I have frame layout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp" >

<LinearLayout
    android:id="@+id/widgetView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:layout_margin="10dp"
    android:gravity="center" >
</LinearLayout>

<LinearLayout
    android:id="@+id/widgetOverlayFrame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="false" >
</LinearLayout>

First layout contains widget layout, and second one is transparent and receives onLongClick for dragging method.That works, the problem is when i want to interact with widget, to click something, click event is taken by overlayFrame. How can i pass click event trough overlayFrame to widgetView?

EDIT:

Now I'm trying to attach GestureLister to overlayFrame LinearLayout, to somehow see difference between MotionEvent that represent single click and long click. The problem that I'm facing is that OnLongPress in gesture listener is always called whatever I do, single click or long click.

Is there an explanation for this behavior? Tnx!

回答1:

Instead of using GestureListener you can override the onTouchListener in this way.

This will call longPress when the timer runs out and if an up comes in between it will cancel the LongPress

   CountDownTimer c;
    long time=5000;
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                c= new CountDownTimer(5000, 1000) {
                          public void onTick(long millisUntilFinished) {
                                  time=millisUntilFinished;
                           }

                          public void onFinish() {
                                 Log.i("","LONG PRESS");
                           }}.start();

            break;
            case MotionEvent.ACTION_UP:
                if (time>0) {
                    Log.i("example","short click");
                    c.cancel();
                }
            break;
        }

        return true;
    }


回答2:

In my case I added flag to layoutParams of my view, which should have passed a touch event under:

WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE

This way view will ignore all touches (like view with visibility GONE)



回答3:

Maybe setting the overlay's attribute android:focusable="false" or android:focusableInTouchMode="false" would be enough.

You could also make your own overlay widget and override its onInterceptTouchEvent method to return false always.

public class NotTouchableLinearLayout extends LinearLayout {

    // Override constructors
    // ...

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


回答4:

Instead of setting a GestureListener on the top layout, you should create your own class that extends LinearLayout and to override it's onTouchEvent method. There you can implement the logic of long click \ short click etc.

The click events will first be sent to the widget layout, and only if it doesn't handle them (hence it's onTouchEvent returns false), you will get them on the top layout.

edit:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" >

<LinearLayout
android:id="@+id/widgetView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="10dp"
android:gravity="center" >
</LinearLayout>

<com.example.touchtesting.MyLinearLayout
android:id="@+id/widgetOverlayFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false" >
</com.example.touchtesting.MyLinearLayout>

</FrameLayout>

change the com.example.touchtesting to the name of your package. and this is the class:

        public class MyLinearLayout extends LinearLayout{

        public MyLinearLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        private long startClick = 0;

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    startClick = ev.getEventTime();
                    break;
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                    if (ev.getEventTime() - startClick < 500) {
                        Log.i("example","short click");
                    }
                    else {
                        Log.i("example","long click");
                    }
                    break;
            }

            return true;
        }

    }


回答5:

To get the long clicks to pass through the widgetView LinearLayout add android:longClickable="true". (For ordinary clicks add android:clickable="true")

So widgetView becomes:

<LinearLayout
    android:id="@+id/widgetView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:layout_margin="10dp"
    android:gravity="center" 
    android:longClickable="true">
</LinearLayout>


标签: android click