I have a horizontal recycler-view within motion layout. Sometimes when I do a horizontal swipe, the page starts scrolling in the vertical direction. This happens when we do a diagonal fling.
I want something like Google Play where horizontal recycler-views can defend slightly diagonal vertical swipes. BTW setting nestedscrollEnabled doesn't work.
There is quite a nice article regarding all the RecycleView scroll behavior and the issue itself. Checkout RĂºben Sousa article. Solution is quite easy, try to use adopted RecyclerView:
/**
* A RecyclerView that only handles scroll events with the same orientation of its LayoutManager.
* Avoids situations where nested recyclerviews don't receive touch events properly:
*/
public class OrientationAwareRecyclerView extends RecyclerView {
private float lastX = 0.0f;
private float lastY = 0.0f;
private boolean scrolling = false;
public OrientationAwareRecyclerView(#NonNull Context context) {
this(context, null);
}
public OrientationAwareRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public OrientationAwareRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
addOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
scrolling = newState != RecyclerView.SCROLL_STATE_IDLE;
}
});
}
#Override
public boolean onInterceptTouchEvent(MotionEvent e) {
final LayoutManager lm = getLayoutManager();
if (lm == null) {
return super.onInterceptTouchEvent(e);
}
boolean allowScroll = true;
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
lastX = e.getX();
lastY = e.getY();
// If we were scrolling, stop now by faking a touch release
if (scrolling) {
MotionEvent newEvent = MotionEvent.obtain(e);
newEvent.setAction(MotionEvent.ACTION_UP);
return super.onInterceptTouchEvent(newEvent);
}
break;
}
case MotionEvent.ACTION_MOVE: {
// We're moving, so check if we're trying
// to scroll vertically or horizontally so we don't intercept the wrong event.
float currentX = e.getX();
float currentY = e.getY();
float dx = Math.abs(currentX - lastX);
float dy = Math.abs(currentY - lastY);
allowScroll = dy > dx ? lm.canScrollVertically() : lm.canScrollHorizontally();
break;
}
}
if (!allowScroll) {
return false;
}
return super.onInterceptTouchEvent(e);
}
}
This Work perfect for me.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none" />
</LinearLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:orientation="vertical"
android:padding="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp">
<TextView
android:id="#+id/itemTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="#+id/btnMore"
android:text="Sample title"
android:textColor="#android:color/black"
android:textSize="18sp" />
<Button
android:id="#+id/btnMore"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:theme="#style/MyButton"
android:text="more"
android:textColor="#FFF" />
</RelativeLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_list"
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_gravity="center_vertical"
android:orientation="horizontal" />
</LinearLayout>
list_single_card.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:cardCornerRadius="5dp"
app:cardUseCompatPadding="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="0dp"
android:background="?android:selectableItemBackground"
android:orientation="vertical">
<ImageView
android:id="#+id/itemImage"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitCenter"
android:src="#drawable/android" />
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/itemImage"
android:gravity="center"
android:padding="5dp"
android:text="Sample title"
android:textColor="#android:color/black"
android:textSize="18sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
Try this:
RecyclerView rv = findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, true);
rv.setLayoutManager(layoutManager);
rv.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow RecyclerView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
// Allow RecyclerView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
v.onTouchEvent(event);
return true;
}
});
That code prevent scroll vertically when you scroll with your horizontal recyclerview.
Related
I am trying to create a horizontal scroll view inside horizontal scroll view in android. First horizontal scrolling views are working fine. When i am trying to scroll second horizontal scrolling views are not working.
my layout file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="100dp"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
android:layout_width="250dp"
android:layout_height="100dp"
app:cardCornerRadius="20dp"
app:cardBackgroundColor="#color/colorPrimary"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:scrollbars="horizontal"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp">
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="1"></Button>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2"></Button>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="3"></Button>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="4"></Button>
</LinearLayout>
</HorizontalScrollView>
</androidx.cardview.widget.CardView>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</RelativeLayout>
can anybody share your knowledge how to achieve this one?
You can create Custom class for nested scroll view for support horizontal smooth scroll.
public class HorizontalNestedScrollView extends NestedScrollView {
private int slop;
private float mInitialMotionX;
private float mInitialMotionY;
public HorizontalNestedScrollView(Context context) {
super(context);
init(context);
}
private void init(Context context) {
ViewConfiguration config = ViewConfiguration.get(context);
slop = config.getScaledEdgeSlop();
}
public HorizontalNestedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public HorizontalNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private float xDistance, yDistance, lastX, lastY;
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0f;
lastX = ev.getX();
lastY = ev.getY();
// This is very important line that fixes
computeScroll();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
xDistance += Math.abs(curX - lastX);
yDistance += Math.abs(curY - lastY);
lastX = curX;
lastY = curY;
if (xDistance > yDistance) {
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
}
You can read about the issue and the simple fix here: https://code.google.com/p/android/issues/detail?id=194398
Use this class in place of your nestedscrollview in the xml file, and the child lists should intercept and handle the touch events properly.
Hope this will help you.
xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/frame_living_root_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<SurfaceView
android:id="#+id/player_surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
<android.opengl.GLSurfaceView
android:id="#+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:visibility="gone" />
<com.netease.nimlib.sdk.avchat.model.AVChatSurfaceViewRenderer
android:id="#+id/video_render"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<com.netease.nimlib.sdk.avchat.model.AVChatSurfaceViewRenderer
android:id="#+id/bypass_video_render"
android:layout_width="110dip"
android:layout_height="150dip"
android:layout_gravity="right|end|bottom"
android:layout_marginBottom="70dip"
android:layout_marginEnd="10dip"
android:layout_marginRight="10dip"
android:visibility="gone" />
<!--root view is FrameLayout with 40dip layout_margin and is a little complex-->
<include layout="#layout/layout_live_top" />
<!-- the content of this view will be scroll by touch event-->
<com.example.SimpleSlideView
android:id="#+id/slide_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- yellow background-->
<ImageView
android:id="#+id/yellow_child_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff0" />
</com.example.SimpleSlideView>
</FrameLayout>
SimpleSlideView:
public class SimpleSlideView extends FrameLayout {
public int screenWidth;
public int screenHeight;
private float lastY;
public SimpleSlideView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
initScreenSize(context);
scrollTo(0, screenHeight);
}
private void initScreenSize(#NonNull Context context) {
DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
float rawY = ev.getRawY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = rawY;
break;
case MotionEvent.ACTION_MOVE:
final int delta = (int) (rawY - lastY);
scrollTo(0, getScrollY() - (delta));
lastY = rawY;
break;
case MotionEvent.ACTION_UP:
scrollTo(0, screenHeight);
break;
}
return true;
}
}
I want to write a SimpleSlideView that can scroll it content down by pull down on it SimpleSlideView works as expected in lightweight XML but a little weird in complex XML.
#layout/layout_live_top contain a FrameLayout root view with 40dip layout_margin and layout_live_top is a little complex.
SimpleSlideView is a MatchParent view without padding and margin, same with it child #+id/yellow_child_view which has a yellow background.
Something weird is happen when quickly pulldown:
The yellow area has 40dip margin left and right at the beginning of the pull and then it become match parent.SimpleSlideView seems to be affected by the margin(40dip) of other view, it should be matched parent while pulling down.I don't know why this happened.It is because of my complex XML?
I am working on an Android application using C# in Xamarin. In my axml file, I have a LinearLayout with a certain ID that I have assigned a onTouchListener to. The problem is that as long as the buttons I have in my design are on top of the linearLayout, the onTouchListener is never triggered. If I set one of the buttons to invisible, then it works.
Is it possible to still have the onTouchListener react even though there are Controls in the way?
This is my axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout1"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="#+id/button1"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="1"
android:layout_marginBottom="0.0dp"
android:background="#android:color/holo_green_light"
android:soundEffectsEnabled="false" />
<Button
android:id="#+id/button2"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="2"
android:background="#android:color/holo_blue_light" />
</LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1">
<Button
android:id="#+id/button3"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="3"
android:background="#android:color/holo_red_light" />
<Button
android:id="#+id/button4"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="4"
android:background="#android:color/holo_orange_light" />
</LinearLayout>
</LinearLayout>
This is how I set the onTouchlistener for the linearLayout:
LinearLayout linLay = FindViewById<LinearLayout>(Resource.Id.LinearLayout1);
linLay.SetOnTouchListener(new MyTouchListener(this));
This is a custom touch listener class:
public class MyTouchListener : Java.Lang.Object, View.IOnTouchListener
{
Context activityContext;
public MyTouchListener(Context ac)
{
activityContext = ac;
}
public bool OnTouch(View v, MotionEvent e)
{
float x = 0.0f;
float y = 0.0f;
if (e.Action == MotionEventActions.Down)
{
// do stuff
x = e.GetX();
y = e.GetY();
Toast.MakeText(activityContext, x.ToString(), ToastLength.Short).Show();
return true;
}
//if (e.Action == MotionEventActions.Up)
//{
// // do other stuff
// return true;
//}
return true;
}
}
And finally, this is how I set up the button click listener:
Button button = FindViewById<Button>(Resource.Id.button1);
button.Click += (s,e) =>
{
//int i = count % s.Count;
//if(i > 28)
// Toast.MakeText(this, button.GetX().ToString(), ToastLength.Short).Show();
button.Text = string.Format("{0}", count++);
};
You have to intercept the touch event. In order to do that you have to subclass LinearLayout and override onInterceptTouchEvent():
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyLinearLayout(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Toast.makeText(getContext(), "onTouch", Toast.LENGTH_SHORT).show();
return true;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
}
Your xml:
<?xml version="1.0" encoding="utf-8"?>
<com.your.package.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout1"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="#+id/button1"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="1"
android:layout_marginBottom="0.0dp"
android:background="#android:color/holo_green_light"
android:soundEffectsEnabled="false" />
<Button
android:id="#+id/button2"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="2"
android:visibility="invisible"
android:background="#android:color/holo_blue_light" />
</LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1">
<Button
android:id="#+id/button3"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="3"
android:background="#android:color/holo_red_light" />
<Button
android:id="#+id/button4"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="4"
android:background="#android:color/holo_orange_light" />
</LinearLayout>
</com.your.package.MyLinearLayout>
Now any touch event on the layout will be handled by your custom MyLinearLayout.
You need to extend (inherent) the parent linear layout so that you can intercept touch events from the nested children layouts. Override these two methods to receive touches from the children. Then in your xml you will add "myCustomLinearLayout" or whatever you name the your custom linear layout class. It should be pretty similar in C# / Xamarin.
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true; // With this i tell my layout to consume all the touch events from its childs
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Log.d(TAG, String.format("ACTION_DOWN | x:%s y:%s",
break;
case MotionEvent.ACTION_MOVE:
//Log.d(TAG, String.format("ACTION_MOVE | x:%s y:%s",
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
I have a ScrollView. One of its children is a ListView. Both scrolling in the same direction. How do I get both of them to respond to scroll events? And then when the end of the ListView is reached for the event to go to the parent ScrollView so the ScrollView may scroll?
xml layout:
<?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"
>
<LinearLayout
...
android:orientation="vertical"
>
<LinearLayout
android:id="#+id/..."
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="horizontal">
...
</LinearLayout>
<android.support.v4.view.ViewPager
.../>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/pad_half"
>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>
</LinearLayout>
</LinearLayout>
</ScrollView>
My ListView actually goes inside the ViewPager. The design is such that about three items in the ListView is visible, and user is able to scroll to see other items. In the meantime, the views above and below the ViewPager are visible. Again, it's a ViewPager: it has other pages than the ListView in question.
You Should not have a listview within a ScrollView.
But you can have a custom class and use that to accomplish A Listview with in a ScrollView.
Try the following code
first make a custom ScrollView Class.
public class VerticalScrollview extends ScrollView{
public VerticalScrollview(Context context) {
super(context);
}
public VerticalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
return false;
default: break;
}
return false;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
return true;
}
}
Then use this class for you layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:orientation="vertical" >
<com.gui.today.VerticalScrollview
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ProgressBar
android:id="#+id/progressBar3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal" />
<TextView
android:id="#+id/empty_calender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:text="#string/empty_calender"
android:textColor="#ffffff"
android:visibility="gone" />
<ListView
android:id="#+id/listView2"
android:layout_width="fill_parent"
android:layout_height="150dp" >
</ListView>
</FrameLayout>
</LinearLayout>
</com.gui.today.VerticalScrollview>
I have a ScrollView
Get rid of it.
One of its children is a ListView
Put everything in the ListView, either using addHeaderView()/addFooterView(), my MergeAdapter, or something else along those lines.
You cant scroll a listview same direction as the scrollview. But if you have a horizontal scrollview you can scroll vertical with a listview.
you cannot add a ListView in a scroll View ,as list view also scolls and there would be a synchonization problem between listview scroll and scroll view scoll. You can make a CustomList View and add this method into it.
#Override public boolean onInterceptTouchEvent(MotionEvent ev)
{
/*
* Prevent parent controls from stealing our events once we've gotten a touch down
*/
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
ViewParent p = getParent();
if (p != null) {
p.requestDisallowInterceptTouchEvent(true);
}
}
return false;
}
I have a layout where I have a ScrollView and some stuffs. It looks like:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/welcome_scrol_lay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="#drawable/bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#drawable/bg"
android:weightSum="100" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="vertical"
android:weightSum="100"
android:background="#drawable/specialmapholder">
<android.support.v4.view.ViewPager
android:id="#+id/welcomeViewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_weight="90"
android:clickable="true" />
<LinearLayout
android:id="#+id/welcome_indicatorLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:gravity="center" >
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="50"
android:orientation="vertical">
<TextView
android:id="#+id/welcome_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="Large Text"
android:textColor="#color/white"
android:textStyle="bold"
android:textSize="26dp"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/welcome_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="Medium Text"
android:textColor="#color/white"
android:textSize="14dp"
android:textStyle="bold"
android:layout_marginTop="20dp"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
</LinearLayout>
</ScrollView>
As you can see I have a Viewpager in the ScrollView. I want to disable scroll when I touch ViewPager, because when I want to change picture page is scrolled. How can I disable the scroll function when I touch the ViewPager?
In Android, parents can consume child's TouchEvents. In this case, the ScrollView consumes the TouchEvents of your ViewPager component. To avoid this behaviour, Android framework provides the onInterceptTouchEvent(MotionEvent).
In your case, you have to subclass ScrollView and change the onInterceptTouchEvent(MotionEvent) method. You should change the onInterceptTouchEvent(MotionEvent), so that the ScrollView consumes the child's event only when the user scrolls the ScrollView vertically.
example implementation for ListView:
public class VerticalListView extends ListView {
private float mLastX;
private float mLastY;
private float mDiffX;
private float mDiffY;
public VerticalListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalListView(Context context) {
super(context);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// reset difference values
mDiffX = 0;
mDiffY = 0;
mLastX = ev.getX();
mLastY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
mDiffX += Math.abs(curX - mLastX);
mDiffY += Math.abs(curY - mLastY);
mLastX = curX;
mLastY = curY;
// don't intercept event, when user tries to scroll horizontally
if (mDiffX > mDiffY) {
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
}