简体   繁体   中英

ListView won't retain state when i dynamically update after scrolling Android Studio

I am creating a ListView inside of a popupWindow. Currently, i have my list view showing and parts will update as of now, but if click an index to change the background color, scroll to put it off the page, then scroll back to that index, it doesn't retain my change (which was a text change). Also, as of now, another problem is that the "parent.getChildAt(position).setBackgroundColor(Color.BLUE);" causes an error if i click on specific indexes.

Here is the part of the code that contains my popupwindow and the list view

public void bringUpEventsPopover() {
        final LayoutInflater layoutInflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        //inflate the custom popup layout
        final View inflatedView = layoutInflater.inflate(R.layout.popup_layout,null,false);

        //find the listeview in the popup layout (we will need to construct this still)
        final ListView listView = (ListView)inflatedView.findViewById(R.id.commentsListView);

        //get device size
        /*Display display = getActivity().getWindowManager().getDefaultDisplay();
        final Point size = new Point();
        display.getSize(size);*/
        int width = view.getWidth();
        int height = view.getHeight();
        //fill the data to the list items
        setSimpleList(listView);

        //set the height depends on the device size
        //popWindow= new PopupWindow(inflatedView, size.x, size.y, true);
        popWindow= new PopupWindow(inflatedView, width, height-50, true);
        //make it focusable to show the keyboard to enter in 'edittext'
        popWindow.setFocusable(true);
        popWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        //show the popup at bottom of the screen and set some margin at bottom
        popWindow.showAtLocation(view, Gravity.CENTER, 0, 0);

        //make it outside touchable to dismiss the popup window when touched outside the popup area
        popWindow.setOutsideTouchable(true);
        popWindow.update();
        final FrameLayout mainFrame = (FrameLayout) getActivity().findViewById(R.id.frametop);
        mainFrame.getForeground().setAlpha(160);
        popWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                mainFrame.getForeground().setAlpha(0);
            }
        });
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id)
            {
                // selected item
                //Event item = (Event)listView.getItemAtPosition(position);
                TextView tv = (TextView)view.findViewById(R.id.eventCreator);
                parent.getChildAt(position).setBackgroundColor(Color.BLUE);
            }
        });
    }
    void setSimpleList(ListView listView){

        eventList = new ArrayList<>();


        for (int index = 0; index < 6; index++) {
            eventList.add(new Event("BT","We gon play sports and stuff","Title","Time is "+index+"pm today","3 Hours","15/30"));
        }

        for(Event item: eventList)
        {
            System.out.println(item.getTitle()+"\n"+item.getTime()+"\n"+item.getNumPeople()+"\n");
        }
        adapter = new ItemAdapter(getActivity(),R.layout.view_event,eventList);
        listView.setAdapter(adapter);
    }

This is my ItemAdapter class for the ListView

public class ItemAdapter extends ArrayAdapter<Event> {

    // declaring our ArrayList of items
    private ArrayList<Event> objects;

    /* here we must override the constructor for ArrayAdapter
    * the only variable we care about now is ArrayList<Item> objects,
    * because it is the list of objects we want to display.
    */
    public ItemAdapter(Context context, int textViewResourceId, ArrayList<Event> objects) {
        super(context, textViewResourceId, objects);
        this.objects = objects;
    }

