我试图制作一个简单的待办事项列表,您可以长按一个项目将其标记为“已完成”,在这种情况下,它将显示为灰色且删除线。
我首先处理删除线,并在此处找到了一些示例代码creating a strikethrough text in Android?。但是问题是setPaintFlags()方法似乎只在TextView上工作,而我列表中的项目是String。我无法将一个字符串转换为TextView,我在这里找到了一个解决方法,但显然我们非常劝阻它:Cast String to TextView。我也查了一下SpannableString,但它似乎不适用于不同长度的字符串。
所以我回到第一个方面 - 是否有可能实现我想做的事情?或者我是否必须以不同方式存储我的列表项?
相关代码:
public class MainActivity extends ActionBarActivity {
private ArrayList<String> items;
private ArrayAdapter<String> itemsAdapter;
private ListView lvItems;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Setting what the ListView will consist of
lvItems = (ListView) findViewById(R.id.lvItems);
readItems();
itemsAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items);
lvItems.setAdapter(itemsAdapter);
// Set up remove listener method call
setupListViewListener();
}
//Attaches a long click listener to the listview
private void setupListViewListener() {
lvItems.setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapter,
View item, int pos, long id) {
// Trying to make the onLongClick strikethrough the text
String clickedItem = items.get(pos);
//What do I do here??
// Refresh the adapter
itemsAdapter.notifyDataSetChanged();
writeItems();
// Return true consumes the long click event (marks it handled)
return true;
}
});
}
答案 0 :(得分:3)
让我们退后一步,考虑一下您的应用。您想要向用户显示作业列表。每个工作都有描述。每项工作都有两种可能的状态:&#39;已完成&#39;或者&#39;没有完成&#39;。
所以我想介绍一个课程&#39; Job&#39;
class Job
{
private String mDescription;
private boolean mDone;
public Job(String description)
{
this.mDescription = description;
this.mDone = false;
}
// ... generate the usual getters and setters here ;-)
// especially:
public boolean isDone()
{
return mIsDone;
}
}
这样你的ArrayList&#39; items&#39;成为ArrayList< Job >
。工作完成与否将与其描述一起存储。这很重要,因为您希望通过更改UI元素的外观向用户显示作业的当前状态,但您还需要在数据级别上跟踪作业的状态。
UI元素 - TextView
- 将配置为向用户显示有关作业的信息。一条信息是描述。 TextView
会将其存储为String
。另一条信息是状态(已完成/未完成)。 TextView
将(在您的应用中)通过设置删除标记并更改其颜色来存储它。
由于性能原因,ListView
使用的元素少于数据列表(&#39; items&#39;)所包含的元素,因此您必须编写自定义适配器。为了简洁起见,我保持代码非常简单,但是值得花时间阅读View Holder模式:
让我们使用布局文件&#39; mytextviewlayout.xml&#39;对于列表行:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="@+id/textView"/>
</LinearLayout>
现在适配器的代码如下所示:
编辑从ArrayAdapter更改为BaseAdapter并添加了一个视图持有者(请参阅注释):
public class MyAdapter extends BaseAdapter
{
private ArrayList<Job> mDatalist;
private int mLayoutID;
private Activity mCtx;
private MyAdapter(){} // the adapter won't work with the standard constructor
public MyAdapter(Activity context, int resource, ArrayList<Job> objects)
{
super();
mLayoutID = resource;
mDatalist = objects;
mCtx = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = mCtx.getLayoutInflater();
rowView = inflater.inflate(mLayoutID, null);
ViewHolder viewHolder = new ViewHolder();
viewHolder.tvDescription = (TextView) rowView.findViewById(R.id.textView);
rowView.setTag(viewHolder);
}
ViewHolder vholder = (ViewHolder) rowView.getTag();
TextView tvJob = vholder.tvDescription;
Job myJob = mDatalist.get(position);
tvJob.setText(myJob.getJobDescription());
if (myJob.isDone())
{
// apply changes to TextView
tvJob.setPaintFlags(tvJob.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
tvJob.setTextColor(Color.GRAY);
}
else
{
// show TextView as usual
tvJob.setPaintFlags(tvJob.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
tvJob.setTextColor(Color.BLACK); // or whatever is needed...
}
return rowView;
}
@Override
public int getCount()
{
return mDatalist.size();
}
@Override
public Object getItem(int position)
{
return mDatalist.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
static class ViewHolder
{
public TextView tvDescription;
}
}
由于更改了适配器,
在MainActivity中,您必须声明&#39;项目&#39;和&#39; itemsAdapter&#39;如下:private ArrayList<Job> items;
private MyAdapter itemsAdapter;
...并且在你的'onCreate()&#39;方法,你写:
itemsAdapter = new MyAdapter<String>(this, R.layout.mytextviewlayout, items);
不要忘记更改&#39; readItems()&#39;和&#39; writeItems()&#39;方法因为&#39;项目&#39;现在是ArrayList< Job >
。
然后,最后,&#39; onItemLongClick()&#39;方法:
编辑使用&#39; parent.getItemAtPosition()&#39;而不是&#39; items.get()&#39;,请参阅评论
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
{
// items.get(position).setDone(true);
Object o = parent.getItemAtPosition(position);
if (o instanceof Job)
{
((Job) o).setDone(true);
}
// and now indeed the data set has changed :)
itemsAdapter.notifyDataSetChanged();
writeItems();
return true;
}