ListViewを折りたたまずにScrollViewに入れるにはどうすればよいですか?


351

私はこの問題の解決策を探して回りましたが、私が見つけることができる唯一の答えは「ListViewをScrollViewに入れないでください」のようです。その理由については、まだ本当の説明はありません。私が見つけたように見える唯一の理由は、Googleがあなたがそれをしたいのではないかと思っていないことです。ええと、そうです。

では、問題は、ListViewを最小の高さに折りたたむことなく、どのようにしてScrollViewに配置できるかということです。


11
デバイスがタッチスクリーンを使用する場合、ネストされた2つのスクロール可能なコンテナーを区別する良い方法がないためです。スクロールバーを使用してコンテナーをスクロールする従来のデスクトップで機能します。
Romain Guy

57
確かにあります。それらが内側のものに触れたら、それをスクロールします。内側が大きすぎると、UIのデザインが悪くなります。それはそれが一般的に悪い考えだということではありません。
DougW 2010

5
私のタブレットアプリの場合、これに遭遇しました。スマートフォンではそれほど悪くはないように見えますが、ユーザーが外側または内側のScrollViewをスクロールするかどうかを簡単に決定できるタブレットでは、これは恐ろしいことです。@DougW:恐ろしいデザインだと思います。
クラゲ

4
@Romain-これはかなり古い投稿なので、ここでの懸念はすでに対処されているのか、それともScrollView内でListViewを使用する良い方法がないのか(または手動でコーディングする必要のない別の方法) ListViewのすべてのnicitiesをLinearLayoutに)?
ジム、

3
@ジム:「または、ListViewのすべての素晴らしさをLinearLayoutに手動でコーディングする必要のない代替手段」-すべてを内に配置しListViewます。ListView複数の行スタイルと、選択できない行を含めることができます。
CommonsWare 2013

回答:


196

ListViewスクロールしないようにするためにa を使用すると、非常に費用がかかり、の目的全体に反しListViewます。これを行うべきではありませんLinearLayout代わりにを使用してください。


69
私は過去2〜3年間ListViewを担当してきたので、ソースは私でしょう:) ListViewは、アダプターの使用を最適化するために多くの追加作業を行います。それを回避しようとすると、ListViewはLinearLayoutが行う必要のない多くの作業を実行します。ListViewの実装を説明する十分な余地がないので、詳細には触れません。これは、タッチイベントに関するListViewの動作も解決しません。また、ハッキングが今日機能する場合でも、将来のリリースでも機能するという保証はありません。LinearLayoutを使用しても、それほど多くの作業は必要ありません。
Romain Guy

7
まあそれは合理的な応答です。いくつかのフィードバックを共有できれば、iPhoneの体験がはるかに大きくなり、パフォーマンスの特性とこのような使用例(またはアンチパターン)に関しては、Appleのドキュメントの方がはるかに優れていることがわかります。全体として、Androidのドキュメントははるかに分散されており、焦点が絞られていません。その背景にはいくつかの理由があることは理解していますが、それは長い議論です。
DougW 2010

6
アダプタからLinearLayoutを作成する静的メソッドを簡単に作成できます。
Romain Guy

125
これは答えではありませんHow can I put a ListView into a ScrollView without it collapsing?...あなたはそれをすべきではないと言うことができますが、それを行う方法についても答えを出すことができます。それは良い答えです。ListViewには、スクロール以外に、LinearLayoutにはない機能がいくつかあります。
ホルヘフエンテスゴンサレス2013年

44
ListView +他のビューを含む領域があり、すべてを1つのスクロールとしてスクロールしたい場合はどうでしょうか?これは、ListViewをScrollView内に配置するための合理的なユースケースのようです。ListViewをLinearLayoutで置き換えることは、アダプタを使用できないため、解決策ではありません。
バリーフルーツマン2013

262

これが私の解決策です。私はAndroidプラットフォームにかなり慣れていないので、特に.measureを直接呼び出してLayoutParams.heightプロパティを直接設定する部分では、これは少しハックだと確信していますが、動作します。

