ListView: how to access Item's elements programmatically from outside?

前端 未结 6 959
长情又很酷
长情又很酷 2021-01-22 02:17

I have the following situation.

I have a ListView, each item of the ListView is comprised of different widgets (TextViews, ImageViews, etc...) inflated form a Layout in

相关标签:
6条回答
  • 2021-01-22 02:26

    When your event is triggered you should just call a notifyDataSetChanged on your adapter so that it will call again getView for all your visible elements.

    Your getView method should take into account that some elements may have different background colors (and not forget to set it to normal color if the element doesn't need the changed background, else with recycling you would have many elements with changed background when you scroll)

    edit :

    I would try something like this :

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

    And on the special event i would add the position of the item into the map and call notifyDataSetChanged.

    0 讨论(0)
  • 2021-01-22 02:27

    I assume you have a model object that you use to "draw" the list item , and for example the background color is determined based on a boolean or something.

    All you need to do, is change the value on which you base your decision which background color should that TextView have.

    Your getView() method should have code like that

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

    All you should do when ur event is triggered, is set the value of the brown boolean in your model and call notifyDataSetChanged() on your adapter

    EDIT

    If for some reason you don't wanna call nofitfyDataSetChanged(), althought it won't move the scroll position of your list and with the right recyclying it won't cause bad performance

    You can find the View object that represent the list item you want to edit-if it's visisble-, and simply change the background in it, without refreshing the list at all.

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

    then use wantedView to edit your background

    This answer can be found here

    0 讨论(0)
  • 2021-01-22 02:27

    try this one:

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

    those function force your views to redraw itself and they will render again. look at invalidate()

    0 讨论(0)
  • 2021-01-22 02:34

    What I normally do is this:

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

    NOTE: that this example might not compile I pasted it from some code I have and deleted some lines to show an example but the logic it the same.

    And then when you want to render it, just get the children from the list, iterate over them, check if the renderer contains the card you want to flip and call its render method... then you render a specific item in the list without effecting the rest of the items.

    Let me know if this works...

    Adam.

    0 讨论(0)
  • 2021-01-22 02:35

    User EasyListViewAdapters library https://github.com/birajpatel/EasyListViewAdapters

    Features

    1. Easier than implementing your own Adapter (ie handling BaseAdaper#getView).Very Easier to provide multi-row support.
    2. Library takes care of recycling all views, that ensures performance & helps your list view scroll smoothly.
    3. Cleaner code. By keeping different RowViewSetter classes for different row-types makes your code easy to manage & easy to reuse.
    4. No data browsing, Library takes care of browsing data through data-structure when View is being drawn or event occurs so that Users does not have to look for their data to take actions.
    5. Just by passing correct row-types library will Auto-map your data-types to row-types to render views. Row views can be created by using XML or Java (doesn't restrict to XML-Only Approach).
    6. Load More callbacks can be registered to implement paginatation support to your list.
    7. Handling children viewclicks, you can also register for Children(present inside your rows) view click events.
    8. All these Views are registered with single OnClickListner so that this mechanism is very memory efficient when click event occurs users you gets clickedChildView, rowData,int eventId as callback params.

    enter image description hereenter image description hereenter image description here

    0 讨论(0)
  • 2021-01-22 02:50

    Use the onitemclicklistener which has method onclicksomething..that takes four or five parameters. (View parent, View view, int position, int id). Use the view parameter to customize your background.

    Update Here's some of my code, If you don't understand I recommend to read about recycling and ViewHolder pattern.

    @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;
        }
    
    0 讨论(0)
提交回复
热议问题