Spannable String only working for last Item in ListView

后端 未结 2 1872
情歌与酒
情歌与酒 2020-12-04 03:34

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.

相关标签:
2条回答
  • 2020-12-04 04:09

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

    0 讨论(0)
  • 2020-12-04 04:10

    @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-array name="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"?>
    <RelativeLayout xmlns: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" >
    
    <CheckBox
        android:id="@+id/cb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:focusable="false" />
    
    <TextView
        android: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" />
    
    <TextView
        android: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:

    public class MainActivity extends Activity {
    static final String ITEM_ID = "item_id";
    static final String ITEM_NAME = "item_name";
    static final String ITEM_CHECKED ="item_checked";
    ListView mListView;
    
    ArrayList<HashMap<String, Object>> mDataList = new ArrayList<>();
    ArrayAdapter<HashMap<String, Object>> mArrayAdapter;
    
    @Override
    protected void onCreate(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 = new HashMap<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 = new ArrayAdapter<HashMap<String, Object>>(getApplicationContext(), R.layout.custom_list_items, mDataList){
            class ViewHolder{
                CheckBox cb;
                TextView tvId;
                TextView tvDescription;
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder holder;
                // Prepare views ready for data
                if(convertView == null){
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.custom_list_items, parent, false);
                    holder = new ViewHolder();
                    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(new OnClickListener(){
                        @Override
                        public void onClick(View view) {
                            // Get view, position and DataList(position)
                            CheckBox buttonView = (CheckBox) view;
                            int pos = (int) buttonView.getTag();
                            HashMap<String, Object> selectedItem = new HashMap<String, Object>();
                            selectedItem = getItem(pos);
    
                            // Update DataList
                            remove(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 by
                            notifyDataSetChanged();
                            // 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 DataList
                HashMap<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;
            }
            private void toggleLineThrough(TextView tasksTitle, String title, boolean completed){
                SpannableString styledString = new SpannableString(title);
                if(completed == true){
                    styledString.setSpan(new StrikethroughSpan(), 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!

    0 讨论(0)
提交回复
热议问题