【问题标题】:android: listview in listviewandroid:列表视图中的列表视图
【发布时间】:2012-07-24 01:35:59
【问题描述】:

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

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

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

【问题讨论】:

  • 根据您的描述,您不希望在ListView 中包含ListView,这很好,因为这不会很好地工作。相反,您希望在 ListView 行内有一个垂直的 LinearLayout,您的设置与行的其​​余内容没有什么不同。
  • 也许你可以尝试使用片段。每个fragment都是一个listview,你可以添加任意数量的fragment来创建listview的listview!
  • @CommonsWare 是的,我不想在列表视图中使用列表视图。但是由于内部-“它是什么”是一个包含一到四个项目的列表(可能因行而异),所以我需要某种容器。
  • @kopi_b LinearLayout 一个容器。
  • @SreekanthKarumanaghat:这不可能在摘要中回答。

标签: android listview


【解决方案1】:

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

您并不是真的想滚动该内部列表视图,而是想要滚动外部列表视图。但是我认为内部列表视图可能会根据其包含的元素数量而有所不同。

你可以使用一个代替内部列表视图

对于线性布局(一些示例代码):

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

您应该将线性布局保存在视图支架中(请参阅View Holder pattern)。我认为removeAllViews() 仅在当前行的内部行少于重用行时才需要,因此我还将保存视图持有者中的行数。

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 对我不起作用。 innerListView 仍然不可滚动。当我尝试在 InnerListView 中滚动时,我在父 ListView 中滚动...
    • @Cocorico 我应该指定我的内部列表视图实际上是在外部列表视图内部的线性布局内
    • 几个小时后,我找到了这个答案,谢谢,非常棒
    【解决方案3】:

    我在我的应用程序中遇到了同样的问题,但我需要使用 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();
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 可重用视图在何处/何时被填充?
      • @lobzik - 我目前正在使用您的代码,它使得在另一个列表视图中拥有一个列表视图变得非常容易。但我一直在尝试为这个内部列表视图实现 onItemClick 并让它在外部列表视图中运行良好,目前我没有成功。关于如何做到这一点的任何提示?
      • 您没有缓存任何视图。
      • @q126y 你是什么意思?
      【解决方案5】:

      @试试这个嵌套类

      这适用于滚动 listViewlistView 或 2 listviews 在同一 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>
      

      嵌套列表视图:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-24
        • 1970-01-01
        • 2013-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多