Veljko
Veljko

Reputation: 1903

Pass click event through the view android

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!

Upvotes: 8

Views: 18740

Answers (5)

Eugene Voronoy
Eugene Voronoy

Reputation: 1433

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)

Upvotes: 7

cjds
cjds

Reputation: 8426

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;
    }

Upvotes: 0

LouisB
LouisB

Reputation: 1

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>

Upvotes: 0

Rotem
Rotem

Reputation: 1492

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;
        }

    }

Upvotes: 0

Vincent Mimoun-Prat
Vincent Mimoun-Prat

Reputation: 28541

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;
    }
}

Upvotes: 0

Related Questions