あなたがしなければならないすべては電話でUtility.setListViewHeightBasedOnChildren(yourListView)あり、それはそのアイテムの高さに正確に対応するようにサイズ変更されます。

public class Utility {
    public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();

        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            if (listItem instanceof ViewGroup) {
                listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
             }

             listItem.measure(0, 0);
             totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
    }
}

66
非常に高価なLinearLayoutを再作成しました:)
Romain Guy

82
を除いて、aにLinearLayoutはaに本来備わっているすべての機能はありません。ディバイダーListView、ヘッダー/フッタービュー、電話のUIテーマの色に一致するリストセレクターなどはありません。正直なところ、スクロールできない理由はありません。内側のコンテナーが最後に到達するまで、その後、外側のコンテナーがスクロールするようにタッチイベントのインターセプトを停止します。スクロールホイールを使用している場合、すべてのデスクトップブラウザーがこれを行います。Android自体は、トラックボールを介してナビゲートしている場合、ネストされたスクロールを処理できます。
Neil Traft 2010

29
listItem.measure(0,0)listItemがViewGroupインスタンスの場合、NPEをスローします。私は前に以下を追加しましたlistItem.measureif (listItem instanceof ViewGroup) listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
Siklab.ph

4
0以外のパディングを含むリストビューの修正:int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
Paul

8
残念ながら、ListView高さが可変のアイテムをに含めることができる場合、この方法には少し欠陥があります。への呼び出しgetMeasuredHeight()は、実際の高さではなく、対象となる最小の高さのみを返します。getHeight()代わりに使用してみましたが、これは0を返します。これに対処する方法について誰か洞察がありますか?
Matt Huggins 2013年

89

これは間違いなく動作します............レイアウトXMLファイルを次のように
置き換える必要があります<ScrollView ></ScrollView>Custom ScrollView<com.tmd.utils.VerticalScrollview > </com.tmd.utils.VerticalScrollview >

package com.tmd.utils;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;

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:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" );
                    super.onTouchEvent(ev);
                    break;

            case MotionEvent.ACTION_MOVE:
                    return false; // redirect MotionEvents to ourself

            case MotionEvent.ACTION_CANCEL:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" );
                    super.onTouchEvent(ev);
                    break;

            case MotionEvent.ACTION_UP:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" );
                    return false;

            default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break;
        }

        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        super.onTouchEvent(ev);
        Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
         return true;
    }
}

4
これはとてもいい。また、GoogleマップのフラグメントをScrollView内に配置することも可能で、ズームイン/ズームアウトでも機能します。ありがとう。
Magnus Johansson

このアプローチの短所に気づいた人はいますか?その非常に単純な私は恐れています:o
Marija Milosevic 14年

1
良い解決策、受け入れられる答え+1である必要があります!私はそれを(djunodからの)以下の答えと混ぜました、そしてそれは素晴らしい働きです!
tanou 2014

1
これは私のために同時に働いている子供たちをスクロールしてクリックする唯一の修正です。大きな感謝
pellyadolfo 2016

25

ListView内に置くScrollViewことを目的ListViewとして、として使用できますScrollView。中になければならないものをのListView中に入れることができますListView。のListViewヘッダーとフッターにレイアウトを追加することで、の上部と下部の他のレイアウトを配置できますListView。したがって、全体ListViewがスクロールのエクスペリエンスを提供します。


3
これは最もエレガントで適切な答えです。このアプローチの詳細については、この回答を参照してください:stackoverflow.com/a/20475821/1221537
adamdport

21

ScrollViewにListViewを配置することが理にかなっている状況はたくさんあります。

以下は、DougWの提案に基づくコードです。フラグメントで機能し、メモリ使用量が少なくなります。

public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null) {
        return;
    }
    int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
    int totalHeight = 0;
    View view = null;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        view = listAdapter.getView(i, view, listView);
        if (i == 0) {
            view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT));
        }
        view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
        totalHeight += view.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
    listView.requestLayout();
}

埋め込まれた各リストビューでsetListViewHeightBasedOnChildren(listview)を呼び出します。


リスト項目が可変サイズの場合、つまり複数行にまたがるテキストビューの場合は機能しません。解決策はありますか?
コバイブ2014

