Programming

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

procodes 2020. 3. 1. 16:05
반응형

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

ListView안에 넣는 것을 고집 ScrollView하여 ListView사용할 수 있습니다 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/


우리는 두 개의 스크롤을 동시에 사용할 수 없었습니다. 우리는 ListView의 전체 길이를 가져 와서 전체 높이로 listview를 확장합니다. 그런 다음 ScrollView에 직접 하나의 자식이 있기 때문에 ListView를 직접 추가하거나 LinearLayout을 사용하여 ListView를 추가 할 수 있습니다. 코드에 setListViewHeightBasedOnChildren (lv) 메소드를 복사하고 listview를 확장하면 scrollview 내에서 listview를 사용할 수 있습니다. \ 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>

활동 클래스의 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);
      }

스크롤 할 수없는 사용자 정의 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>

자바 파일에서

다음과 같이 ListView 대신 customListview의 객체를 만듭니다. NonScrollListView non_scroll_list = (NonScrollListView) findViewById (R.id.lv_nonscroll_list);


이것은 DougW, Good Guy Greg 및 Paul의 답변을 조합 한 것입니다. 나는 이것을 사용자 정의 listview 어댑터 및 비표준 목록 항목과 함께 사용하려고 할 때 모두 필요하다는 것을 알았습니다. 그렇지 않으면 listview가 응용 프로그램과 충돌했습니다 (Nex의 답변과 충돌 함).

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

ListView가 이미 있기 때문에 당신은있는 ScrollView에 ListView를 넣어 안 입니다 있는 ScrollView. 따라서 ScrollView를 ScrollView에 넣는 것과 같습니다.

무엇을 이루려고 노력하고 있습니까?


@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로 작업해야 할 때 빡빡했습니다. :-)


이봐 비슷한 문제가 있었다. 스크롤하지 않은 목록보기를 표시하고 싶었지만 매개 변수 조작이 효과가 있지만 비효율적이며 다른 장치에서 다르게 작동한다는 것을 알았습니다. 결과적으로 이것은 실제로 매우 효율적으로 수행하는 일정 코드의 일부입니다 .

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

            }

        });

ScrollView 내에서 ListView를 사용할 때 두 가지 문제가 있습니다.

1- ListView가 자식 높이까지 완전히 확장되어야합니다. 이 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);
    }
}

이것이 내가 트릭을 수행하는 가장 좋은 방법입니다!


내가 사용하는 해결책은 ScrollView의 모든 내용 (목록보기 위와 아래에 있어야 함)을 ListView에서 headerView 및 footerView로 추가하는 것입니다.

그래서 그것은 작동합니다, 또한 convertview는 어떻게되어야하는지에 달려 있습니다.


이것이 나를 위해 일한 유일한 것입니다.

롤리팝에서 당신은 사용할 수 있습니다

yourtListView.setNestedScrollingEnabled(true);

이전 버전의 OS와의 하위 호환성이 필요한 경우 RecyclerView를 사용해야하는 경우이보기에 대해 중첩 스크롤을 사용하거나 사용하지 않습니다.


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 안에 유지되므로 모두 스크롤 가능하게됩니다. :)


다음은 @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();
}

이것을 시도해보십시오. 이것은 저에게 효과적이며, 스택 오버플로의 어딘가에서 그것을 발견 한 곳을 잊어 버렸습니다. 왜 작동하지 않는지 설명하지 않았습니다. 그러나 이것이 답입니다 :).

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

편집!, 나는 코드를 어디서 얻었는지 마침내 알았습니다. 여기 ! : ScrollView 내의 ListView가 Android에서 스크롤되지 않습니다.


제안 된 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);

        }
    }
}
}

이 모든 답변이 잘못되었습니다 !!! 목록보기를 스크롤보기에 넣으려는 경우 디자인을 다시 생각해야합니다. ScrollView에 ScrollView를 넣으려고합니다. 목록을 방해하면 목록 성능이 저하됩니다. Android에서는 이와 같이 설계되었습니다.

목록이 다른 요소와 동일한 스크롤에있게하려면 어댑터의 간단한 switch 문을 사용하여 목록의 맨 위에 다른 항목을 추가하기 만하면됩니다.

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


}

목록 어댑터는 보이는 것만 렌더링하므로 모든 것을 처리 할 수 ​​있습니다.


불가능하기 전에. 그러나 새로운 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>

LinearLayout에 setAdapter 메소드가 있다면이 모든 문제는 사라질 것입니다. 왜냐하면 누군가에게 사용하도록 지시했을 때 대안이 사소한 것이기 때문입니다.

실제로 다른 스크롤보기 내에서 스크롤 ListView를 원한다면 도움이되지 않지만 그렇지 않으면 적어도 아이디어를 얻을 수 있습니다.

스크롤하려는 모든 컨텐츠를 결합하고 ListView의 어댑터를 해당 어댑터로 설정하려면 사용자 정의 어댑터를 작성해야합니다.

편리한 샘플 코드는 없지만 원하는 경우 원합니다.

<ListView/>

(other content)

<ListView/>

그런 다음 해당 컨텐츠를 모두 나타내는 어댑터를 작성해야합니다. ListView / Adapters는 다양한 유형을 처리 할 수있을만큼 똑똑하지만 어댑터를 직접 작성해야합니다.

안드로이드 UI API는 다른 모든 것만 큼 성숙하지 않기 때문에 다른 플랫폼과 같은 장점이 없습니다. 또한 안드로이드에서 무언가를 할 때 당신은 아마 작은 부분의 기능을 조립하고 그것을 얻기 위해 많은 코드를 작성해야 할 것으로 예상되는 안드로이드 (유닉스) 사고 방식에 있어야합니다. 작업.


우리가 ListView안에두면 ScrollView두 가지 문제가 발생합니다. 하나는 지정되지 ScrollView않은 모드에서 자녀를 측정하므로 ListView하나의 항목 (왜 그런지 모르겠습니다)을 수용하도록 자체 높이를 설정하고 다른 하나는 ScrollView터치 이벤트를 가로 채서 ListView스크롤하지 않습니다.

그러나 몇 가지 해결 방법으로 내부 배치 수 있습니다 . 이 게시물 은 해결 방법을 설명합니다. 이 해결 방법으로 의 재활용 기능 도 유지할 수 있습니다 .ListViewScrollViewListView


목록보기를 Scrollview 안에 넣는 대신 목록보기와 Scrollview 열기 사이의 나머지 내용을 별도의보기로 놓고 해당보기를 목록보기의 헤더로 설정하십시오. 따라서 마지막으로 Scroll을 담당하는 목록보기 만 끝납니다.


라이브러리는 문제에 대한 가장 쉽고 빠른 솔루션입니다.


다음은 목록보기의 총 높이를 계산하는 코드 버전입니다. 이것은 나를 위해 작동합니다 :

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

참고 URL : https://stackoverflow.com/questions/3495890/how-can-i-put-a-listview-into-a-scrollview-without-it-collapsing



반응형