如何在 Android 中隐藏列表视图中的项目

问题描述 投票:0回答:12

我知道,这个问题之前曾被问过,但我还没有看到有效的答案。

有没有办法在不更改源数据的情况下隐藏

ListView
中的某些项目?

我尝试将项目视图的可见性设置为消失,它不会再显示,但为此项目保留的位置仍然存在。

我还设置了:

android:dividerHeight="0dp"
android:divider="#FFFFFF"

没有成功。

android listview android-listview
12个回答
25
投票

您可以编写自己的

ListAdapter
或对现有的之一进行子类化。

在您的

ListAdapter
中,您只需根据需要返回
getCount()
getItem()
getItemId()
的修改值来过滤掉不希望显示的项目。


15
投票

如果你想像这样隐藏项目:

convertView.setLayoutParams(new AbsListView.LayoutParams(-1,1));
convertView.setVisibility(View.GONE);

不能是 AbsListView.LayoutParams(-1,0);

如果convertview被重用,你应该在下面添加这个来设置它的高度:

if(convertView.getVisibility() == View.GONE) {
            convertView.setVisibility(View.VISIBLE);
            convertView.setLayoutParams(new AbsListView.LayoutParams(-1,-2));
        }

11
投票

我尝试了几种解决方案,包括

setVisibitlity(View.GONE)
和膨胀默认
null
视图,但它们都有一个共同的问题,那就是隐藏项目之间的分隔线堆叠在一起,并在大列表中形成了糟糕的可见灰色空间。

如果您的

ListView
CursorAdapter
支持,那么最好的解决方案是用
CursorWrapper
包裹它。

所以我的解决方案(基于@RomanUsachev答案这里)是这样的:

过滤光标包装器

   public class FilterCursorWrapper extends CursorWrapper {
    private int[] index;
    private int count = 0;
    private int pos = 0;

    public boolean isHidden(String path) {

      // the logic to check where this item should be hidden

      //   if (some condintion)
      //      return false;
      //    else {
      //       return true; 
      //   }

       return false;

    }

    public FilterCursorWrapper(Cursor cursor, boolean doFilter, int column) {
        super(cursor);
        if (doFilter) {
            this.count = super.getCount();
            this.index = new int[this.count];
            for (int i = 0; i < this.count; i++) {
                super.moveToPosition(i);
                if (!isHidden(this.getString(column)))
                    this.index[this.pos++] = i;
            }
            this.count = this.pos;
            this.pos = 0;
            super.moveToFirst();
        } else {
            this.count = super.getCount();
            this.index = new int[this.count];
            for (int i = 0; i < this.count; i++) {
                this.index[i] = i;
            }
        }
    }

    @Override
    public boolean move(int offset) {
        return this.moveToPosition(this.pos + offset);
    }

    @Override
    public boolean moveToNext() {
        return this.moveToPosition(this.pos + 1);
    }

    @Override
    public boolean moveToPrevious() {
        return this.moveToPosition(this.pos - 1);
    }

    @Override
    public boolean moveToFirst() {
        return this.moveToPosition(0);
    }

    @Override
    public boolean moveToLast() {
        return this.moveToPosition(this.count - 1);
    }

    @Override
    public boolean moveToPosition(int position) {
        if (position >= this.count || position < 0)
            return false;
        return super.moveToPosition(this.index[position]);
    }

    @Override
    public int getCount() {
        return this.count;
    }

    @Override
    public int getPosition() {
        return this.pos;
    }
}

当您的

Cursor
准备就绪时,将您所需的列索引输入到
FilterCursorWrapper

FilterCursorWrapper filterCursorWrapper = new FilterCursorWrapper(cursor, true,DATA_COLUMN_INDEX);

dataAdapter.changeCursor(filterCursorWrapper);

如果您进行过滤和排序,请不要忘记在任何地方使用

FilterCursorWrapper

    dataAdapter.setFilterQueryProvider(new FilterQueryProvider() {
        @Override
        public Cursor runQuery(CharSequence constraint) {
            String selection = MediaStore.Video.Media.DATA + " LIKE '%" + constraint.toString().toLowerCase() + "%'";
            return new FilterCursorWrapper(context.getContentResolver().query(videoMediaUri, columns, selection, null, null), true, DATA_COLUMN_INDEX);
        }
    });

为了刷新列表,使用空过滤器查询就足够了:

dataAdapter.getFilter().filter("");

就完成了,只需更改

isHidden
方法的逻辑,即可控制显示或隐藏隐藏项目。这样做的好处是您不会看到不必要的分隔物堆积起来。 :-)


5
投票

在某些情况下,您有一个简单的解决方案:

我必须隐藏列表视图中的视图,因为填充视图的项目无效,所以我不想看到该视图:

在我的列表适配器中:

public class PlanListAdapter extends BaseAdapter{

//some code here : constructor ......

    // my code that create the view from the item list (one view by item ...)
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {


        LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        convertView = inflater.inflate(R.layout.my_layout, null);

        if(my_data_are_not_valid) {
             //just create an empty view     
             convertView = new Space(context);  
        }
        else {
             //populate the view with data here     
             populate(convertView);
        }

        return convertView;
}

//some code here to populate the view ...


}