ここに私のコメントをチェックしてください-それは完璧なソリューションを提供します- stackoverflow.com/a/23315696/1433187
Khobaib

API 19では機能しましたが、API 23では機能しませんでした。ここでは、listViewの下に多くの空白が追加されています。
Lucker10

17

ListViewは実際には、すべてのアイテムを表示するのに十分な高さになるようにそれ自体を測定することができますが、単にwrap_content(MeasureSpec.UNSPECIFIED)を指定しただけでは測定できません。MeasureSpec.AT_MOSTで高さを指定すると、これが行われます。この知識があれば、非常に単純なサブクラスを作成してこの問題を解決できます。この問題は、上記のどのソリューションよりもはるかにうまく機能します。このサブクラスでは引き続きwrap_contentを使用する必要があります。

public class ListViewForEmbeddingInScrollView extends ListView {
    public ListViewForEmbeddingInScrollView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
    }
}

heightMeasureSpecを非常に大きなサイズ(Integer.MAX_VALUE >> 4)でAT_MOSTに操作すると、ListViewは指定された(非常に大きな)高さまでのすべての子を測定し、それに応じて高さを設定します。

これは、いくつかの理由で他のソリューションよりもうまく機能します。

  1. すべてを正しく測定します(パディング、ディバイダー)
  2. メジャーパス中にListViewを測定します
  3. #2により、追加のコードなしで、アイテムの幅または数の変更を正しく処理します

マイナス面としては、これを行うことは、SDKの文書化されていない動作に依存しているため、変更される可能性があるということです。一方、これがwrap_contentが実際にListViewで機能する方法であり、現在のwrap_contentの動作が壊れていると主張することもできます。

将来的に動作が変更される可能性がある場合は、onMeasure関数と関連する関数をListView.javaから独自のサブクラスにコピーしてから、UNSPECIFIEDのonMeasure実行を介してAT_MOSTパスを作成する必要があります。

ちなみに、これは、少数のリストアイテムで作業している場合、完全に有効なアプローチだと思います。LinearLayoutと比較すると効率が悪くなる可能性がありますが、項目数が少ない場合、LinearLayoutを使用することは不必要な最適化であり、したがって不必要な複雑さになります。


リストビューの可変高さのアイテムでも機能します!
デニー

@ジェイソンYこれは何を意味しますか、Integer.MAX_VALUE >> 4は?? 4は何ですか?
KJEjava48

@Jason Yは、Integer.MAX_VALUE >> 2をInteger.MAX_VALUE >> 21に変更した後にのみ機能しました。なぜそうなのか?また、NestedScrollViewではなくScrollViewでも機能します。
KJEjava48

13

組み込みの設定があります。ScrollViewで:

android:fillViewport="true"

Javaでは、

mScrollView.setFillViewport(true);

Romain Guyはここでそれを詳しく説明しています:http : //www.curious-creature.org/2010/08/15/scrollviews-handy-trick/


2
彼が示すように、これはLinearLayoutで機能します。ListViewでは機能しません。その投稿の日付に基づいて、彼が彼の代替案の例を提供するためにそれを書いたと思いますが、これは質問の答えにはなりません。
DougW 2014

これは高速なソリューションです

10

スクロールできないカスタムListViewを作成する

public class NonScrollListView extends ListView {

    public NonScrollListView(Context context) {
        super(context);
    }
    public NonScrollListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                    Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();    
    }
}

レイアウトリソースファイル

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <!-- com.Example Changed with your Package name -->

    <com.Example.NonScrollListView
        android:id="@+id/lv_nonscroll_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </com.Example.NonScrollListView>

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

        <!-- Your another layout in scroll view -->

    </RelativeLayout>
</RelativeLayout>

Javaファイル

次のように、ListViewではなくcustomListviewのオブジェクトを作成します。NonScrollListView non_scroll_list =(NonScrollListView)findViewById(R.id.lv_nonscroll_list);


8

