ListView:如何从外部以编程方式访问Item的元素?

时间:2014-10-14 14:04:49

标签: android listview

我有以下情况。

我有一个ListView,ListView的每个项目都包含不同的小部件(TextViews,ImageViews等等),这些小部件在自定义适配器的getView()方法中从一个布局中充气。

现在,我想实现以下目标:

当触发某个事件时,我想要更改项目内的视图的背景。

请问我该怎么做?


这是项目布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cardlayout"
android:layout_width="320dp"
android:layout_height="130dp"
android:background="@android:color/transparent"
android:orientation="vertical"
android:paddingBottom="5dp"
android:paddingRight="5dp"
android:paddingTop="5dp" >

<FrameLayout
    android:layout_width="320dp"
    android:layout_height="117dp" >

    <View
        android:id="@+id/card"
        android:layout_width="320dp"
        android:layout_height="117dp"
        android:background="@drawable/card_selector" />

</FrameLayout>  
</LinearLayout>

我需要更改card

的背景

我试过这样做:

View v=lv.getAdapter().getView(index, null, lv);
View card =(View)v.findViewById(R.id.card);
card.setBackgroundResource(R.drawable.pressed_background_card);

但没有成功: - ((

6 个答案:

答案 0 :(得分:7)

当你的事件被触发时,你应该只在你的适配器上调用notifyDataSetChanged,这样它就会再次调用所有可见元素的getView。

你的getView方法应该考虑到一些元素可能有不同的背景颜色(如果元素不需要改变背景,不要忘记将它设置为正常颜色,否则回收你会有很多元素和背景改变当你滚动)

编辑:

我会尝试这样的事情:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if(convertView == null)
    {
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.card, parent, false);
    }

    //This part should also be optimised with a ViewHolder
    //because findViewById is a costly operation, but that's not the point of this example
    CardView cardView =(CardView)convertView .findViewById(R.id.card);

    //I suppose your card should be determined by your adapter, not a new one each time
    Card card = getItem(position);

    //here you should check sthg like the position presence in a map or a special state of your card object
    if(mapCardWithSpecialBackground.contains(position))
    {
        card.setBackgroundResource(specialBackground);
    }
    else
    {
        card.setBackgroundResource(normalBackground);
    }
    cardView.setCard(card);

    return convertView;
}

在特殊事件中,我会将项目的位置添加到地图中并调用notifyDataSetChanged。

答案 1 :(得分:2)

使用onitemclicklistener,它有方法onclicksomething..that需要四个或五个参数。 (查看父级,视图视图,int位置,int id)。使用view参数自定义背景。

<强>更新 这是我的一些代码,如果你不明白我建议阅读有关回收和ViewHolder模式的内容。

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
    {
            ViewHolder viewHolder;
            // If convertView isn't a recycled view, create a new.
            if(convertView == null){
                LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.row_gallery_frame, parent, false);

                viewHolder = new ViewHolder();
                // Here you must be able to find your Widget inside convertView and set a listener to it I guess?
                viewHolder.nameHolder = (TextView) convertView.findViewById(R.id.nameTv);
                // Set a reference to newly inflated view
                convertView.setTag(viewHolder);
            }
            // If it is, then get the ViewHolder by tag
            else{
                viewHolder = (ViewHolder)convertView.getTag();
            }
            // Set the data
            GalleryFrame galleryFrame = galleryFrameArrayList.get(position);

            viewHolder.nameHolder.setText(galleryFrame.getName());

            return convertView;
        }
    }
    // Viewholder pattern which holds all widgets used
    public static class ViewHolder{
        public TextView nameHolder;
    }

答案 2 :(得分:2)

我假设你有一个模型对象用于&#34;绘制&#34;列表项,例如背景颜色是基于boolean或其他东西确定的。

您需要做的就是更改您决定的值TextView应该具有哪种背景颜色。

您的getView()方法应该包含类似

