android:列表视图中的列表视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11652814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:22:55  来源:igfitidea点击:

android: listview in listview

androidlistview

提问by kopi_b

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 way to to this? table, grid, ...? the problem i'm facing right now is that the inner listview doesn't take the space it needs, so it's cut at about the end of the first listitem. if i try to scroll, just the outer listview is scrolling which is exactly what i want.

我正在尝试将一个列表视图放在一个列表视图项中。内部列表视图不应该是可滚动的,而是采用显示所有行所需的所有大小。有没有更好的方法呢?桌子,网格,...?我现在面临的问题是内部列表视图没有占用它需要的空间,所以它在第一个列表项的末尾被切断。如果我尝试滚动,只是外部列表视图正在滚动,这正是我想要的。

how_it_should_look_likethanks, my final solution is

how_it_should_look_like谢谢,我的最终解决方案是

LinearLayout layout = (LinearLayout) row.findViewById(R.id.LLBroadcasts);
layout.removeAllViews();

for (Item b : bs.getItems()) {

  View child = _inflater.inflate(R.layout.item_row, null);

  TextView tvTitle = (TextView) child.findViewById(R.id.TVItemTitle);
  tvTitle.setText(b.getTitle());

  TextView tvDesc = (TextView) child.findViewById(R.id.TVItemDescription);
  tvDesc.setText(b.getDescription());
  layout.addView(child);
}

回答by ChrLipp

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

来自 Android 文档 - ListviewListView 是一个显示可滚动项目列表的视图组

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

除了内部列表视图,您还可以使用

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.

您应该将线性布局保存在视图支架中(请参阅视图支架模式)。我认为removeAllViews()只有当当前行的内部行少于重用的行时才需要,所以我也会保存视图持有者中的行数。

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

如果内部行的最大数量不是很高,您还可以考虑将它们缓存在视图持有者中以避免膨胀和 findByViewId(可以在 ArrayList 中说)。

回答by Ian Holing

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:

我的应用程序中有同样的问题,但我需要使用 ListView 因为它是一个共享项目,我不想复制相同的组件。所以..我只是以编程方式固定内部 ListView 的大小以显示所有行和..瞧!问题解决了:

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

回答by lobzik

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

也许有人会发现我的解决方案很有用。它基于@ChrLipp 答案并使用 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"
    />

回答by madhu527

@Try this nested class

@试试这个嵌套类

this works for scroll listViewinside listViewOr 2 listviews in same activity

这适用于滚动listView内部listView或 2listviewactivity

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

回答by Fiberwire

I tried making this exact structure (a ListViewinside 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_heightof the inner list from match_parentto a set dp.

我尝试制作这个精确的结构(a 的ListView内部ListView)并且遇到了同样的问题,它只显示了 inner 的第一项ListView。我通过将layout_height内部列表的match_parent更改为 set 来修复它dp

It seemed to work exactly as I wanted it to.

它似乎完全按照我的意愿工作。