Skip to content Skip to sidebar Skip to footer

Spannable String Only Working For Last Item In Listview

Edit: I'm now able to strike words in the listview but only able to do it from the bottom up and can only unstrike the bottom item afterwards. The code is below. @Override public

Solution 1:

You should pass checked state and tasksTitle to toggleLineThrough() too. Variables completed and tasksTitle contain wrong values because onClickListener is called later than getView(). They were overwritten several times by consecutive calls of getView().

Solution 2:

@SmiffyKmc, I am trying to use the following to answer other similar questions, so some comments may not related to your problem.

Have made a completed sample here:

in strings.xml:

<string-arrayname="list_items_sample"><item>One</item><item>Two</item><item>Three</item><item>Four</item><item>Five</item><item>Six</item><item>Seven</item><item>Eight</item><item>Nine</item><item>Ten</item><item>Eleven</item><item>Twelve</item><item>Thirteen</item><item>Fourteen</item><item>Fifteen</item><item>Sixteen</item><item>Seventeen</item><item>Eighteen</item><item>Nineteen</item><item>Twenty</item></string-array>

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="${relativePackage}.${activityClass}" >

<ListView
    android:id="@+id/listView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="7dp" >

</ListView>

custom_list_items.xml:

<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/RelativeLayout1"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="20dp"android:paddingTop="20dp" ><CheckBoxandroid:id="@+id/cb"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentEnd="true"android:layout_alignParentRight="true"android:focusable="false" /><TextViewandroid:id="@+id/tvId"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBaseline="@+id/cb"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:layout_marginBottom="5dp"android:layout_marginTop="5dp"android:gravity="center"android:minWidth="70dp"android:textSize="25sp" /><TextViewandroid:id="@+id/tvDescription"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignBaseline="@+id/cb"android:layout_alignParentTop="true"android:layout_toEndOf="@id/tvId"android:layout_toLeftOf="@+id/cb"android:layout_toRightOf="@id/tvId"android:layout_toStartOf="@id/cb" />

MainActivity.java:

publicclassMainActivityextendsActivity {
static final StringITEM_ID = "item_id";
static final StringITEM_NAME = "item_name";
static final StringITEM_CHECKED ="item_checked";
ListView mListView;

ArrayList<HashMap<String, Object>> mDataList = newArrayList<>();
ArrayAdapter<HashMap<String, Object>> mArrayAdapter;

@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mListView = (ListView) findViewById(R.id.listView1);

    String items[] = getResources().getStringArray(R.array.list_items_sample);
    mDataList.clear();
    for(int i=1; i<20; i++){
        HashMap<String, Object> newItem = newHashMap<String, Object>();
        newItem.put(ITEM_ID, String.valueOf(i));
        newItem.put(ITEM_NAME, "Sample<"+items[i-1]+">");
        newItem.put(ITEM_CHECKED, false);
        mDataList.add(newItem);
    }

    mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

    mArrayAdapter = newArrayAdapter<HashMap<String, Object>>(getApplicationContext(), R.layout.custom_list_items, mDataList){
        classViewHolder{
            CheckBox cb;
            TextView tvId;
            TextView tvDescription;
        }
        @OverridepublicViewgetView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            // Prepare views ready for dataif(convertView == null){
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.custom_list_items, parent, false);
                holder = newViewHolder();
                holder.cb = (CheckBox) convertView.findViewById(R.id.cb);
                holder.tvId = (TextView) convertView.findViewById(R.id.tvId);
                holder.tvDescription = (TextView) convertView.findViewById(R.id.tvDescription);
                convertView.setTag(holder);

                holder.cb.setOnClickListener(newOnClickListener(){
                    @OverridepublicvoidonClick(View view) {
                        // Get view, position and DataList(position)CheckBox buttonView = (CheckBox) view;
                        int pos = (int) buttonView.getTag();
                        HashMap<String, Object> selectedItem = newHashMap<String, Object>();
                        selectedItem = getItem(pos);

                        // Update DataListremove(selectedItem);
                        selectedItem.remove(ITEM_CHECKED);
                        if(buttonView.isChecked()){
                            selectedItem.put(ITEM_CHECKED, true);
                            insert(selectedItem, pos);
                        }else{
                            selectedItem.put(ITEM_CHECKED, false);
                            insert(selectedItem, pos);
                        }

                        // Update all UI views bynotifyDataSetChanged();
                        // or Update the affected views directly//                          View itemView = (View) buttonView.getParent();//                          TextView tv = (TextView) itemView.findViewById(R.id.tvDescription);//                          toggleLineThrough(tv, (String)getItem(pos).get(ITEM_NAME), buttonView.isChecked());
                    }
                });
            }else{
                holder = (ViewHolder) convertView.getTag();
            }

            // Get data from DataListHashMap<String, Object> currentItem = getItem(position);

            // Setup List items UI
            holder.tvId.setText((String)currentItem.get(ITEM_ID));
            holder.cb.setChecked((boolean)currentItem.get(ITEM_CHECKED));
            toggleLineThrough(holder.tvDescription, (String)currentItem.get(ITEM_NAME), (boolean)currentItem.get(ITEM_CHECKED));

            // Save position to CheckBox, so position can be retrieved when CheckBox is clicked
            holder.cb.setTag(position);

            return convertView;
        }
        privatevoidtoggleLineThrough(TextView tasksTitle, String title, boolean completed){
            SpannableString styledString = newSpannableString(title);
            if(completed == true){
                styledString.setSpan(newStrikethroughSpan(), 0, title.length(), 0);
                tasksTitle.setText(styledString);
            }else{
                tasksTitle.setText(title);
            }
        }
    };
    mListView.setAdapter(mArrayAdapter);
}
}

Some important points:

  1. Keep state of the CheckBox as a field in data list and setup UI accordingly, otherwise ListView will be wrong after scroll.
  2. getView() is over when the ListView is shown. OnClickListener SHOULD NOT use the data obtained from getView().
  3. OnClickListener SHOULD ABLE and NEED to get data from data list. The simplest method may be: "View.setTag(position) in getView(), View.getTag() in OnClickListener()".
  4. Don't just modified views only. Change data, data list first. Then call notifyDataSetChanged(). If there is only a small change to UI, can do it directly but should be the same as calling notifyDataSetChanged().

Hope that help!

Post a Comment for "Spannable String Only Working For Last Item In Listview"