Right now I can handle swipe gestures fine with the posted code. But I want to add a background color for the transition as the user swipes from one direction to another. Very similar to the way the stock contacts app does it. I know I will have to use a GestureOverlay but I can't figure out how to link that with my current code. Is it possible, or is there an easier way to do this?
// inside my onCreate method
View view = getLayoutInflater().inflate(R.layout.gesture_overlay, null);
GestureOverlayView gestureOverlayView = new GestureOverlayView(this);
gestureOverlayView.addView(view);
mGestureDetector = new GestureDetector(new MyGestureDetector());
mGestureListener = new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
mLongPress = false;
return mGestureDetector.onTouchEvent(event);
}
};
// mListView.setOnItemClickListener(this);
mListView.setOnTouchListener(mGestureListener);
}
class MyGestureDetector extends SimpleOnGestureListener {
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 200;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
return false;
}
// right to left swipe
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
return true;
} else
if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
return true;
}
return false;
}
}
I have created a solution that worked for me so far...
create for the list item a flipperview like this:
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listItemViewFlipper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- ViewFlipper Child 1 -->
<RelativeLayout
android:id="#+id/listItem"
android:layout_width="match_parent"
android:layout_height="80dip"
android:padding="4dip"
android:background="#drawable/list_item_background"
>
<TextView
android:id="#+id/productName"
android:singleLine="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:gravity="left|center_vertical"
android:text=""
android:textColor="#FFFFFF"/>
<TextView
android:id="#+id/short_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="short description"
android:gravity="left"
android:layout_below="#id/productName"
/>
<EditText
android:id="#+id/editValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="#string/value"
android:layout_alignParentRight="true"
android:layout_alignBaseline="#id/productName"
android:textColorHint="#FFFFFF"
android:text=""
android:singleLine="true"
android:inputType="number"
android:textColor="#FFFFFF"
android:maxLength="2"
/>
<TextView
android:id="#+id/productPrice"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingRight="8dip"
android:layout_toLeftOf="#id/editValue"
android:text="€3,40"
android:textSize="20sp"
android:textColor="#FFFFFF"
/>
</RelativeLayout>
<!-- Transition views -->
<!-- ViewFlipper Child 2 -->
<LinearLayout
android:id="#+id/transitionViewAdd"
android:layout_width="match_parent"
android:layout_height="80dip"
android:padding="4dip"
android:background="#drawable/list_item_swipe"
android:orientation="horizontal"
>
<TextView
android:id="#+id/swipe_transition_textview_add"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textSize="25sp"
android:textColor="#FFFFFF"
android:text="#string/swipe_transition_text_add"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:src="#drawable/content_new"
/>
</LinearLayout>
<!-- ViewFlipper Child 3 -->
<LinearLayout
android:id="#+id/transitionViewRemove"
android:layout_width="match_parent"
android:layout_height="80dip"
android:background="#ff7978"
android:orientation="horizontal"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:src="#drawable/ic_action_remove"
/>
<TextView
android:id="#+id/swipe_transition_textview_remove"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textSize="25sp"
android:textColor="#FFFFFF"
android:text="#string/swipe_transition_text_remove"
/>
</LinearLayout>
</ViewFlipper>
Set for the background of the flipperview a gradient like below:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:startColor="#FF0000"
android:endColor="#android:color/transparent"
android:angle="0"/>
<corners android:radius="3dp"/>
</shape>
now in the GestureDetector when swiping change the FlipperView to the View you want.
(I assume you use the MotionEvent to handle the different states of the swipe)
case MotionEvent.ACTION_MOVE:{
float deltaX = motionEvent.getRawX() - mDownX;
int deltaXRound = Math.round(deltaX);
float deltaY = motionEvent.getRawY() - mDownY;
if(mVelocityTracker == null || mPaused){
break;
}
if(Math.abs(deltaY) > Math.abs(deltaX)){
return false;
}
mVelocityTracker.addMovement(motionEvent);
if (Math.abs(deltaX) > mSlop) {
mSwiping = true;
mListView.requestDisallowInterceptTouchEvent(true);
}
// Cancel ListView's touch (un-highlighting the item)
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
(motionEvent.getActionIndex()
<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));
mListView.onTouchEvent(cancelEvent);
cancelEvent.recycle();
if(deltaX > 0 && mSwiping){
mViewFlipper.setDisplayedChild(mViewFlipper.indexOfChild(mViewFlipper.findViewById(R.id.transitionViewAdd)));
mCurrentFlipperView = mViewFlipper.getCurrentView();
Drawable background = mCurrentFlipperView.getBackground();
background.setBounds(0, 0, deltaXRound, mCurrentFlipperView.getHeight());
background.invalidateSelf();
now.. the thing that does the trick is to use the setBounds method to set the bounds of the background of your listitem
Drawable background = mCurrentFlipperView.getBackground();
background.setBounds(0, 0, deltaXRound, mCurrentFlipperView.getHeight());
background.invalidateSelf();
this works for me.. it creates a gradient that follows the touch while swiping.. it needs some editing to let it work better.. but i've looked for a solution very long and I know a lot of people are looking for it so I wanted to show it as fast as possible.
But i think you'll figure it out to make it the way you want.
Does the screenshot comes from Samsung phone? I have implemented this effect before.
This swipe bar isn't a gradient color but just composed with three pictures .
You can get these pictures by decompile the APK file with apktool
Related
I am trying to implement horizontal and vertical scrolling for a Recycler view at the same time.I have to show a table of 8 columns, so I plan to implement horizontal and vertical scrolling at the same time.
I tried HorizontalScrollView in list row but it is scrolling horizontally in one row.
I also tried the HorizontalScrollView as the parent of recyclerview but its not working
list_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:clickable="true"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical">
<TextView
android:id="#+id/title"
android:textColor="#color/title"
android:textStyle="bold"
android:layout_alignParentTop="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="aaa"/>
<TextView
android:layout_toRightOf="#+id/title"
android:id="#+id/genre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="bbb"/>
<TextView
android:layout_toRightOf="#+id/genre"
android:id="#+id/year"
android:textColor="#color/year"
android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="20dp"
android:layout_height="wrap_content"
android:text="ccc"/>
</RelativeLayout>
Activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
can any one please tell me an idea.
The best solution i found so far to have horizontal and vertical scrolling on one view is to put it inside one FrameLayout. Then your view must implement OnTouch (you can do this in your activity to) and you just have to scroll it as the touch pointer moves.
Here is an example :
xml :
<FrameLayout
android:id="#+id/TwoWaysScrollableContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false">
<YourView
android:id="#+id/GridContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false" />
</FrameLayout>
C# (i use xamarin, but Java wouldn't have so many differencies i think)
:
public class MyActivity : Activity
{
private MyView _myView; //Can be GridView, relative layout or wathever
private float _startX, _startY,_prevDx, _prevDy, _dx,_dy;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
_myView = FindViewById<MyView>(Resource.Id.GridContainer);
}
public bool OnTouch(View v, MotionEvent e)
{
switch (e.Action)
{
case MotionEventActions.Down:
{
mode = Mode.DRAG;
startX = e.GetX() - prevDx;
startY = e.GetY() - prevDy;
break;
}
case MotionEventActions.Move:
{
/* you also could add logic to prevent your view from scrolling out of you grid bounds*/
if (mode == Mode.DRAG)
{
dx = startX - e.GetX();
dy = startY - e.GetY();
_myView.ScrollBy((int)(dx), (int)(dy));
startX = e.GetX();
startY = e.GetY();
}
break;
}
case MotionEventActions.Up:
{
mode = Mode.NONE;
prevDx = dx;
prevDy = dy;
break;
}
}
return true;
}
}
I know this doesn't answer your question directly ( i don't know much about recycler view), but i hope it can still help you. I used this for a tile engine and it did the trick very well.
I've searched around and has read this thread and this thread and so, but nothing helped me .
I have a listview that contains custom layouts. the layout has a custom seekbar. I've used the seekbar out of the listview and it works very well but when uses in list view the onTouch event does not called correctly and runs only when I'm start touching it.
this is a part of my code in getView:
newSimpleDim.layTouch1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
if (y < 0)
y = 0;
if (y > dimHeight)
y = dimHeight;
G.log("Event : " + event.getAction());
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
setHeight(newSimpleDim.layGray1, y);
setHeight(newSimpleDim.layGreen1, dimHeight - y);
setPadding(newSimpleDim.imgGreen1, -y);
newSimpleDim.txtlbl1.setText("" + (100 - ((int) ((y / (double) dimHeight) * 100))));
break;
}
return true;
}
});
and this is list item layout :
<LinearLayout
android:id="#+id/dimmerOne"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/layTouch1"
android:layout_width="wrap_content"
android:layout_height="202dp"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/layGray1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dp"
android:orientation="vertical" >
<ImageView
android:id="#+id/imgGray1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
android:src="#drawable/lay_component_dimmer_slider_off" />
</LinearLayout>
<LinearLayout
android:id="#+id/layGreen1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/imgGreen1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="matrix"
android:src="#drawable/lay_component_dimmer_slider_on" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="#+id/txtlbl1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="TextView"
android:typeface="monospace" />
</LinearLayout>
This problem seems similar to the one I was facing, I am has checkbox and on itemClickListener was not working, did the following to make itemClickListener work,
Added the following properties to the checkbox,
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
and ItemClickListner started working.
for you if onTouch is not getting invoked for the seek bar then add the above code to the layout.
For detailed example for checkbox clickable in listview you can go through the link, and you can apply the same concept to make your onTouch wor
http://knowledge-cess.com/android-itemclicklistner-with-checkbox-or-radiobutton/
Hope it helps Cheers!!
I have an image button, i am trying to record an audio on touch of a button & when user leaves a button i stop recording.I am successfull in doing that.I have a problem when user starts moving its finger within that bounds of imagebutton.I am using on ACTION_MOVE to handle this, i am not getting 100% success , sometimes it detects on leave , sometimes not. Please help. Below is code i am using..
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
case R.id.btn_audio :
final int action = event.getAction();
// get the View's Rect relative to its parent
v.getHitRect(rect);
// offset the touch coordinates with the values from rect to obtain meaningful coordinates
final float x = event.getX() + rect.left;
final float y = event.getY() + rect.top;
switch (action) {
case MotionEvent.ACTION_DOWN :
audioBtn.setImageDrawable(getResources().getDrawable(R.drawable.img_audio_pressed));
mHandler.sendEmptyMessage(MSG_START_TIMER);
timer.setVisibility(View.VISIBLE);
playBtn.setVisibility(View.GONE);
break;
case MotionEvent.ACTION_MOVE :
Log.e(TAG, rect.top+","+rect.bottom+","+rect.left+","+rect.right);
Log.e(TAG, (int)x+","+(int)y);
if (!rect.contains((int) x, (int) y)) {
Log.e(TAG, "In action move,outside");
audioBtn.setImageDrawable(getResources().getDrawable(R.drawable.img_audio));
playBtn.setVisibility(View.VISIBLE);
if (stop)
mHandler.sendEmptyMessage(MSG_STOP_TIMER);
} else {
Log.e(TAG, "In action move,inside");
audioBtn.setImageDrawable(getResources().getDrawable(R.drawable.img_audio_pressed));
timer.setVisibility(View.VISIBLE);
playBtn.setVisibility(View.GONE);
}
break;
case MotionEvent.ACTION_UP :
// the user raised his finger, cancel the Runnable
audioBtn.setImageDrawable(getResources().getDrawable(R.drawable.img_audio));
playBtn.setVisibility(View.VISIBLE);
if (stop)
mHandler.sendEmptyMessage(MSG_STOP_TIMER);
break;
}
break;
default :
break;
}
return false;
}
XML ::
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/actvity_background"
android:padding="15dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/record_review"
style="#style/textview.review"
android:layout_below="#id/rating_app"
android:layout_marginTop="20dp"
android:text="Record a review" />
<LinearLayout
android:id="#+id/record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/record_review"
android:orientation="horizontal"
android:splitMotionEvents="false"
android:weightSum="2" >
<RelativeLayout
android:id="#+id/audio_record"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" >
<ImageButton
android:id="#+id/btn_audio"
style="#style/imagebutton"
android:layout_centerInParent="true"
android:layout_marginTop="20dp"
android:background="#android:color/transparent"
android:contentDescription="#string/desc_provider_thumb"
android:focusableInTouchMode="true"
android:src="#drawable/img_audio" />
<TextView
android:id="#+id/timer"
style="#style/textview.review"
android:layout_below="#id/btn_audio"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:text="00:30"
android:visibility="gone" />
<ImageButton
android:id="#+id/btn_play"
style="#style/imagebutton"
android:layout_below="#id/btn_audio"
android:layout_marginLeft="6dp"
android:layout_marginTop="5dp"
android:layout_toRightOf="#id/timer"
android:background="#android:color/transparent"
android:contentDescription="#string/desc_provider_thumb"
android:src="#drawable/img_play"
android:visibility="gone" />
<ImageButton
android:id="#+id/btn_pause"
style="#style/imagebutton"
android:layout_below="#id/btn_audio"
android:layout_marginLeft="6dp"
android:layout_marginTop="5dp"
android:layout_toRightOf="#id/timer"
android:background="#android:color/transparent"
android:contentDescription="#string/desc_provider_thumb"
android:src="#drawable/img_pause"
android:visibility="gone" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/video_record"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" >
<ImageButton
android:id="#+id/btn_video"
style="#style/imagebutton"
android:layout_centerInParent="true"
android:layout_marginTop="20dp"
android:background="#android:color/transparent"
android:contentDescription="#string/desc_provider_thumb"
android:src="#drawable/img_video" />
<RelativeLayout
android:id="#+id/video_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" >
<ImageView
android:id="#+id/thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:src="#drawable/img_dumy_home_video_thumbnail" />
<ImageButton
android:id="#+id/play_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/img_play" />
</RelativeLayout>
<Button
android:id="#+id/btn_rerecord"
style="#style/button.review"
android:layout_below="#id/video_preview"
android:layout_centerHorizontal="true"
android:layout_marginTop="2dp"
android:text="#string/re_record"
android:visibility="gone" />
</RelativeLayout>
</LinearLayout>
<Button
android:id="#+id/btn_submit_review"
style="#style/button.review"
android:layout_below="#id/record"
android:text="Submit review" />
</RelativeLayout>
return true
instead of
return false
in your onTouch method
Instead of v.getHitRect(rect); use getLocationInWindow() which returns screen co-ordinates instead of co-ordinates relative to the parent. Update your onTouch code as follows:
//same here
...
...
int[] location = new int[2];
v.getLocationInWindow(location); // get position on the screen.
rect = new Rect(location[0], location[1], location[0]+v.getWidth(), location[1]+v.getHeight());
final float x = event.getX(); // screen x position
final float y = event.getY(); // screen y position
...
...
//same here
This is my Layout xml file.
...
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/rlt" >
<TextView
android:id="#+id/title_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="22dp"
android:layout_centerHorizontal="true"
android:textColor ="#add8e6"
/>
<TextView
android:id="#+id/description"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/tatle_text"
android:layout_marginTop="45dp"
android:textColor = "#e3e4fa"
android:autoLink="email"
android:textColorLink="#fdd017"
/>
...
...
...
...
This is my onFling() :
SimpleOnGestureListener simpleOnGestureListener
= new SimpleOnGestureListener(){
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
final float xDistance = Math.abs(e1.getX() - e2.getX());
final float yDistance = Math.abs(e1.getY() - e2.getY());
if(xDistance > gs.swipe_Max_Distance || yDistance > gs.swipe_Max_Distance)
return false;
Log.v("Help_developers", "Flinging baby!");
velocityX = Math.abs(velocityX);
velocityY = Math.abs(velocityY);
boolean result = false;
if(velocityX > gs.swipe_Min_Velocity && xDistance > gs.swipe_Min_Distance){
if(e1.getX() > e2.getX()) // right to left
{ //Slide to Help_app
Intent i=new Intent(Help_developers.this,Help_app.class);
startActivity(i);
finish();
}
else
{
//Slide to Help_qanda
Intent i=new Intent(Help_developers.this,Help_pending.class);
startActivity(i);
finish();
}
result = true;
}
return result;
}
});
final GestureDetector gestureDetector
= new GestureDetector(simpleOnGestureListener);
rlt.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View view, MotionEvent event) {
Log.d("test", "clicked!");
if(gestureDetector.onTouchEvent(event)) {
Log.d("test", "gesture detected");
return true;
}
return false;
}
});
rlt is the id of RelativeLayout rlt.
Now the flinging in the onFling() does not work with the attribute android:autoLink="email" in the text view with id description. But when I remove that attribute, the fling works. I have no idea why this is happening. How can that attribute affect the fling gesture?
EDIT
The onTouch() of the GestureListener itself is not called. The logs are never recorded in the logcat. When the attribute android:autoLink="email" is present.
Complete Layout XML File :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/rlt" >
<TextView
android:id="#+id/title_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="22dp"
android:layout_centerHorizontal="true"
android:textColor ="#ffffff"
/>
<TextView
android:id="#+id/description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tatle_text"
android:layout_marginTop="45dp"
android:textColor = "#e3e4fa"
android:autoLink="email"
android:textColorLink="#fdd017"
android:
/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rlt_touch" />
<Button
android:id="#+id/Home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="#drawable/home"
android:text="Home"
/>
</RelativeLayout>
</ScrollView>
Instead of turning off the touch handling in the TextView as in my first answer, we can add a transparent View (as the topmost child of the RelativeLayout) to capture the touch events so that we can selectively forward relevant events to the TextView while still getting all the events to detect the gestures:
Modify the XML layout, adding the touch-capturing View:
...
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rlt">
<TextView
android:id="#+id/title_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="22dp"
android:layout_centerHorizontal="true"
android:textColor="#add8e6"
android:background="#ff0000" />
<TextView
android:id="#+id/description"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/title_text"
android:layout_marginTop="45dp"
android:textColor="#e3e4fa"
android:textColorLink="#fdd017"
android:autoLink="email" />
<!-- our touch-capturing view -->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rlt_touch" />
</RelativeLayout>
...
Modify the Java code, setting our OnTouchListener to the added rlt_touch View instead and adding the event forwarding code:
final View rt = findViewById(R.id.rlt_touch);
final TextView tv = (TextView) findViewById(R.id.description);
rt.setOnTouchListener(new OnTouchListener() {
final Rect r = new Rect();
final Point p1 = new Point();
final Point p2 = new Point();
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("test", "clicked!");
if (gestureDetector.onTouchEvent(event)) {
Log.d("test", "gesture detected");
}
// offset touch location into the TextView and forward it if relevant
rt.getGlobalVisibleRect(r, p2);
tv.getGlobalVisibleRect(r, p1);
event.offsetLocation(p2.x - p1.x, p2.y - p1.y);
if (r.contains((int) event.getRawX(), (int) event.getRawY())) {
tv.onTouchEvent(event);
}
return true;
}
});
Setting android:autoLink="email" on your TextView will make it to start consuming touch events, affecting whether your OnTouchListener will get events supplied to it or not.
Here's a couple of changes that you can try so you always get the events:
Set the android:linksClickable attribute on your TextView to false:
...
android:autoLink="email"
android:linksClickable="false"
...
Modify your OnTouchListener to always return true:
rlt.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("test", "clicked!");
if (gestureDetector.onTouchEvent(event)) {
Log.d("test", "gesture detected");
}
return true;
}
});
I have a custom draggable SlidingDrawer using RadioButtons as its Handle. In order to enable the touch events on the RadioButtons I call return super.onInterceptTouchEvent(event); instead of return true on the onInterceptTouchEvent method. But somehow every time I want to drag my SlidingDrawer I can't drag it up by touching exactly on the RadioButtons, I have to move my finger up a little bit to drag the SlidingDrawer up.
Is there any way to make the SlidingDrawer exactly draggable by touching its RadioButtons without losing the TouchEvent on the RadioButtons itself?
Here's my touch method:
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mLocked) {
//return false;
}
final int action = event.getAction();
float x = event.getX();
float y = event.getY();
final Rect frame = mFrame;
final View handle = mHandle;
handle.getHitRect(frame);
if (!mTracking && !frame.contains((int) x, (int) y)) {
return false;
}
if (action == MotionEvent.ACTION_DOWN) {
mTracking = true;
WWHApplication.getListActivityIntance().resizeListView(1800);
handle.setPressed(true);
// Must be called before prepareTracking()
prepareContent();
// Must be called after prepareContent()
if (mOnDrawerScrollListener != null) {
mOnDrawerScrollListener.onScrollStarted();
}
if (mVertical) {
final int top = mHandle.getTop();
mTouchDelta = (int) y - top;
prepareTracking(top);
} else {
final int left = mHandle.getLeft();
mTouchDelta = (int) x - left;
prepareTracking(left);
}
mVelocityTracker.addMovement(event);
}
//return true;
return super.onInterceptTouchEvent(event);
}
Here's how my handle looks like
<LinearLayout
android:id="#+id/handle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/tab_content_bg_top" />
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/tab_content_bg"
android:fillViewport="true"
android:scrollbars="none" >
<RadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RadioButton
android:id="#+id/cb_tab_all"
android:layout_width="46dp"
android:layout_height="45dp"
android:background="#drawable/checkbox_background"
android:button="#drawable/tab_all_selector"
android:onClick="true" />
<RadioButton
android:id="#+id/cb_tab_favorites"
android:layout_width="84dp"
android:layout_height="45dp"
android:background="#drawable/checkbox_background"
android:button="#drawable/tab_favorites_selector"
android:onClick="true" />
<RadioButton
android:id="#+id/cb_tab_historical"
android:layout_width="134dp"
android:layout_height="45dp"
android:background="#drawable/checkbox_background"
android:button="#drawable/tab_historical_selector"
android:onClick="true" />
<RadioButton
android:id="#+id/cb_tab_food"
android:layout_width="116dp"
android:layout_height="45dp"
android:background="#drawable/checkbox_background"
android:button="#drawable/tab_food_selector"
android:onClick="true" />
</RadioGroup>
</HorizontalScrollView>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/tab_content_bg_bottom" />
</LinearLayout>