繁体   English   中英

ScrollView Inside ScrollView

[英]ScrollView Inside ScrollView

我知道谷歌的人已经要求我们不要将Scrollable视图放在另一个Scrollable视图中,但他们是否有任何官方声明指示我们不要这样做?

试试这个吧

注意:这里parentScrollView表示外部ScrollView,而childScrollView表示childScrollView ScrollView

parentScrollView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
        Log.v(TAG, "PARENT TOUCH");

        findViewById(R.id.child_scroll).getParent()
                .requestDisallowInterceptTouchEvent(false);
        return false;
    }
});

childScrollView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
        Log.v(TAG, "CHILD TOUCH");

        // Disallow the touch request for parent scroll on touch of  child view
        v.getParent().requestDisallowInterceptTouchEvent(true);
        return false;
    }
});

Atul Bhardwaj上面的回答是正确的方法。 但是如果有人需要将它应用到你对父母的控制较少的ScrollView,我认为这足够灵活,只是它应该工作的方式:

private void makeMyScrollSmart() {
    myScroll.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View __v, MotionEvent __event) {
            if (__event.getAction() == MotionEvent.ACTION_DOWN) {
                //  Disallow the touch request for parent scroll on touch of child view
                requestDisallowParentInterceptTouchEvent(__v, true);
            } else if (__event.getAction() == MotionEvent.ACTION_UP || __event.getAction() == MotionEvent.ACTION_CANCEL) {
                // Re-allows parent events
                requestDisallowParentInterceptTouchEvent(__v, false);
            }
            return false;
        }
    });
}

private void requestDisallowParentInterceptTouchEvent(View __v, Boolean __disallowIntercept) {
    while (__v.getParent() != null && __v.getParent() instanceof View) {
        if (__v.getParent() instanceof ScrollView) {
            __v.getParent().requestDisallowInterceptTouchEvent(__disallowIntercept);
        }
        __v = (View) __v.getParent();
    }
}

该函数的作用是向myScroll添加一个触摸侦听器,当触摸在子节点中启动时禁用父触摸拦截,然后在触摸实际结束时将其恢复。 您不需要对父ScrollView的引用,它不必是直接父级...它将在显示列表中移动直到找到它。

在我看来,两全其美。

这够近了吗?

你永远不应该使用带有ListView的Horizo​​ntalScrollView,因为ListView负责自己的滚动。 最重要的是,这样做会使ListView中的所有重要优化都无法处理大型列表,因为它有效地强制ListView显示其整个项目列表以填充Horizo​​ntalScrollView提供的无限容器。

http://developer.android.com/reference/android/widget/Horizo​​ntalScrollView.html

更新:

由于您可能被迫使用二维滚动视图,您可以考虑使用此: blog.gorges.us/2010/06/android-two-dimensional-scrollview/的Internet存档

我没有用过这个,但这可能是一个合理的方法。

childScrollView.setOnTouchListener(new View.OnTouchListener() {

      @Override
    public boolean onTouch(View v, MotionEvent event) {

        int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
           // Disallow ScrollView to intercept touch events.
          v.getParent().requestDisallowInterceptTouchEvent(true);
           break;

        case MotionEvent.ACTION_UP:
            // Allow ScrollView to intercept touch events.
            v.getParent().requestDisallowInterceptTouchEvent(false);
            break;
        }

        return false;
    }
});

v.getParent()=父scrollView。

这是一个可能的解决方案。 当到达子ScrollView的末尾时,它将控件传递给父ScrollView进行滚动。 它适用于ScrollView中的ScrollView和ListView。

第1步 - 设置父OnTouchListener

parentScroll.setOnTouchListener(new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        v.getParent().requestDisallowInterceptTouchEvent(false);
        return false;
    }
});

第2步 - 设置子项的OnTouchListener(ScrollView或ListView)

aChildScrollView.setOnTouchListener(new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event)
    {
        v.getParent().requestDisallowInterceptTouchEvent(shouldRequestDisallowIntercept((ViewGroup) v, event));
        return false;
    }
});
aListView.setOnTouchListener(new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        v.getParent().requestDisallowInterceptTouchEvent(shouldRequestDisallowIntercept((ViewGroup) v, event));
        return false;
    }
});