    /*
     * we are overriding the getView method here - this is what defines how each
     * list item will look.
     */
    public View getView(int position, View convertView, ViewGroup parent){
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        // assign the view we are converting to a local variable
        View v = convertView;
        // first check to see if the view is null. if so, we have to inflate it.
        // to inflate it basically means to render, or show, the view.
        if (v == null) {
            v = inflater.inflate(R.layout.view_event, null);
            v.setTag(position);
        }
        else
        {
            v.getTag();
        }

        /*
         * Recall that the variable position is sent in as an argument to this method.
         * The variable simply refers to the position of the current object in the list. (The ArrayAdapter
         * iterates through the list we sent it)
         *
         * Therefore, i refers to the current Item object.
         */
        Event i = objects.get(position);

        if (i != null) {

            // This is how you obtain a reference to the TextViews.
            // These TextViews are created in the XML files we defined.

            TextView creator = (TextView) v.findViewById(R.id.eventCreator);
            TextView title = (TextView) v.findViewById(R.id.eventTitle);
            TextView description = (TextView) v.findViewById(R.id.eventDescription);
            TextView time = (TextView) v.findViewById(R.id.eventTime);
            TextView duration = (TextView) v.findViewById(R.id.eventDuration);
            TextView numPeople = (TextView) v.findViewById(R.id.eventAttendance);

            // check to see if each individual textview is null.
            // if not, assign some text!
            if(creator!=null)
            {
                creator.setText("Creator: "+i.getCreator());
            }
            if (title != null){
                title.setText("Title: "+i.getTitle());
            }
            if(description!=null)
            {
                description.setText("Description: "+i.getDescription());
            }
            if( time != null) {
                time.setText("Time: "+i.getTime());
            }
            if(duration!=null)
            {
                duration.setText("Duration: "+i.getDuration());
            }
            if (numPeople != null){
                numPeople.setText(i.getNumPeople());
            }
        }

        // the view must be returned to our activity
        return v;

    }


}

and this is the layout for each list item

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/eventCreator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="false"
        android:text="Creator: "
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_margin="5dp" />
    <TextView
        android:id="@+id/eventTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/eventCreator"
        android:text="Title: "
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_margin="5dp" />

    <TextView
        android:id="@+id/eventDescription"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/eventTitle"
        android:text="Description: "
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_margin="5dp" />

    <TextView
        android:id="@+id/eventTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/eventDescription"
        android:text="Time: "
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_margin="5dp" />

    <TextView
        android:id="@+id/eventDuration"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/eventTime"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Duration: "
        android:layout_margin="5dp" />

    <TextView
        android:id="@+id/eventAttendance"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/eventDuration"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="15/30 Going"
        android:layout_margin="5dp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/eventAttendance"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_margin="20dp"
        android:text="I'm Going!"
        android:layout_centerHorizontal="true"
        android:focusable="false"
        android:clickable="false"/>

</RelativeLayout>

Two thoughts. 1) Maybe consider a container for your events/items so that you can give them dynamic ids and then use those to set the background color. You might have more luck saving the state when it roll on/off the screen. 2) I'm not 100% sure on this, so don't take it as gospel, but I think when you roll a list view out of view, the adaptor may mess with the index variable in the child structure. Is there another way you can access the child nodes of that list view? Sorry I don't have a good answer for that one, just an idea for you to chase down maybe. Good luck!

  • Jon

I figured it out on my own. So the Array Adapter has several parts to it when setting it up.

// first check to see if the view is null. if so, we have to inflate it.
        // to inflate it basically means to render, or show, the view.
        if (v == null) {
            /* This is where you initialize new rows, by:
         *  - Inflating the layout,
         *  - Instantiating the ViewHolder,
         *  - And defining any characteristics that are consistent for every row */
            v = inflater.inflate(R.layout.view_event, null);
            v.setTag(position);
        }
        else
        {
            /* Fetch data already in the row layout,
         *    primarily you only use this to get a copy of the ViewHolder */
            v.getTag();
        }
     /* Set the data that changes in each row, like `title` and `size`
     *    This is where you give rows there unique values. */

so i setup a new variable in my Event Class to hold an "isSelected" field, which my "onItemClickListener" sets, and then notifies the ArrayAdapter to a data change. In the Array Adapter, i just did a check for the Event.isSelected() var and loaded background accordingly.

myArrayAdapter that alters background:

        if(objects.get(position).isSelected())
        {
            v.setBackgroundColor(Color.CYAN);
        }
        else
        {
            v.setBackgroundColor(Color.WHITE);
        }

myItemClickListener:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id)
            {

                // selected item
                adapter.objects.get(position).setSelected(true);
                adapter.notifyDataSetChanged();
            }
        });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM