[android] ListView가 접히지 않고 어떻게 ScrollView에 넣을 수 있습니까?

이 문제에 대한 해결책을 찾아 보았는데 찾을 수있는 유일한 대답은 ” ListView를 ScrollView에 넣지 마십시오 “입니다. 나는 왜 그런지에 대한 실제 설명을 아직 보지 못했습니다 . 내가 찾을 수있는 유일한 이유는 Google이 그렇게하고 싶지 않다고 생각하기 때문입니다. 글쎄, 그렇게 했어.

문제는 ListView를 최소 높이로 축소하지 않고 어떻게 ListView를 ScrollView에 배치 할 수 있습니까?



답변

a ListView를 사용하여 스크롤하지 않도록하려면 비용이 많이 들고 전체 목적에 위배 ListView됩니다. 당신은해야 하지 이렇게. LinearLayout대신 사용하십시오 .


답변

여기 내 해결책이 있습니다. 나는 안드로이드 플랫폼에 익숙하지 않으며, 특히 .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);
    }
}


답변

이것은 확실히 작동합니다 ……… 레이아웃 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;
    }
}


답변

퍼팅의 Insted ListView돌며 ScrollView, 우리가 사용할 수있는 ListViewA와 ScrollView. ListView안에 있어야 할 것들을 안에 넣을 수 있습니다 ListView. 의 ListView머리글과 바닥 글에 레이아웃을 추가하여 상단 및 하단의 다른 레이아웃을 넣을 수 있습니다 ListView. 따라서 전체 ListView가 스크롤의 경험을 제공합니다.


답변

ListView를 ScrollView에 포함시키는 것이 합리적 인 상황 이 많이 있습니다 .

다음은 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)을 호출하십시오.


답변

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에서 자신의 하위 클래스로 복사 한 다음 onMeasure를 통해 AT_MOST 경로를 UNSPECIFIED에 대해 실행해야합니다.

그건 그렇고, 나는 이것이 적은 수의 목록 항목으로 작업 할 때 완벽하게 유효한 접근법이라고 생각합니다. LinearLayout과 비교할 때 비효율적 일 수 있지만 항목 수가 적은 경우 LinearLayout을 사용하는 것은 불필요한 최적화이므로 불필요한 복잡성입니다.


답변

내장 설정이 있습니다. ScrollView에서 :

android:fillViewport="true"

자바에서는

mScrollView.setFillViewport(true);

Romain Guy는 여기에 자세히 설명되어 있습니다. http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/