第3步 - 这是正确功能所需的魔术方法

protected boolean shouldRequestDisallowIntercept(ViewGroup scrollView, MotionEvent event) {
    boolean disallowIntercept = true;
    float yOffset = getYOffset(event);

    if (scrollView instanceof ListView) {
        ListView listView = (ListView) scrollView;
        if (yOffset < 0 && listView.getFirstVisiblePosition() == 0 && listView.getChildAt(0).getTop() >= 0) {
            disallowIntercept = false;
        }
        else if (yOffset > 0 && listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 && listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) {
            disallowIntercept = false;
        }
    }
    else {
        float scrollY = scrollView.getScrollY();
        disallowIntercept = !((scrollY == 0 && yOffset < 0) || (scrollView.getHeight() + scrollY == scrollView.getChildAt(0).getHeight() && yOffset >= 0));

    }

    return disallowIntercept;
}

protected float getYOffset(MotionEvent ev) {
    final int historySize = ev.getHistorySize();
    final int pointerCount = ev.getPointerCount();

    if (historySize > 0 && pointerCount > 0) {
        float lastYOffset = ev.getHistoricalY(pointerCount - 1, historySize - 1);
        float currentYOffset = ev.getY(pointerCount - 1);

        float dY = lastYOffset - currentYOffset;

        return dY;
    }

    return 0;
}

我找到了一个很好的解决方案。 请使用此代码。

    parentScrollView.setOnTouchListener(new View.OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {

            Utils.showLog("PARENT TOUCH");
            findViewById(R.id.activity_mesh_child_scrollView).getParent().requestDisallowInterceptTouchEvent(false);
            return false;
        }
    });

    childScrollView.setOnTouchListener(new View.OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {

            Utils.showLog("CHILD TOUCH");
            // Disallow the touch request for parent scroll on touch of child view
            v.getParent().requestDisallowInterceptTouchEvent(true);
            return false;
        }
    });

这肯定会奏效。 如果不能正常工作,请尝试告诉我。

[......]是否有任何官方声明指示我们不要这样做?

我想虽然我似乎无法在笔记中找到它。 我知道在尝试在列表活动中使用滚动视图时,我发现了这样的声明。 我认为Android UI系统处理嵌套滚动条的方式实际上存在一个逻辑焦点“bug”,可能应该更好地检测并传达给开发人员。 但我的建议是......

最后,为了用户的利益,最好考虑单个可滚动视图。 这就像在HTML页面上的滚动条内有滚动条; 它可能是合法的,但却是一种糟糕的用户体验。

实际上,有一个关于它的官方声明,在一个名为“ ListView世界相当古老的视频中。 他们说不要将任何可滚动视图放在另一个视图中(当两者都在同一方向时)。

但是,现在我们有了一个新视图,允许两个视图同时滚动,可能显示一个很酷的效果:

https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html

我没有找到任何这方面的例子,所以我写的只是猜测它的作用和它的用途。

Android支持v4库有一个名为NestedScrollView的类。

尝试嵌套滚动视图: http//ivankocijan.xyz/android-nestedscrollview/

