Spannable String 仅适用于 ListView 中的最后一项
Posted
技术标签:
【中文标题】Spannable String 仅适用于 ListView 中的最后一项【英文标题】:Spannable String only working for last Item in ListView 【发布时间】:2017-02-16 23:49:47 【问题描述】:编辑:
我现在可以在列表视图中敲击单词,但只能从底部向上敲击,之后只能取消敲击底部的项目。代码如下。
@Override
public View getView(int position, View convertView, ViewGroup parent)
final SubTask subTask = getItem(position);
if(convertView == null)
convertView = LayoutInflater.from(getContext()).inflate(R.layout.subtask_adapter_list, parent, false);
final TextView tasksTitle = (TextView)convertView.findViewById(R.id.tasksName);
tasksTitle.setTypeface(typeface);
completed = (CheckBox)convertView.findViewById(R.id.completed);
changeColor();
tasksTitle.setText(subTask.getSubTask());
completed.setChecked(subTask.isCompleted());
toggleLineThrough(tasksTitle, tasksTitle.getText().toString(), subTask.getSubTask(), completed.isChecked());
completed.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
if(completed.isChecked())
subTask.setCompleted(true);
subTask.save();
toggleLineThrough(tasksTitle, tasksTitle.getText().toString(), subTask.getSubTask(), completed.isChecked());
else
subTask.setCompleted(false);
subTask.save();
toggleLineThrough(tasksTitle, tasksTitle.getText().toString(), subTask.getSubTask(), completed.isChecked());
);
return convertView;
private void toggleLineThrough(TextView tasksTitle, String title, String oldTitle, boolean completed)
SpannableString styledString = new SpannableString(title);
if(completed == true)
styledString.setSpan(new StrikethroughSpan(), 0, title.length(), 0);
tasksTitle.setText(styledString);
else
tasksTitle.setText(oldTitle);
如果满足条件,我正试图让罢工跨越 TextView。从逻辑上讲,它有效,但仅适用于 ListView 中的最后一项。所有其他项目似乎根本没有造成罢工。我的代码如下:
@Override
public View getView(int position, View convertView, ViewGroup parent)
subTask = getItem(position);
if(convertView == null)
convertView = LayoutInflater.from(getContext()).inflate(R.layout.subtask_adapter_list, parent, false);
tasksTitle = (TextView)convertView.findViewById(R.id.tasksName);
tasksTitle.setTypeface(typeface);
completed = (CheckBox)convertView.findViewById(R.id.completed);
changeColor();
tasksTitle.setText(subTask.getSubTask());
toggleLineThrough(subTask.getSubTask());
completed.setChecked(subTask.isCompleted());
completed.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
if(completed.isChecked())
subTask.setCompleted(true);
subTask.save();
toggleLineThrough(subTask.getSubTask());
else
subTask.setCompleted(false);
subTask.save();
toggleLineThrough(subTask.getSubTask());
);
return convertView;
private void toggleLineThrough(String text)
SpannableString styledString = new SpannableString(text);
if(completed.isChecked())
styledString.setSpan(new StrikethroughSpan(), 0, text.length(), 0);
tasksTitle.setText(styledString);
else
tasksTitle.setText(text);
我似乎无法让罢工为他们所有人服务。我也尝试使用具有相同结果的 Paint Flags 方式(甚至完全隐藏我的 TextView)。非常感谢在 ListView 中为我的 TextViews 使用 Spannable String 的任何帮助。
【问题讨论】:
【参考方案1】:您也应该将检查状态和tasksTitle
传递给toggleLineThrough()
。
变量 completed
和 tasksTitle
包含错误值,因为 onClickListener 的调用晚于 getView()
。它们被getView()
的连续调用多次覆盖。
【讨论】:
啊谢谢!!我现在就去那里。谢谢谢尔盖。 所以我也尝试将这两个传递到函数中,除非我做错了,否则似乎已经完成了一半。如果我从下往上开始,我只能让所有项目的文本都被删除。但那之后我只能触底吗?我将编辑上面的代码。【参考方案2】:@SmiffyKmc,我正在尝试使用以下内容来回答其他类似的问题,因此某些 cmets 可能与您的问题无关。
在这里制作了一个完整的示例:
在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_
android:layout_
tools:context="$relativePackage.$activityClass" >
<ListView
android:id="@+id/listView1"
android:layout_
android:layout_
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_
android:layout_
android:orientation="horizontal"
android:paddingBottom="20dp"
android:paddingTop="20dp" >
<CheckBox
android:id="@+id/cb"
android:layout_
android:layout_
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:focusable="false" />
<TextView
android:id="@+id/tvId"
android:layout_
android:layout_
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_
android:layout_
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);
一些要点:
-
保持CheckBox的状态作为数据列表中的一个字段,并相应设置UI,否则ListView滚动后会出错。
getView() 在 ListView 显示时结束。 OnClickListener 不应该使用从 getView() 获得的数据。
OnClickListener 应该能够并且需要从数据列表中获取数据。最简单的方法可能是:“getView() 中的 View.setTag(position),OnClickListener() 中的 View.getTag()”。
不要只修改视图。更改数据,先列出数据。然后调用 notifyDataSetChanged()。如果只是对 UI 进行小改动,可以直接做,但应该和调用 notifyDataSetChanged() 一样。
希望有所帮助!
【讨论】:
非常感谢您的意见!我还没有机会解决它,但我会试一试,然后回复你。谢谢:)以上是关于Spannable String 仅适用于 ListView 中的最后一项的主要内容,如果未能解决你的问题,请参考以下文章
将 Spannable 与 String.format() 结合使用
java [Spannable String] #android_snippet #android
我可以在 android 中将 Spannable 转换为 String 以加载 ExpandableListView 吗?
从/向本机插件传递 wchar_t 字符串 - 仅适用于 Windows?