2つのスクロールを同時に使用することはできませんでした。ListViewの全長を取得し、リストビューを合計の高さで展開します。次に、ScrollViewに直接またはLinearLayoutを使用してListViewを追加できます。コードにsetListViewHeightBasedOnChildren(lv)メソッドをコピーしてリストビューを展開すると、スクロールビュー内でリストビューを使用できます。\ layout 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="match_parent"
android:orientation="vertical" >
 <ScrollView

        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
         android:background="#1D1D1D"
        android:orientation="vertical"
        android:scrollbars="none" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#1D1D1D"
            android:orientation="vertical" >

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="40dip"
                android:background="#333"
                android:gravity="center_vertical"
                android:paddingLeft="8dip"
                android:text="First ListView"
                android:textColor="#C7C7C7"
                android:textSize="20sp" />

            <ListView
                android:id="@+id/first_listview"
                android:layout_width="260dp"
                android:layout_height="wrap_content"
                android:divider="#00000000"
               android:listSelector="#ff0000"
                android:scrollbars="none" />

               <TextView
                android:layout_width="fill_parent"
                android:layout_height="40dip"
                android:background="#333"
                android:gravity="center_vertical"
                android:paddingLeft="8dip"
                android:text="Second ListView"
                android:textColor="#C7C7C7"
                android:textSize="20sp" />

            <ListView
                android:id="@+id/secondList"
                android:layout_width="260dp"
                android:layout_height="wrap_content"
                android:divider="#00000000"
                android:listSelector="#ffcc00"
                android:scrollbars="none" />
  </LinearLayout>
  </ScrollView>

   </LinearLayout>

ActivityクラスのonCreateメソッド:

 import java.util.ArrayList;
  import android.app.Activity;
 import android.os.Bundle;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
  import android.widget.ListView;

   public class MainActivity extends Activity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.listview_inside_scrollview);
    ListView list_first=(ListView) findViewById(R.id.first_listview);
    ListView list_second=(ListView) findViewById(R.id.secondList);
    ArrayList<String> list=new ArrayList<String>();
    for(int x=0;x<30;x++)
    {
        list.add("Item "+x);
    }

       ArrayAdapter<String> adapter=new ArrayAdapter<String>(getApplicationContext(), 
          android.R.layout.simple_list_item_1,list);               
      list_first.setAdapter(adapter);

     setListViewHeightBasedOnChildren(list_first);

      list_second.setAdapter(adapter);

    setListViewHeightBasedOnChildren(list_second);
   }



   public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null) {
        // pre-condition
        return;
    }

    int totalHeight = 0;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        View listItem = listAdapter.getView(i, null, listView);
        listItem.measure(0, 0);
        totalHeight += listItem.getMeasuredHeight();
    }

    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight
            + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
      }

良い修正です!必要に応じて機能します。ありがとう。私の場合、リストの前にたくさんのビューがあり、ビューの垂直スクロールを1つだけにするのが完璧な解決策です。
Proverbio 14

4

これは、DougW、Good Guy Greg、およびPaulの回答を組み合わせたものです。これをカスタムリストビューアダプターと非標準のリストアイテムで使用しようとすると、すべてが必要であることがわかりました。

public void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            return;
        }

        int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            if (listItem instanceof ViewGroup)
                listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
    }

このメソッドを呼び出す場所は?
Dhrupal 14

リストビューを作成してアダプタを設定した後。
放棄されたカート

これは、長いリストでは遅くなります。
cakan

@cakanまた、2年前に、実際には組み合わせることが意図されていない特定のUIコンポーネントを一緒に使用できるようにするための回避策として書かれました。最新のAndroidでは不要なオーバーヘッドが追加されるため、リストが大きくなるとリストの速度が低下することが予想されます。
放棄されたカート

3

リストビューがすでにので、あなたはScrollViewにListViewコントロールを置くべきではないです ScrollView。つまり、ScrollViewにScrollViewを配置するようなものです。

あなたは何を成し遂げようとしているのですか?


4
ScrollView内にListViewを配置しようとしています。ListViewをスクロール可能にしたくないのですが、myListView.scrollEnabled = falseを設定する単純なプロパティはありません。
DougW 2010

