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:
- Keep state of the CheckBox as a field in data list and setup UI accordingly, otherwise ListView will be wrong after scroll.
- getView() is over when the ListView is shown. OnClickListener SHOULD NOT use the data obtained from getView().
- 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()".
- 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"