您可以将ScrollView放在另一个ScrollView中。 只需扩展子ScrollView以覆盖onTouchEvent方法。 像这样

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class ChildScrollView extends android.widget.ScrollView {
    private int parent_id;

    public ChildScrollView(Context context) {
        super(context);
    }

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

    public ChildScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

在这里,我在ScrollView中创建了一个与ScrollView相关的示例项目。 一种观点是可滚动的两种方式。 看看这个 :-

MainActivity.java -

package com.example.dev_task_193_scrollview;

import com.example.dev_task_196_scrollview.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.Toast;

public class MainActivity extends Activity implements View.OnClickListener{
    ImageView imageView1,imageView2,imageView3,IVimage1,IVimage2,IVimage3,IVimage4,IVimage5,IVimage6;
    ListView listView1,listView2;
    HorizontalScrollView horizontalScrollView1,horizontalScrollView2;
    ScrollView parentScrollView, scrollView1;
    RelativeLayout relativeLayout1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String[] values = new String[] { "Android", "iPhone", "WindowsMobile",
                "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X",
                "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux",
                "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
                "Android", "iPhone", "WindowsMobileWindowsMobileWindowsMobileWindowsMobile" };

        relativeLayout1 = (RelativeLayout) findViewById(R.id.relativeLayout1);
        imageView1 = (ImageView) findViewById(R.id.imageView1);
        imageView1.setBackgroundResource(R.drawable.info);

        imageView2 = (ImageView) findViewById(R.id.imageView2);
        imageView2.setBackgroundResource(R.drawable.info);

        imageView3 = (ImageView) findViewById(R.id.imageView3);
        imageView3.setBackgroundResource(R.drawable.info);

        listView1 = (ListView) findViewById(R.id.listView1);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                R.layout.list_item, values);
        listView1.setAdapter(adapter);

        listView2 = (ListView) findViewById(R.id.listView2);
        ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this,
                R.layout.list_item, values);
        listView2.setAdapter(adapter1);


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


        horizontalScrollView1 = (HorizontalScrollView) findViewById(R.id.horizontalScrollView1);
        horizontalScrollView2 = (HorizontalScrollView) findViewById(R.id.horizontalScrollView2);


        IVimage1 = (ImageView) findViewById(R.id.IVimage1);
        IVimage2 = (ImageView) findViewById(R.id.IVimage2);
        IVimage3 = (ImageView) findViewById(R.id.IVimage3);
        IVimage4 = (ImageView) findViewById(R.id.IVimage4);
        IVimage5 = (ImageView) findViewById(R.id.IVimage5);
        IVimage6 = (ImageView) findViewById(R.id.IVimage6);


        scrollView1.setOnTouchListener(new View.OnTouchListener() {

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

        horizontalScrollView1.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event)
            {
                //  Disallow the touch request for parent scroll on touch of child view
                parentScrollView.requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });
        listView1.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event)
            {
                //  Disallow the touch request for parent scroll on touch of child view
                parentScrollView.requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });
        listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Toast.makeText(getApplicationContext(), "Clicked "+parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show();

            }

        });
        listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Toast.makeText(getApplicationContext(), "Clicked "+parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show();

            }

        });

        listView2.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event)
            {
                //  Disallow the touch request for parent scroll on touch of child view
                parentScrollView.requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });
        horizontalScrollView2.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event)
            {
                //  Disallow the touch request for parent scroll on touch of child view
                parentScrollView.requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });
        /*imageView1.setOnClickListener(this);
        imageView2.setOnClickListener(this);
        imageView3.setOnClickListener(this);*/
        IVimage1.setOnClickListener(this);
        IVimage2.setOnClickListener(this);
        IVimage3.setOnClickListener(this);
        IVimage4.setOnClickListener(this);
        IVimage5.setOnClickListener(this);
        IVimage6.setOnClickListener(this);
        imageView1.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event)
            {
                //  Disallow the touch request for parent scroll on touch of child view
                parentScrollView.requestDisallowInterceptTouchEvent(true);
                Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();

                return false;
            }
        });

        imageView2.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event)
            {
                //  Disallow the touch request for parent scroll on touch of child view
                parentScrollView.requestDisallowInterceptTouchEvent(true);
                Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();

                return false;
            }
        });
        imageView3.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event)
            {
                //  Disallow the touch request for parent scroll on touch of child view
                parentScrollView.requestDisallowInterceptTouchEvent(true);
                Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();

                return false;
            }
        });

    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    @Override
    public void onClick(View v) {
        switch(v.getId()){
        case R.id.imageView1:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.imageView2:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.imageView3:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.IVimage1:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.IVimage2:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.IVimage3:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.IVimage4:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.IVimage5:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.IVimage6:
            Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show();
            break;  




        }
        // TODO Auto-generated method stub

    }
}

