Android中一个ScrollView嵌套在另一个ScrollView中无法滚动。

24

我正在尝试在一个 ScrollView 中嵌套另一个 ScrollView,我尝试了在该站点上找到的答案,但似乎仍然无法完全工作。以下是 XML:

 <ScrollView
    android:id="@+id/scrollView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusableInTouchMode="false" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textViewDirectoryDetailName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Name"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="@color/red" />

        <LinearLayout
            android:id="@+id/linearLayoutDirectoryDetailContainImage"
            android:layout_width="300dp"
            android:layout_height="200dp"
            android:layout_gravity="center_vertical|center_horizontal"
            android:background="@drawable/general_image"
            android:gravity="center"
            android:orientation="vertical" >
        </LinearLayout>

        <ScrollView
            android:id="@+id/scrollView2"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:focusableInTouchMode="false" >

            <TextView
                android:id="@+id/textViewDirectoryDescription"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:autoLink="phone"
                android:text="098 123 45 678"
                android:textAppearance="?android:attr/textAppearanceLarge" />
        </ScrollView>

以下是Java代码:

parentScrollView = (ScrollView) findViewById(R.id.scrollView1);
    childScrollView = (ScrollView) findViewById(R.id.scrollView2);

    parentScrollView.setOnTouchListener(new View.OnTouchListener() {
        public boolean onTouch(View p_v, MotionEvent p_event) {
            childScrollView.getParent().requestDisallowInterceptTouchEvent(
                    false);
            // We will have to follow above for all scrollable contents
            return false;
        }
    });
    childScrollView.setOnTouchListener(new View.OnTouchListener() {
        public boolean onTouch(View p_v, MotionEvent p_event) {
            // this will disallow the touch request for parent scroll on
            // touch of child view
            p_v.getParent().requestDisallowInterceptTouchEvent(true);
            return false;
        }
    });
    // We will have to follow above for all child scrollable contents
似乎发生的情况是:当我在TextView中有文本时,它似乎根本不让我滚动它。 它只是滚动父级。 但是当我没有文本并触摸子ScrollView时,它不会滚动父级,所以我想那时它是有效的。 但您有任何想法为什么在我有文本时它不起作用吗?

2
我正在尝试将一个ScrollView放置在另一个ScrollView中 - 不要这样做,当你有两个不同的滚动区域时,你如何期望滚动工作呢? - user
这实际上是个不好的想法。 - i.n.e.f
移除scrollView2。你一开始为什么要放它在那里,你想要实现什么功能? - 2Dee
1
我正在为客户开发这个应用程序,他已经在IOS上实现了这个功能。问题是某些项目的描述可能太长,这种情况下我使用子滚动视图向下滚动。我看到有人这样做,所以我也想这样做。 - Mihai Boisteanu
这可能对您有所帮助 http://grishma102.blogspot.in/2014/01/handle-scrolling-of-scrollable-controls.html - Gopal Gopi
9个回答

52

你应该使用 NestedScrollView

<android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >
            <!-- -->
</android.support.v4.widget.NestedScrollView>

1
我之前有一个类似的项目,这个方法有效。谢谢! - Mihai Boisteanu
2
这是一个简单的解决方案。我仅在内部滚动视图中使用它;不需要更改外部滚动视图。 - arlomedia
顺便提一下,iOS和Android在处理嵌套滚动时有些不同。在iOS上,触摸内部滚动视图仅会滚动内部视图,而在内部滚动视图之外但在外部滚动视图之内触摸则会滚动外部视图。在使用NestedScrollView的Android上,触摸内部滚动视图将滚动内部视图,直到其在任何方向上达到滚动限制,然后开始滚动外部视图。 - arlomedia

5

虽然这是一个老问题,但我会分享一下我的解决方法。我自己也遇到过这个问题。我在XML中把ScrollView从TextView中移除,然后在Java代码中实现了TextView的滚动功能。因此,XML的代码如下:

    <TextView
        android:id="@+id/textViewDirectoryDetailName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Name"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="@color/red" />

    <LinearLayout
        android:id="@+id/linearLayoutDirectoryDetailContainImage"
        android:layout_width="300dp"
        android:layout_height="200dp"
        android:layout_gravity="center_vertical|center_horizontal"
        android:background="@drawable/general_image"
        android:gravity="center"
        android:orientation="vertical" >
    </LinearLayout>   
            <TextView
            android:id="@+id/textViewDirectoryDescription"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:autoLink="phone"
            android:text="098 123 45 678"
            android:textAppearance="?android:attr/textAppearanceLarge" />

