web-dev-qa-db-ja.com

ScrollView内のScrollView

Googleの人々が、スクロール可能なビューを別のスクロール可能なビューの中に入れないように要求していることを知っていますが、そうしないように指示する公式の声明はありますか?

30
66CLSjY

これで十分ですか?

ListViewが独自のスクロールを処理するため、Horizo​​ntalScrollViewをListViewで使用しないでください。最も重要なことは、これを行うと、ListViewが項目のリスト全体を表示して、Horizo​​ntalScrollViewが提供する無限コンテナをいっぱいにするため、大きなリストを処理するためのListViewのすべての重要な最適化を無効にします。

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

更新:

2次元のスクロールビューの使用を余儀なくされる可能性があるため、これを使用することを検討できます。 インターネットアーカイブof blog.gorges.us/2010/06/Android-two-dimensional-scrollview /

私はこれを使用していませんが、合理的なアプローチかもしれません。

16
Pedro Loureiro

これを試してみてください

注:ここでparentScrollViewはOuter ScrollViewを意味し、childScrollViewはInnner 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;
    }
});
62
Atul Bhardwaj

上記の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への参照は必要なく、直接の親である必要はありません...それが見つかるまで表示リストを移動します。

私の意見では、両方の長所があります。

16
zeh
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。

7
M. Usman Khan

これが解決策です。子の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;
}
3
Nicolai Nita

非常に良い解決策を見つけました。このコードを使用してください。

    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;
        }
    });

これは確実に機能します。動作していない場合は試してみてください。

2
Mitesh Shah

[...]彼らから、そうしないようにとの公式声明はありますか?

私はメモにそれを見つけることができないようですが、あると思います。リストアクティビティでスクロールビューを表示しようとしたときに、このようなステートメントを見つけたことがわかります。実際、Android UIシステムがネストされたスクロール可能オブジェクトを処理する方法に論理的なフォーカス "バグ"があると思います。

最終的には、ユーザーのために単一のスクロール可能なビューを検討することをお勧めします。これは、HTMLページのスクロールバーの中にスクロールバーがあるようなものです。それは合法かもしれませんが、ひどいユーザーエクスペリエンスです。

2
Andrew White

Androidサポートv4ライブラリには、NestedScrollViewというクラスがあります。

ネストされたスクロールビューを試す: http://ivankocijan.xyz/Android-nestedscrollview/

1
Noyloy

実際には、「 the ListView 」という非常に古いビデオに、公式の声明があります。彼らは、スクロール可能なビューを別のビュー内に配置しないように言っています(両方が同じ方向にある場合)。

ただし、今では両方のビューを同時にスクロールできる新しいビューがあり、おそらくクールな効果を示しています。

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

この例は見つかりませんでしたので、私が書いたのは、それが何をするのか、何のために使われているのかの推測にすぎません。

1

誰かがこれに対する答えを探しているなら、私はわずかに異なる実装を持っていました。 ScrollViewクラスを拡張し、子にonTouchListenerを実装し、コンストラクターでselfに設定しました。

OnTouchコールバックで、モーションイベントオブジェクトのポインターカウントの値が2の場合、trueを返し、それ以外の場合はfalseを返しました。このように、2本の指が画面上を移動している場合、ズームするピンチと見なされ、そうでなければ通常のスクロールと見なされます。親タッチの無効化などをリクエストしませんでした。

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

ここでは、ScrollView内にScrollViewに関連するサンプルプロジェクトを作成しました。 1つのビューは両方の方法でスクロール可能です。見てみな :-

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"
/>
0
Rahul Gupta

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);
    }
}
0
JackMahoney