Romain Guyが言ったように、これはListViewの目的ではありません。ListViewは、アイテムの長いリストを表示するために最適化されたビューであり、ビューの遅延読み込みやビューの再利用などを行う複雑なロジックがたくさんあります。ListViewにスクロールしないように指示している場合、これは意味がありません。垂直列に多数のアイテムが必要な場合は、LinearLayoutを使用します。
シェリルサイモン

9
問題は、あなたが言及したものを含めて、ListViewが提供する多くのソリューションがあることです。アダプターが簡素化する機能の多くは、UIの最適化ではなく、データの管理と制御に関するものです。IMOには、単純なListViewと、すべてのリストアイテムの再利用やその他の処理を行うより複雑なものが必要です。
DougW 2010

2
絶対に同意しました。LinearLayoutで既存のアダプターを使用するのは簡単ですが、ListViewが提供するすべての優れた機能(ディバイダーなど)が必要であり、手動で実装する必要はないことに注意してください。
Artem Russakovskii

1
@ArtemRussakovskii ListViewをLinearLayoutに既存のアダプターで置き換える簡単な方法を説明していただけますか?
happyhardik 2012

3

@DougW UtilityをC#に変換しました(Xamarinで使用)。以下は、リスト内の固定高さの項目で正常に機能し、一部の項目のみが標準項目より少し大きい場合は、ほとんど問題なく、または少なくとも適切な開始となります。

// You will need to put this Utility class into a code file including various
// libraries, I found that I needed at least System, Linq, Android.Views and 
// Android.Widget.
using System;
using System.Linq;
using Android.Views;
using Android.Widget;

namespace UtilityNamespace  // whatever you like, obviously!
{
    public class Utility
    {
        public static void setListViewHeightBasedOnChildren (ListView listView)
        {
            if (listView.Adapter == null) {
                // pre-condition
                return;
            }

            int totalHeight = listView.PaddingTop + listView.PaddingBottom;
            for (int i = 0; i < listView.Count; i++) {
                View listItem = listView.Adapter.GetView (i, null, listView);
                if (listItem.GetType () == typeof(ViewGroup)) {
                    listItem.LayoutParameters = new LinearLayout.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
                }
                listItem.Measure (0, 0);
                totalHeight += listItem.MeasuredHeight;
            }

            listView.LayoutParameters.Height = totalHeight + (listView.DividerHeight * (listView.Count - 1));
        }
    }
}

@DougWに感謝します。これにより、OtherPeople'sCodeを使用する必要があったときに、窮地から脱出した。:-)


1つの質問:いつsetListViewHeightBasedOnChildren()メソッドを呼び出しましたか?それは私にとっていつもうまくいくわけではないからです。
アレクサンドルD. 14

@AlexandreDは、アイテムのリストを作成したときにUtility.setListViewHeightBasedOnChildren(yourListView)を呼び出します。つまり、最初にリストを作成したことを確認してください!リストを作成していることがわかり、Console.WriteLineにアイテムを表示していましたが、どういうわけか、アイテムのスコープが間違っていました。私がそれを理解し、自分のリストに適切な範囲があることを確認したら、これは魅力のように機能しました。
Phil Ryan

実際のところ、私のリストはViewModelで作成されています。Utility.setListViewHeightBasedOnChildren(yourListView)を呼び出す前に、ビューにリストが作成されるのをどのように待つことができますか?
アレクサンドルD.

3

これは私のために働いた唯一のものです:

Lollipop以降では使用できます

yourtListView.setNestedScrollingEnabled(true);

これにより、RecyclerViewを使用する必要がある古いバージョンのOSとの下位互換性が必要な場合に、このビューのネストされたスクロールを有効または無効にします。


これは、AppCompatアクティビティのDialogFragmentにあるAPI 22のリストビューに影響を与えませんでした。彼らはまだ崩壊しています。@Phil Ryanの回答は、少し変更して機能しました。
ハカンCelikのMK1

3

以前は不可能でした。しかし、新しいAppcompatライブラリとデザインライブラリのリリースにより、これを実現できます。

NestedScrollView https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.htmlを使用するだけです

Listviewで動作するかどうかはわかりませんが、RecyclerViewで動作します。