2
投票

如果您创建自己的

adapter
,您可以在
public View getView(int position, View convertView, ViewGroup parent)
方法中完成。如果您计划在某个时候显示不可见的项目,这可能很有用。例如:

if(item.getYourRequirement == undesiredVlue)
    convertView.setVisibility(View.GONE);
else
    convertView.setVisibility(View.VISIBLE);

我希望这有帮助


2
投票

我有一个无法使用支持数组修改的

CursorAdapter
,因为检查项目是否应该显示是在从数据库获取结果之后。我已经按照其他帖子中描述的类似方法在
bindView(View v, Context context, Cursor c)
中实现了解决方案。 我认为最好的方法是重写
bindView()
方法而不是
getView(int position, View convertView, ViewGroup parent)
,因为你应该在getView()中对convertView进行空值检查。
第二件事:我尝试将
View v
隐藏在
bindView(View v, Context context, Cursor c)
中,但没有成功。经过调查,我发现我必须隐藏视图中的每个元素(包括包含文本、图像等的布局)


1
投票

一个技巧是将要隐藏的列表项的高度设置为 0。

但是,正如seretur所说,正确的方法是删除该项目并使用

notifyDataSetChanged()
。为什么这个解决方案不适合您的情况?


1
投票

为我解决这个问题的简单方法,只需在调用方法“setAdapter”之前解析并检查活动中的列表,例如:

for(Object a : list){
//here must be some condition for getting all items without hidden
newList += a;
}
setAdapter(newList);

0
投票

listview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp" >

<ImageView
    android:id="@+id/imgView"
    android:layout_width="40dp"
    android:layout_height="20dp"/>

<TextView
    android:id="@+id/totalTime"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:textSize="14dp"
    android:text="16 分鐘"
    android:layout_weight="1"
    android:paddingLeft="10dp" />
<TextView
    android:id="@+id/currentTime"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:textSize="14dp"
    android:text="11:46"
    android:layout_weight="1"
    android:gravity="right"
    android:paddingLeft="10dp" />
<ImageView
    android:id="@+id/img"
    android:layout_width="40dp"
    android:layout_height="20dp"
    />
</LinearLayout>

MainActivity.java

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            view.findViewById(R.id.img).setVisibility(View.GONE);

        }
    });

对我来说很有效。


0
投票

对我来说,一个简单的解决方案是使用自定义行布局创建自己的适配器,其中包含所有内容的包装器(例如 LinearLayout),并在适配器的 getView() 方法中将此包装器可见性设置为 View.GONE ,而我没有这样做希望显示该项目。无需修改数据集或维护两个列表。创建ListView时,我还设置它不自动显示分隔线:

    android:divider="@null"
    android:dividerHeight="0dp"

并绘制我自己的分隔线(当我不想要该项目时,我也将其设置为“消失”)。否则,您会看到多个分隔线或一条粗灰线,其中隐藏了多个项目。


0
投票

我使用 Jetpasck Compose,所以我不使用 XML 布局。

无论如何,我找到了隐藏项目遵循模式或正则表达式的解决方案。

在 LazyColumn 范围内,我向列表添加了一个过滤器,然后在选择代码中我在未过滤的列表中进行查找

这是使用此选项的部分代码:

LazyColumn(modifier = Modifier.fillMaxWidth(), state = listState) {
                    if (notSetLabel != null) {
                        item {
                            LargeDropdownMenuItem(
                                text = notSetLabel,
                                selected = false,
                                enabled = false,
                                onClick = { },
                            )

                        }
                    }
                    //Adding the filter. I my case a contains function was good enough
                    itemsIndexed(items.filter { x -> x.toString().contains(term, true)
                    }) { index, item ->
                        val selectedItem = index == selectedIndex
                        drawItem(
                            item,
                            selectedItem,
                            true
                        ) {
                            //onItemSelected(index, item) --- Original code
                            //Change the selection to a lookup for original index in the unfiltered List
                            onItemSelected(items.indexOf(item), item)
                            expanded = false
                        }

                        if (index < items.lastIndex) {
                            Divider(modifier = Modifier.padding(horizontal = 8.dp))
                        }
                    }

                }

就是这样,一切都保持不变。


-1
投票

这是我的解决方案:

public class MyAdapter extends ArrayAdapter<MyEntry> {

    public MyAdapter(Context context, int resId) {
        super(context, resId);
    }

    private List<MyEntry> visibleEntries() {

        List<MyEntry> result = new ArrayList<MyEntry>();

        int i = 0;
        try {
            while (true) {
                if (getItem(i).isVisible())
                    result.add(getItem(i));
                i++;
            }

        } catch(Exception e) {

        }

        return result;

    }

    @Override
    public int getCount() {
        return visibleEntries().size();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LinearLayout layout = 
            convertView == null ? 
                (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.entry, parent, false) :
                (LinearLayout) convertView;

        MyEntry entry = visibleEntries().get(position);

        ...

        return layout;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.