android: listview in listview

前端 未结 5 1305
栀梦
栀梦 2020-11-28 06:31

i\'m trying to place a listview inside a listviewitem. the inner listview should not be scrollable but take all size it needs to display all it\'s rows. is there a better wa

相关标签:
5条回答
  • 2020-11-28 07:01

    I tried making this exact structure (a ListView inside of a ListView) and had the same problem of it only showing the first item of the inner ListView. I fixed it by changing the layout_height of the inner list from match_parent to a set dp.

    It seemed to work exactly as I wanted it to.

    0 讨论(0)
  • 2020-11-28 07:04

    Maybe somebody will find my solution useful. It is based on @ChrLipp answer and uses LinearLayout.

    public class NotScrollableListView extends LinearLayout {
    
    private ListAdapter adapter;
    private DataChangeObserver dataChangeObserver;
    private Drawable divider;
    private int dividerHeight;
    
    private List<View> reusableViews = new ArrayList<>();
    
    public NotScrollableListView(Context context) {
        super(context);
    }
    
    public NotScrollableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    
        setAttributes(attrs);
    }
    
    public NotScrollableListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    
        setAttributes(attrs);
    }
    
    public ListAdapter getAdapter() {
        return adapter;
    }
    
    public void setAdapter(ListAdapter adapter) {
        if (this.adapter != null && dataChangeObserver != null) {
            this.adapter.unregisterDataSetObserver(dataChangeObserver);
        }
    
        this.adapter = adapter;
    }
    
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    
        if (adapter != null) {
            dataChangeObserver = new DataChangeObserver();
            adapter.registerDataSetObserver(dataChangeObserver);
    
            fillContents();
        }
    }
    
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    
        if (adapter != null) {
            adapter.unregisterDataSetObserver(dataChangeObserver);
            dataChangeObserver = null;
        }
    }
    
    private void fillContents() {
    
        // clearing contents
        this.removeAllViews();
    
        final int count = adapter.getCount();   // item count
        final int reusableCount = reusableViews.size(); // count of cached reusable views
    
        // calculating of divider properties
        ViewGroup.LayoutParams dividerLayoutParams = null;
        if (divider != null && dividerHeight > 0) {
            dividerLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dividerHeight);
        }
    
        // adding items
        for (int i = 0; i < count; i++) {
            // adding item
            View converView = null;
            if (i < reusableCount) {    // we have cached view
                converView = reusableViews.get(i);
            }
            View view = adapter.getView(i, converView, this);
    
            if (i >= reusableCount) {   // caching view
                reusableViews.add(view);
            }
    
            addView(view);
    
            // adding divider
            if (divider != null && dividerHeight > 0) {
                if (i < count - 1) {
                    ImageView dividerView = new ImageView(getContext());
                    dividerView.setImageDrawable(divider);
                    dividerView.setLayoutParams(dividerLayoutParams);
                    addView(dividerView);
                }
            }
        }
    }
    
    private void setAttributes(AttributeSet attributes) {
        int[] dividerAttrs = new int[]{android.R.attr.divider, android.R.attr.dividerHeight};
    
        TypedArray a = getContext().obtainStyledAttributes(attributes, dividerAttrs);
        try {
            divider = a.getDrawable(0);
            dividerHeight = a.getDimensionPixelSize(1, 0);
        } finally {
            a.recycle();
        }
    
        setOrientation(VERTICAL);
    }
    
    private class DataChangeObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
    
            fillContents();
        }
    
        @Override
        public void onInvalidated() {
            super.onInvalidated();
    
            fillContents();
        }
    }
        }
    
        <com.sample.ui.view.NotScrollableListView
        android:id="@+id/internalList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:divider="@color/list_divider_color"
        android:dividerHeight="@dimen/list_divider_width"
        />
    
    0 讨论(0)
  • 2020-11-28 07:14

    I have the same problem in my App but I needed to use a ListView cause it was a shared item and I didn't want to replicate equal components. So.. I just fixed the size of inner ListView programatically to show all rows and.. voila! Problem solved:

    ViewGroup.LayoutParams layoutParams = innerListView.getLayoutParams();
    layoutParams.height = (int) context.getResources().getDimension(R.dimen.rowheight) * innerListView.getCount();
    innerListView.setLayoutParams(layoutParams);
    CustomAdapter adapter = new CustomAdapter(context, blabla..);
    innerListView.setAdapter(adapter);
    
    rowListView.invalidate();
    
    0 讨论(0)
  • 2020-11-28 07:17

    @Try this nested class

    this works for scroll listView inside listView Or 2 listviews in same activity

            <com.example.taskgrptaskslistview.NestedListView
                android:id="@+id/listviewTasks"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_marginBottom="2dp"
                android:layout_weight="1"
                android:cacheColorHint="#00000000" >
            </com.example.taskgrptaskslistview.NestedListView>
        </LinearLayout>
    

    NestedListView :

    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnTouchListener;
    import android.view.ViewGroup;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.ListAdapter;
    import android.widget.ListView;
    
    public class NestedListView extends ListView implements OnTouchListener, OnScrollListener {
    
    private int listViewTouchAction;
    private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;
    
    public NestedListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        listViewTouchAction = -1;
        setOnScrollListener(this);
        setOnTouchListener(this);
    }
    
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
            if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
                scrollBy(0, -1);
            }
        }
    }
    
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
        int newHeight = 0;
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            ListAdapter listAdapter = getAdapter();
            if (listAdapter != null && !listAdapter.isEmpty()) {
                int listPosition = 0;
                for (listPosition = 0; listPosition < listAdapter.getCount()
                        && listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
                    View listItem = listAdapter.getView(listPosition, null, this);
                    //now it will not throw a NPE if listItem is a ViewGroup instance
                    if (listItem instanceof ViewGroup) {
                        listItem.setLayoutParams(new LayoutParams(
                                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                    }
                    listItem.measure(widthMeasureSpec, heightMeasureSpec);
                    newHeight += listItem.getMeasuredHeight();
                }
                newHeight += getDividerHeight() * listPosition;
            }
            if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
                if (newHeight > heightSize) {
                    newHeight = heightSize;
                }
            }
        } else {
            newHeight = getMeasuredHeight();
        }
        setMeasuredDimension(getMeasuredWidth(), newHeight);
    }
    
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
            if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
                scrollBy(0, 1);
            }
        }
        return false;
    }
    }
    
    0 讨论(0)
  • 2020-11-28 07:25

    From the Android documentation - Listview: ListView is a view group that displays a list of scrollable items

    You do not really want to scroll that inner list view, you want to scroll the outer listview. However I asume that the inner listview may vary on the amount of elements it contains.

    Instead of the inner list view you could use a

    • linear layout, see this tutorial or look at Adding content to a linear layout dynamically?
    • table layout

    For the linear layout (some sample code):

    // access your linear layout
    LinearLayout layout = (LinearLayout)findViewById(R.id.layout);
    // load the xml structure of your row
    View child = getLayoutInflater().inflate(R.layout.row);
    // now fill the row as you would do with listview
    //e.g. (TextView) child.findViewById(...
    ...
    // and than add it
    layout.addView(child);
    

    You should save the linear layout in a view holder (see View Holder pattern). I think the removeAllViews() is only necessary when the current row has lesser inner rows than the reused one, so I would also save the number of rows in the view holder.

    If the maximum number of inner rows is not to high you could also think about caching them in the view holder to avoid the inflate and findByViewId (lets say in an ArrayList).

    0 讨论(0)
提交回复
热议问题