コードスニペット:

<android.support.v4.widget.NestedScrollView 
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

</android.support.v4.widget.NestedScrollView>

いいですね、試していないので、内部のListViewが折りたたまれていないことは確認できませんが、それが意図されているように見えます。非難ログで
ロマンガイ

1
これは、recyclerViewでは機能しますが、listViewでは機能しません。Thanx
IgniteCoders 2017年

2

ちょっと私は同様の問題がありました。スクロールしないリストビューを表示したいのですが、パラメーターの操作は機能しましたが効率が悪く、デバイスによって動作が異なることがわかりました。その結果、これは実際に非常に効率的に実行する私のスケジュールコードの一部です。 。

db = new dbhelper(this);

 cursor = db.dbCursor();
int count = cursor.getCount();
if (count > 0)
{    
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layoutId);
startManagingCursor(YOUR_CURSOR);

YOUR_ADAPTER(**or SimpleCursorAdapter **) adapter = new YOUR_ADAPTER(this,
    R.layout.itemLayout, cursor, arrayOrWhatever, R.id.textViewId,
    this.getApplication());

int i;
for (i = 0; i < count; i++){
  View listItem = adapter.getView(i,null,null);
  linearLayout.addView(listItem);
   }
}

注:これを使用notifyDataSetChanged();すると、ビューが再描画されないため、意図したとおりに動作しません。回避策が必要な場合は、これを行ってください

adapter.registerDataSetObserver(new DataSetObserver() {

            @Override
            public void onChanged() {
                super.onChanged();
                removeAndRedrawViews();

            }

        });

2

ScrollView内でListViewを使用する場合、2つの問題があります。

1- ListViewは、その子の高さに完全に拡張する必要があります。このリストビューはこれを解決します:

public class ListViewExpanded extends ListView
{
    public ListViewExpanded(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        setDividerHeight(0);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST));
    }
}

仕切りの高さは0でなければなりません。代わりに行のパディングを使用してください。

2- ListViewはタッチイベントを消費するため、通常どおりScrollViewをスクロールできません。このScrollViewはこの問題を解決します。

public class ScrollViewInterceptor extends ScrollView
{
    float startY;

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e)
    {
        onTouchEvent(e);
        if (e.getAction() == MotionEvent.ACTION_DOWN) startY = e.getY();
        return (e.getAction() == MotionEvent.ACTION_MOVE) && (Math.abs(startY - e.getY()) > 50);
    }
}

これは私がトリックを行うために見つけた最良の方法です!


2

私が使用する解決策は、ScrollViewのすべてのコンテンツ(listViewの上と下にあるもの)を、HeadViewとFooterViewとしてListViewに追加することです。

つまり、convertviewも同様に機能します。


1

Vinayのコードのおかげで、ここにスクロールビュー内にリストビューを置くことができないが、そのようなものが必要な場合の私のコードがあります

LayoutInflater li = LayoutInflater.from(this);

                RelativeLayout parent = (RelativeLayout) this.findViewById(R.id.relativeLayoutCliente);

                int recent = 0;

                for(Contatto contatto : contatti)
                {
                    View inflated_layout = li.inflate(R.layout.header_listview_contatti, layout, false);


                    inflated_layout.setId(contatto.getId());
                    ((TextView)inflated_layout.findViewById(R.id.textViewDescrizione)).setText(contatto.getDescrizione());
                    ((TextView)inflated_layout.findViewById(R.id.textViewIndirizzo)).setText(contatto.getIndirizzo());
                    ((TextView)inflated_layout.findViewById(R.id.textViewTelefono)).setText(contatto.getTelefono());
                    ((TextView)inflated_layout.findViewById(R.id.textViewMobile)).setText(contatto.getMobile());
                    ((TextView)inflated_layout.findViewById(R.id.textViewFax)).setText(contatto.getFax());
                    ((TextView)inflated_layout.findViewById(R.id.textViewEmail)).setText(contatto.getEmail());



                    RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);

                    if (recent == 0)
                    {
                        relativeParams.addRule(RelativeLayout.BELOW, R.id.headerListViewContatti);
                    }
                    else
                    {
                        relativeParams.addRule(RelativeLayout.BELOW, recent);
                    }
                    recent = inflated_layout.getId();

                    inflated_layout.setLayoutParams(relativeParams);
                    //inflated_layout.setLayoutParams( new RelativeLayout.LayoutParams(source));

                    parent.addView(inflated_layout);
                }