并且 Java 代码将会是

 TextView extViewDD =  
    (TextView)findViewById(R.id.textViewDirectoryDescription);    
    //for Scrolling of textView       
    textViewDD.setMovementMethod(new ScrollingMovementMethod());
//to stop parent linearlayout scrollview when touched on textview
    textViewDD.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            v.getParent().requestDisallowInterceptTouchEvent(true);
            return false;
        }
    });

很棒的答案。简洁明了。 - AhabLives
谢谢!这是解决这个问题最简单、最干净的方法。 - Mehmet Sefa Balık

2

我使用RectF来测试您的手指是否在child_view的范围内。

我已经在一个混合了scrollview和viewpager的情况下使用它(其中包含两个具有recycleviews的页面)。

尝试这些代码,您将获得您想要的结果。

findViewById(R.id.parent_view).setOnTouchListener(new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            View childV = findViewById(R.id.child_view);
            if (childV != null) {
                int[] l = new int[2];
                childV.getLocationOnScreen(l);
                RectF rect = new RectF(l[0], l[1], l[0] + childV.getWidth(), l[1] + childV.getHeight());
                if(rect.contains(  event.getX(), event.getY())) {
                    childV.getParent()
                            .requestDisallowInterceptTouchEvent(false);
                    childV.onTouchEvent(event);
                    return true;
                }
            }
            childV.getParent()
                    .requestDisallowInterceptTouchEvent(true);
            return false;
        }
    });

2
在另一个滚动视图中放置滚动视图不是一个好的做法。然而,您使用的代码在某些情况下可能有效。但是,在有多个元素的情况下,它可能会失败。在那种情况下,它可能无法识别手势。
但是,如果有帮助,您可以尝试这个答案:ScrollView Inside ScrollView。它会在检测到子元素的触摸时禁用父滚动视图的触摸。如果有帮助,请查看这个帖子

我已经尝试了那些方法,但是日志中总是出现PARENT TOUCH而不是CHILD TOUCH。 - Mihai Boisteanu
抱歉,我无法理解您的意思。您能展示一下您尝试过什么以及遇到了什么问题吗? - Sahil Mahajan Mj
我的意思是大多数方法都是相同的。例如,我使用了这个链接中的方法:link,但当我触摸子滚动视图时,它仍然显示我已经触摸了父视图,并且根本不起作用。 - Mihai Boisteanu

0

使用此自定义滚动视图作为内部滚动视图:

public class TouchMeScrollView extends ScrollView {
public TouchMeScrollView(Context context) {
    super(context);
}

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

public TouchMeScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TouchMeScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    requestDisallowInterceptTouchEvent(true);
    return super.onTouchEvent(ev);
}
}

0

请查看this链接,其中展示了如何在同一活动中使用两个带有滚动功能的小部件。请检查下面的代码。

parentScroll.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {
                Log.v("PARENT", "PARENT TOUCH");
                findViewById(R.id.child_scroll).getParent()
                        .requestDisallowInterceptTouchEvent(false);
                return false;
            }
        });
        childScroll.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {
                Log.v("CHILD", "CHILD TOUCH");
                // Disallow the touch request for parent scroll on touch of
                // child view
                v.getParent().requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });

这实际上是与我上面的代码完全相同,除了日志之外,但我也会尝试一下,以确保百分之百正确。 - Mihai Boisteanu
完全没有反应。日志总是显示“PARENT TOUCH”,从未显示“CHILD TOUCH”,所以我猜我不能触摸子滚动视图。 - Mihai Boisteanu

0

你不能在ScrollView内部使用两个ScrollView,操作系统会混淆哪一个需要滚动,导致你的活动卡死,请不要这样使用。


0

我几乎确定这是不可能的:

Android如何处理触摸事件:

父级获取事件并决定是否处理它,或者是否应该让子级处理;

因此,如果ScrollView处理了触摸事件,则处理它的始终是父级。

http://developer.android.com/training/gestures/viewgroup.html

就我个人而言,我不知道是否有一种方法可以理解在父级滚动视图背后触摸了什么,以查看它是否是另一个滚动视图,并让其处理移动。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接