【发布时间】:2014-01-22 16:02:47
【问题描述】:
我正在开发一个家庭作业计划器应用程序,并且我正在寻找一种方法来仅显示包含 Task 对象的 ArrayList 中的某些元素。用户从课程标题列表中单击课程后,应显示与该课程相关的任务列表。目前,它显示所有任务的列表,无论选择了哪个课程。每个 Task 对象都将其所属的课程存储在名为 mBelongsToCourse 的字段中。我在我的 TaskAdapter 中创建了一个过滤器来按课程名称进行过滤,但我不知道在哪里调用它才能使它工作。我已经在这里广泛搜索了这个问题的答案,但是在任何人过滤 ArrayAdapter 的情况下,过滤器似乎都在响应一些用户输入,例如搜索。在我的例子中,当用户选择一门课程时,用户输入只是课程名称的额外意图,它启动了显示我的 TaskListFragment 的意图,但应该只显示该课程的任务。
下面是我的TaskListFragment 类,其中包括TaskAdapter 和TaskFilter:
public class TaskListFragment extends ListFragment {
private ArrayList<Task> mTasks;
private static String courseName;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
courseName = getActivity().getIntent().getStringExtra("name");
getActivity().setTitle(courseName);
mTasks = TaskLab.get(getActivity()).getTasks();
TaskAdapter adapter = new TaskAdapter(mTasks);
setListAdapter(adapter);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
//Get the Task from the adapter
Task t = ((TaskAdapter)getListAdapter()).getItem(position);
// Start TaskActivity with this task
//Intent i = new Intent(getActivity(), TaskPagerActivity.class);
Intent i = new Intent(getActivity(), TaskActivity.class);
i.putExtra(TaskFragment.EXTRA_TASK_ID, t.getId());
startActivity(i);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_task_list, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_task:
Task task = new Task();
task.setBelongsToCourse(courseName);
Log.d("yoyo", "belongsToCourse was set as: " + task.getBelongsToCourse());
TaskLab.get(getActivity()).addTask(task);
Intent i = new Intent(getActivity(), TaskActivity.class);
i.putExtra(TaskFragment.EXTRA_TASK_ID, task.getId());
startActivityForResult(i, 0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
getActivity().getMenuInflater().inflate(R.menu.task_list_item_context, menu);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = super.onCreateView(inflater, parent, savedInstanceState);
ListView listView = (ListView)v.findViewById(android.R.id.list);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
// Required, but not used in this implementation
}
// ActionMode.Callback methods
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.task_list_item_context, menu);
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
// Required, but not used in this implementation
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_delete_task:
TaskAdapter adapter = (TaskAdapter)getListAdapter();
TaskLab taskLab = TaskLab.get(getActivity());
for (int i = adapter.getCount() - 1; i >= 0; i--) {
if (getListView().isItemChecked(i)) {
taskLab.deleteTask(adapter.getItem(i));
}
}
mode.finish();
adapter.notifyDataSetChanged();
return true;
default:
return false;
}
}
public void onDestroyActionMode(ActionMode mode) {
// Required, but not used in this implementation
}
});
return v;
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
int position = info.position;
TaskAdapter adapter = (TaskAdapter)getListAdapter();
Task task = adapter.getItem(position);
switch (item.getItemId()) {
case R.id.menu_item_delete_task:
TaskLab.get(getActivity()).deleteTask(task);
adapter.notifyDataSetChanged();
return true;
}
return super.onContextItemSelected(item);
}
@Override
public void onResume() {
super.onResume();
((TaskAdapter)getListAdapter()).notifyDataSetChanged();
}
private class TaskAdapter extends ArrayAdapter<Task> implements Filterable {
private ArrayList<Task> taskList;
private Filter taskFilter;
public TaskAdapter(ArrayList<Task> tasks) {
super(getActivity(), 0, tasks);
this.taskList = tasks;
this.taskFilter = new TaskFilter();
getFilter().filter(courseName);
notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// If we weren't given a view, inflate one
if (convertView == null) {
convertView = getActivity().getLayoutInflater()
.inflate(R.layout.list_item_task, null);
}
// Configure the view for this Task
Task t = getItem(position);
TextView titleTextView =
(TextView)convertView.findViewById(R.id.task_list_item_titleTextView);
titleTextView.setText(t.getTitle());
TextView dateTextView =
(TextView)convertView.findViewById(R.id.task_list_item_dateTextView);
dateTextView.setText(t.getDate().toString());
CheckBox completedCheckBox =
(CheckBox)convertView.findViewById(R.id.task_list_item_completedCheckBox);
completedCheckBox.setChecked(t.isCompleted());
return convertView;
}
@Override
public Filter getFilter() {
if (taskFilter == null)
taskFilter = new TaskFilter();
return taskFilter;
}
private class TaskFilter extends Filter {
@Override
protected FilterResults performFiltering (CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint == null | constraint.length() == 0) {
results.values = taskList;
results.count = taskList.size();
} else {
ArrayList<Task> newTaskList = new ArrayList<Task>();
for (Task t : taskList) {
if (t.getBelongsToCourse().toUpperCase().equals(constraint.toString().toUpperCase())) {
newTaskList.add(t);
}
}
results.values = newTaskList;
results.count = newTaskList.size();
} return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
// Now we have to inform the adapter about the new list filtered
if (results.count == 0)
notifyDataSetInvalidated();
else {
taskList = (ArrayList<Task>)results.values;
notifyDataSetChanged();
}
}
}
}
}
任何帮助将不胜感激!我已经尝试解决这个问题太久了,但我仍然完全迷失了。
编辑:我已经删除了与原始过滤器有关的所有内容,而是在我的 TaskAdapter 中使用此方法:
public ArrayList<Task> filterTasks() {
ArrayList<Task> filteredTasks = new ArrayList<Task>();
for (Task t: taskList) {
if (t.getBelongsToCourse().equals(courseName)) {
filteredTasks.add(t);
}
} return filteredTasks;
}
过滤任务。在TaskListFragment的onCreate方法中,我在下面添加了中间一行:
TaskAdapter adapter = new TaskAdapter(mTasks);
adapter.filterTasks();
setListAdapter(adapter);
我还让 LogCat 打印出 filtersTasks 中的任务列表(仍在 onCreate 方法中)。因此,当我单击课程,添加任务,然后返回 TaskListFragment 时,我会打印出属于该课程的任务。每门课程的列表都是分开的!在过去一周试图做到这一点并没有看到任何结果之后,到目前为止,这对我来说是一个很大的进步。尽管如此,我还是在每个课程页面上看到了所有任务,而不是过滤后的任务。这只是我的 listView 没有更新的问题吗?
【问题讨论】:
-
开始显示我的 TaskListFragment 的意图, - 将目标课程发送到您的
TaskListFragment(通过它创建时的 Bundle)并将其传递给TaskAdapter班级。在TaskAdapter的构造函数中,只需过滤任务列表。如果您不想在使用适配器时更改适配器,则不需要实现Filter(这似乎不是您的情况,因为您想在首次显示片段时过滤(仅一次?) )。 -
嗨 Luksprog,非常感谢您的回答!目前,我正在从我的 CourseListFragment 向 TaskListFragment 发送一个额外的意图,这是已单击的课程的名称。所以我也应该把它传递给我的TaskAdapter?目前,由于它们都在同一个类中,因此包含课程名称的字段可以通过 TaskAdapter 访问,并且我尝试直接在构造函数中过滤结果,但是无论如何,我都得到了完整的任务列表当然我点击了。
-
有什么办法可以给我更详细的说明我应该做什么,因为我觉得我必须忽略一些我没有意识到的重要方面,因为我是新手安卓。
-
如果您使用 BaseAdapter(以获得更大的灵活性)有一个过滤系统,您可以覆盖 getFilter() 并实现 Filterable gist.github.com/fjfish/3024308
标签: android android-listview android-arrayadapter android-listfragment android-filterable