relativeLayoutはScrollView内に留まるため、すべてスクロール可能になります:)


1

@djunod答えを少し変更して、完全に機能させる必要があります。

public static void setListViewHeightBasedOnChildren(ListView listView)
{
    ListAdapter listAdapter = listView.getAdapter();
    if(listAdapter == null) return;
    if(listAdapter.getCount() <= 1) return;

    int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
    int totalHeight = 0;
    View view = null;
    for(int i = 0; i < listAdapter.getCount(); i++)
    {
        view = listAdapter.getView(i, view, listView);
        view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
        totalHeight += view.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
    listView.requestLayout();
}

:こんにちは。回答はほとんどの場合機能しますが、リストビューにヘッダービューとフットビューがある場合は機能しません。確認してもらえますか?
hguser 2013年

リストアイテムのサイズが可変である場合の解決策、つまり複数行にまたがるいくつかのテキストビューが必要です。なにか提案を?
コバイブ2014

1

これを試してください、これは私にとってはうまくいきます、私はそれを見つけた場所を忘れてしまいました、スタックオーバーフローのどこかで、私はここでそれがうまくいかない理由を説明していませんが、これが答えです:)

    final ListView AturIsiPulsaDataIsiPulsa = (ListView) findViewById(R.id.listAturIsiPulsaDataIsiPulsa);
    AturIsiPulsaDataIsiPulsa.setOnTouchListener(new ListView.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;
            }

            // Handle ListView touch events.
            v.onTouchEvent(event);
            return true;
        }
    });
    AturIsiPulsaDataIsiPulsa.setClickable(true);
    AturIsiPulsaDataIsiPulsa.setAdapter(AturIsiPulsaDataIsiPulsaAdapter);

編集!、私は最終的にどこでコードを入手したかを見つけました。ここに !:AndroidでScrollView内のListViewがスクロールしない


これは、スクロールビューの相互作用が失われないようにする方法をカバーしていますが、問題はリストビューの高さを維持することでした。
放棄されたカート

1

提案されたsetListViewHeightBasedOnChildren()メソッドはほとんどの場合に機能しますが、場合によっては、特に多くのアイテムを処理する場合でも、最後の要素が表示されないことに気付きました。そこで、アダプタコードを再利用するために、ListView動作の単純なバージョンを模倣することにしました。ここでは、ListViewの代替案を示します。

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListAdapter;

public class StretchedListView extends LinearLayout {

private final DataSetObserver dataSetObserver;
private ListAdapter adapter;
private OnItemClickListener onItemClickListener;

public StretchedListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setOrientation(LinearLayout.VERTICAL);
    this.dataSetObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            syncDataFromAdapter();
            super.onChanged();
        }

        @Override
        public void onInvalidated() {
            syncDataFromAdapter();
            super.onInvalidated();
        }
    };
}

public void setAdapter(ListAdapter adapter) {
    ensureDataSetObserverIsUnregistered();

    this.adapter = adapter;
    if (this.adapter != null) {
        this.adapter.registerDataSetObserver(dataSetObserver);
    }
    syncDataFromAdapter();
}

protected void ensureDataSetObserverIsUnregistered() {
    if (this.adapter != null) {
        this.adapter.unregisterDataSetObserver(dataSetObserver);
    }
}

public Object getItemAtPosition(int position) {
    return adapter != null ? adapter.getItem(position) : null;
}

public void setSelection(int i) {
    getChildAt(i).setSelected(true);
}

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
    this.onItemClickListener = onItemClickListener;
}

public ListAdapter getAdapter() {
    return adapter;
}

public int getCount() {
    return adapter != null ? adapter.getCount() : 0;
}