activity_main.xml -

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/parentScrollView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginBottom="5dp"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    android:background="@drawable/login_bg" >

    <RelativeLayout
        android:id="@+id/relativeLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <ScrollView
            android:id="@+id/scrollView1"
            android:layout_width="fill_parent"
            android:layout_height="300dp" >

            <HorizontalScrollView
                android:id="@+id/horizontalScrollView1"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                android:fillViewport="false" >

                <RelativeLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="5dp"
                    android:background="@drawable/bg" >

                    <ImageView
                        android:id="@+id/imageView1"
                        android:layout_width="300dp"
                        android:layout_height="400dp"
                        android:tag="imageView1" />

                    <ImageView
                        android:id="@+id/imageView2"
                        android:layout_width="300dp"
                        android:layout_height="400dp"
                        android:layout_toRightOf="@+id/imageView1"
                        android:tag="imageView2" />

                    <ImageView
                        android:id="@+id/imageView3"
                        android:layout_width="300dp"
                        android:layout_height="400dp"
                        android:layout_toRightOf="@+id/imageView2"
                        android:tag="imageView3" />
                </RelativeLayout>
            </HorizontalScrollView>
        </ScrollView>

        <ListView
            android:id="@+id/listView1"
            android:layout_width="500dp"
            android:layout_height="400dp"
            android:layout_below="@+id/scrollView1"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:background="@drawable/ic_launcherwrweq" >
        </ListView>

        <HorizontalScrollView
            android:id="@+id/horizontalScrollView2"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/listView1"
            android:layout_centerHorizontal="true"
            android:layout_gravity="center"
            android:layout_marginTop="5dp"
            android:background="@drawable/claim_detail_header_bg"
            android:fillViewport="true" >

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal" >

                <ImageView
                    android:id="@+id/IVimage1"
                    android:layout_width="125dp"
                    android:layout_height="125dp"
                    android:padding="15dp"
                    android:src="@drawable/a"
                    android:tag="a" >
                </ImageView>

                <ImageView
                    android:id="@+id/IVimage2"
                    android:layout_width="125dp"
                    android:layout_height="125dp"
                    android:padding="15dp"
                    android:src="@drawable/b"
                    android:tag="b" >
                </ImageView>

                <ImageView
                    android:id="@+id/IVimage3"
                    android:layout_width="125dp"
                    android:layout_height="125dp"
                    android:padding="15dp"
                    android:src="@drawable/c"
                    android:tag="c" >
                </ImageView>

                <ImageView
                    android:id="@+id/IVimage4"
                    android:layout_width="125dp"
                    android:layout_height="125dp"
                    android:padding="15dp"
                    android:src="@drawable/g"
                    android:tag="g" >
                </ImageView>

                <ImageView
                    android:id="@+id/IVimage5"
                    android:layout_width="125dp"
                    android:layout_height="125dp"
                    android:padding="15dp"
                    android:src="@drawable/e"
                    android:tag="e" >
                </ImageView>

                <ImageView
                    android:id="@+id/IVimage6"
                    android:layout_width="125dp"
                    android:layout_height="125dp"
                    android:padding="15dp"
                    android:src="@drawable/f"
                    android:tag="f" >
                </ImageView>
            </LinearLayout>
        </HorizontalScrollView>

        <ListView
            android:id="@+id/listView2"
            android:layout_width="500dp"
            android:layout_height="400dp"
            android:layout_below="@+id/horizontalScrollView2"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:background="@drawable/ic_launcherwrweq" >
        </ListView>
    </RelativeLayout>

</ScrollView>

list_item.xml(用于ListView) -

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:textSize="25sp"
    android:maxLines="1"
    android:singleLine="true"
/>

如果有人正在寻找答案,我的实现略有不同。 我扩展了ScrollView类并在子节点中实现了onTouchListener,并在构造函数中将其设置为self。

在onTouch回调中,如果运动事件对象带有指针计数值为2,则返回true,否则返回false。 这样,如果两个手指在屏幕上移动,它会将其视为缩放的缩放,否则会将其视为正常滚动。 我没有要求父母触摸禁用等。

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    if(motionEvent.getPointerCount() == 2){
        mCallbacks.onPinchZoomAction(motionEvent);
        return true;
    }
    return false;
}

不仅谷歌说它的不良做法,它只是没有多大意义。 假设您有两个嵌套在另一个内部的垂直可滚动视图。 当您将手指移动到滚动视图上时,您要移动哪一个,内部还是外部?

你应该重新考虑你的UI设计不需要这个,有很多方法可以创建一个很棒的用户界面,并且仍然保持简单。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM