Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android, gestures over clickable widgets

My application contains an area filled with buttons. I wish to implement the activity in such way, that fling gesture over the button area would switch it to one of two another areas (using ViewFlipper).

I've made two approaches on detecting gestures. The first one involved using GestureDetector. However, the touch motion events over the Button didn't raised the onTouchEvent activity method, so - in result - I couldn't have forwarded it to the GestureDetector class. A failure, in short.

The second approach - involved using the GestureOverlayView. This time, however, I've reached the second extreme: not only the gesture was detected, but also the button, over which gesture is performed, reported a click.

I wish the interface to work in the following way: if user touches button and releases the touch (or moves the finger only a little), the button reports click and no gesture is detected. On the other hand, if user touches the screen and makes a longer move, the gesture shall be detected and no click event reported by the button.

I've implemented a small proof-of-concept application. The activity XML code follows:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"  xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical">
  <android.gesture.GestureOverlayView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/overlay">
    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
    <TextView android:id="@+id/display" android:layout_width="match_parent" android:layout_height="wrap_content" />
    <Button android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/button"/>
    </LinearLayout>
  </android.gesture.GestureOverlayView>
</LinearLayout>

The activity java code follows:

package spk.sketchbook;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.gesture.*;
import android.gesture.GestureOverlayView.OnGestureListener;

public class Main extends Activity implements OnGestureListener, OnClickListener
{       
  private void SetupEvents()
  {
    GestureOverlayView ov = (GestureOverlayView)findViewById(R.id.overlay);
    ov.addOnGestureListener(this);

    Button b = (Button)findViewById(R.id.button);
    b.setOnClickListener(this);
  }

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    SetupEvents();
  }

  @Override
  public void onGesture(GestureOverlayView arg0, MotionEvent arg1)
  {
    TextView tv = (TextView)findViewById(R.id.display);
    tv.setText("Gesture");
  }

  @Override
  public void onGestureCancelled(GestureOverlayView arg0, MotionEvent arg1)
  {

  }

  @Override
  public void onGestureEnded(GestureOverlayView overlay, MotionEvent event)
  {

  }

  @Override
  public void onGestureStarted(GestureOverlayView overlay, MotionEvent event)
  {

  }

  @Override
  public void onClick(View v)
  {
    TextView tv = (TextView)findViewById(R.id.display);
    tv.setText("Click");
  }


}

The question is: how to implement such an interface, which can decide, if user action shall be treated as the gesture or button click?

Best regards -- Spook.

like image 679
Spook Avatar asked Apr 21 '11 16:04

Spook


People also ask

In what way gestures are preferred than touch events?

In what way gestures are preferred than touch events? Â Gestures are scripted “solutions” that take advantage of these touch events. Â So instead of tracking two touch points to determine if they're moving away or closer to one another in order to manipulate the size of a photo, you can just use GESTURE_ZOOM.

What is multi touch Gesture in Android?

A multi-touch gesture is when multiple pointers (fingers) touch the screen at the same time. This lesson describes how to detect gestures that involve multiple pointers. Refer to the following related resources: Input Events API Guide. Sensors Overview.

How do I go back with gestures on Android?

Move between screens, webpages & apps Gesture navigation: Swipe from the left or right edge of the screen. 2-button navigation: Tap Back . 3-button navigation: Tap Back .

How do I turn off Gesture navigation?

You can easily enable or disable the 'Gesture' settings. Just navigate to Settings > System > Gestures . Here, you can enable or disable a number of Gesture settings.


2 Answers

Solved myself. The idea is to catch gesture events from GestureOverlayView and, apart from passing them to GestureDetector, measure the distance of user's gesture. The distance shall be stored in a private activity's field (thus available for all event handlers). Finally, fling and click handlers shall check the value of this field; if it is below certain value (say, 10 pixels shall be fine), it should be interpreted as a click. Otherwise - as a gesture.

Note, that the button will both look clicked and its click handler will be called. I've decided to create a low-level click handler (attached to all buttons over GestureOverlayView), which does the gesture/click check and if the result is a click, chooses one of higher-level click handlers.

The solution works for me; however if one wished to disable the clicked look of button and prevent the handler from being called, it would probably involve redefining the button and/or GestureOverlayView components.

like image 145
Spook Avatar answered Oct 12 '22 21:10

Spook


anOther Solution: Make this function:

public void SetSwipe(View v, final GestureDetector gestureScanner){
    // Sets scroll view listener
    v.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
              if (gestureScanner.onTouchEvent(event))  
                return true;  
              else  
                return false;  
        }
    });
}

And call it for each Widget as follows:

scfSetTag.SetSwipe(svAllView, gestureScanner);

If you need make this from many activities or fragments, you can make a class.java file and instantiate this class on each activity you need implement the swipe. This detects both swipe an click on any witdget. Hope help!

like image 21
Rambo VI Avatar answered Oct 12 '22 21:10

Rambo VI