private void syncDataFromAdapter() {
    removeAllViews();
    if (adapter != null) {
        int count = adapter.getCount();
        for (int i = 0; i < count; i++) {
            View view = adapter.getView(i, null, this);
            boolean enabled = adapter.isEnabled(i);
            if (enabled) {
                final int position = i;
                final long id = adapter.getItemId(position);
                view.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        if (onItemClickListener != null) {
                            onItemClickListener.onItemClick(null, v, position, id);
                        }
                    }
                });
            }
            addView(view);

        }
    }
}
}

1

これらの答えはすべて間違っています!!! リストビューをスクロールビューに配置しようとしている場合は、デザインを再考する必要があります。ScrollViewにScrollViewを配置しようとしています。リストに干渉すると、リストのパフォーマンスが低下します。Androidでこうなるように設計されました。

リストを他の要素と同じスクロールにしたい場合は、アダプターで簡単なスイッチステートメントを使用して、リストの先頭に他の項目を追加するだけです。

class MyAdapter extends ArrayAdapter{

    public MyAdapter(Context context, int resource, List objects) {
        super(context, resource, objects);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
         ViewItem viewType = getItem(position);

        switch(viewType.type){
            case TEXTVIEW:
                convertView = layouteInflater.inflate(R.layout.textView1, parent, false);

                break;
            case LISTITEM:
                convertView = layouteInflater.inflate(R.layout.listItem, parent, false);

                break;            }


        return convertView;
    }


}

リストアダプターは、表示されているもののみをレンダリングするため、すべてを処理できます。


0

この問題全体は、LinearLayoutにsetAdapterメソッドがある場合は解消されます。そのため、誰かに代わりに使用するように指示すると、代替方法は簡単になります。

実際に別のスクロールビュー内でスクロールListViewが必要な場合、これは役に立ちませんが、それ以外の場合は、少なくともアイデアが得られます。

スクロールするすべてのコンテンツを組み合わせるカスタムアダプターを作成し、ListViewのアダプターをそれに設定する必要があります。

便利なサンプルコードはありませんが、必要に応じて。

<ListView/>

(other content)

<ListView/>

次に、そのすべてのコンテンツを表すアダプターを作成する必要があります。ListView / Adaptersは、さまざまなタイプを処理するのにも十分スマートですが、アダプタを自分で作成する必要があります。

Android UI APIは、他のほとんどすべてのものほど成熟していないため、他のプラットフォームと同じように優れているわけではありません。また、androidで何かをするときは、android(unix)の考え方で、小さなパーツの機能を組み立て、独自のコードの束を書いてそれを実現する必要があると思われることを期待する必要があります。作業。


0

我々が配置するとListView内部でScrollView二つの問題が生じます。1つはScrollViewUNSPECIFIEDモードでその子を測定ListViewするため、1つのアイテムのみに対応するように独自の高さを設定します(理由はわかりません)。もう1つはScrollViewタッチイベントをインターセプトするためListView、スクロールしません。

しかし、いくつかの回避策で内部に配置できます。この投稿では、回避策について説明しています。この回避策により、のリサイクル機能も保持できます。ListViewScrollViewListView


0

Scrollview内にリストビューを配置する代わりに、リストビューとScrollviewを開く間に残りのコンテンツを別のビューとして配置し、そのビューをリストビューのヘッダーとして設定します。したがって、最終的にはScrollを担当するリストビューのみになります。



-1

これは、リストビューの全体の高さを計算するコードの私のバージョンです。これは私のために働きます:

   public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null || listAdapter.getCount() < 2) {
        // pre-condition
        return;
    }

    int totalHeight = 0;
    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(BCTDApp.getDisplaySize().width, View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

    for (int i = 0; i < listAdapter.getCount(); i++) {
        View listItem = listAdapter.getView(i, null, listView);
        if (listItem instanceof ViewGroup) listItem.setLayoutParams(lp);
        listItem.measure(widthMeasureSpec, heightMeasureSpec);
        totalHeight += listItem.getMeasuredHeight();
    }

    totalHeight += listView.getPaddingTop() + listView.getPaddingBottom();
    totalHeight += (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight;
    listView.setLayoutParams(params);
    listView.requestLayout();
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.