的代码
if (myModelObj.isBrown()) {
    myTextView.setBackgroundResource(R.drawable.brown_bg);
else
    myTextView.setBackgroundResource(R.drawable.not_brown_bg);

触发ur事件时应该执行的操作,在模型中设置brown boolean的值 并在适配器上调用notifyDataSetChanged()

修改

如果由于某种原因你不想打电话给nofitfyDataSetChanged(),虽然它不会移动你的列表的滚动位置,并且正确的回收它不会导致糟糕的性能

您可以找到代表您要编辑的列表项的View对象(如果它是可见的),只需更改其中的背景,而无需刷新列表。

int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();
int wantedChild = wantedPosition - firstPosition
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
    // Wanted item isn't displayed
    return;
}
View wantedView = listView.getChildAt(wantedChild);

然后使用wantedView编辑背景

可以找到此答案here

答案 3 :(得分:1)

试试这个:

View v=lv.getAdapter().getView(index, null, lv);
View card =(View)v.findViewById(R.id.card);
card.setBackgroundResource(R.drawable.pressed_background_card);
card.invalidate();
v.invalidate();

这些函数强制您的视图重绘自己,然后它们将再次渲染。 看看invalidate()

答案 4 :(得分:1)

我通常做的是:

public static class EventDetailsRenderer {

    private TextView title;

    private TextView description;

    private Event item;

    public EventDetailsRenderer(View view) {
        extractFromView(view);
    }

    private final void extractFromView(View view) {
        title = (TextView) view.findViewById(R.id.EventTitle);
        description = (TextView) view.findViewById(R.id.Description);
    }

    public final void render() {
            render(item);
    }

    public final void render(Event item) {
        this.item= item;
        title.setText(item.getTitle());
        description.setText(item.getDescription());
    }
}

private class EventsAdapter
        extends ArrayAdapter<Event> {

    public EventsAdapter(Context context) {
        super(context, R.layout.list_node__event_details, 0);
    }

    public void addAllItems(Event... services) {
        for (int i = 0; i < services.length; i++) {
            add(services[i]);
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Event event = getItem(position);
        EventDetailsRenderer eventRenderer;

        if (convertView != null && convertView.getTag() != null) {
            eventRenderer = (EventDetailsRenderer) convertView.getTag();
        } else {
            convertView = getActivity().getLayoutInflater().inflate(R.layout.list_node__event_details, null);
            eventRenderer = new EventDetailsRenderer(convertView);
            convertView.setTag(eventRenderer);
        }

        eventRenderer.render(event);
        return convertView;
    }
}

注意:这个例子可能无法编译我从我的一些代码粘贴它并删除了一些行来显示一个例子,但逻辑是相同的。

然后当你想渲染它时,只需从列表中获取子项,迭代它们,检查渲染器是否包含要翻转的卡并调用其渲染方法...然后渲染特定项目列表不影响其余项目。

让我知道这是否有效......

亚当。

答案 5 :(得分:1)

用户 EasyListViewAdapters https://github.com/birajpatel/EasyListViewAdapters

  

功能

  1. 比实施自己的适配器更容易(即处理 BaseAdaper#getView)。很容易提供多行支持。
  2. 图书馆负责回收所有观看,确保效果 &安培;帮助您的列表视图顺畅滚动。
  3. 清洁代码。通过保留不同的RowViewSetter类 不同的行类型使您的代码易于管理和易于重复使用。
  4. 无数据浏览:图书馆负责浏览数据 绘制视图或发生事件时的数据结构 用户无需查找其数据即可采取措施。
  5. 只需传递正确的行类型库,自动映射即可 数据类型到行类型以呈现视图。可以创建行视图 使用 XML或Java (不限制为仅使用XML的方法)。
  6. 加载可以注册更多回调以实现 paginatation 支持到您的列表中。
  7. 处理儿童观看次数,您也可以注册 子项(存在于行内)查看单击事件。
  8. 所有这些观点都使用单一 OnClickListner 注册,以便 当单击事件发生时,此机制非常内存效率 用户 clickedChildView ,rowData,int eventId作为回调 PARAMS。
  9. enter image description here enter image description here enter image description here