[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
, 우리가 사용할 수있는 ListView
A와 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가 모든 하위를 주어진 (매우 큰) 높이까지 측정하고 그에 따라 높이를 설정합니다.
몇 가지 이유로 다른 솔루션보다 더 효과적입니다.
- 모든 것을 정확하게 측정합니다 (패딩, 분배기)
- 측정 단계 동안 ListView를 측정합니다.
- # 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/