我为listview创建了一个自定义适配器,可以扩展自定义视图,并允许用户过滤列表。
这一切都运行正常,但问题是我在listview项目中放置的图标没有跟随过滤后的数据。
请注意,图标不会更改位置,但会正确过滤名称。
这是我的自定义适配器,可以完成自定义列表视图
我正在使用Mono所以它是用C#编写的,但希望你们java的人能够告诉我在这里做的事情......
/// <summary>
/// ArrayAdapter to handle displaying student with risk indicator
/// </summary>
private class StudentListAdapter : ArrayAdapter<Student>
{
private IList<Student> items;
private Context outer_context;
public StudentListAdapter(Context context, int resource, int textViewResourceId, IList<Student> items)
: base(context, resource, textViewResourceId, items)
{
this.items = items;
this.outer_context = context;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
LayoutInflater vi = (LayoutInflater)outer_context.GetSystemService(Context.LayoutInflaterService);
View tmpView = vi.Inflate(Resource.Layout.ItemStudent, null);
// call base.GetView that uses Object.ToString() to keep sorting intact
View v = base.GetView(position, tmpView, parent);
Student s = items[position];
if (s != null)
{
// determine correct risk image
ImageView listRisk = v.FindViewById<ImageView>(Resource.Id.listRisk);
if (s.R != null)
{
switch ((int)s.R.Value)
{
case 1:
listRisk.SetImageResource(Resource.Drawable.risk_green);
break;
case 0:
listRisk.SetImageResource(Resource.Drawable.risk_yellow);
break;
case -1:
listRisk.SetImageResource(Resource.Drawable.risk_red);
break;
case -2:
listRisk.SetImageResource(Resource.Drawable.risk_red2);
break;
default:
listRisk.SetImageResource(Resource.Drawable.risk_gray);
break;
}
}
else
{
listRisk.SetImageResource(Resource.Drawable.risk_gray);
}
}
return v;
}
}
更新
经过一些断点和检查后,我发现当列表过滤后,它会在过滤之前重建整个列表
例如,当在过滤字段中输入一个字母时,通过GetView()过程运行的第一个学生(s
)是Heath, Ackerson
,这是该列表中的第一个学生,即使是过滤器与他不匹配。
所以,似乎过滤是在GetView运行之后进行的,将图像留在原地......仍然不确定如何解决它..
*完整解决方案*
http://jondavidjohn.com/blog/2011/08/android-custom-listview-filtering
答案 0 :(得分:2)
我会做以下事情: 将EditText和ListView放在您的布局中。 使用BaseAdapter而不是ArrayAdapter。实际上它是一样的,但我不调用base.getView():
private class StudentListAdapter : BaseAdapter
{
private IList<Student> items;
private Context outer_context;
public StudentListAdapter(Context context, IList<Student> items)
{
this.items = items;
this.outer_context = context;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
LayoutInflater vi = (LayoutInflater)outer_context.GetSystemService(Context.LayoutInflaterService);
View v = vi.Inflate(Resource.Layout.ItemStudent, null);
Student s = items[position];
v.FindViewById<TextView>(R.id.text_view_id).setText(s.Name);
// determine correct risk image
ImageView listRisk = v.FindViewById<ImageView>(Resource.Id.listRisk);
if (s.R != null)
{
switch ((int)s.R.Value)
{
case 1:
listRisk.SetImageResource(Resource.Drawable.risk_green);
break;
case 0:
listRisk.SetImageResource(Resource.Drawable.risk_yellow);
break;
case -1:
listRisk.SetImageResource(Resource.Drawable.risk_red);
break;
case -2:
listRisk.SetImageResource(Resource.Drawable.risk_red2);
break;
default:
listRisk.SetImageResource(Resource.Drawable.risk_gray);
break;
}
}
else
{
listRisk.SetImageResource(Resource.Drawable.risk_gray);
}
return v;
}
void displayNewData(IList<Student> new_items)
{
items=new_items;
notifyDatasetChanged();
}
}
因此,当更改过滤器文本时,您只需使用displayNewData()方法将新数据放入适配器:
public class StudentsActivity extends Activity {
public override void onCreate(Bundle savedInstanceState)
{
...
filterEditText.addTextChangedListener(filterTextWatcher);
}
private TextWatcher filterTextWatcher = new TextWatcher()
{
public void afterTextChanged(Editable s) {}
public void beforeTextChanged(CharSequence s, int start, int count,int after) {}
public void onTextChanged(CharSequence filter, int start, int before, int count)
{
IList<Student> items = getStudentsFiltered(filter);
adapter.displayNewData(items);
}
};
//getStudentsFiltered() method may look like that:
getStudentsFiltered(String filter)
{
IList<Student> students_filtered=new List<Students>();
foreach(Student student in students)
if(student.Name.Contains(filter))
students_filtered.Add(student);
return students_filtered;
}
}
我很确定这种方法可行。随意提出任何问题。
我没有编译代码,所以可能会有一些小错误。
答案 1 :(得分:0)
尝试实例化ImageView listRisk = v.FindViewById<ImageView>(Resource.Id.listRisk)
,然后在每种情况下设置资源。
答案 2 :(得分:0)
检查tmpView和v。我没有Mono的东西,所以我看不到ArrayAdapter&lt;&gt;的实现。
我已经看到问题出现了,因为我的观点最终会在我填充人口之前添加到父级。 GetView()的默认实现将视图添加到父级并返回父级,而不是新增的视图。在父对象上执行findViewById()总是返回相同的ImageView(可能是列表中的第一个),而不是我新增加的视图中的ImageView。
如果是这种情况,请不要将父级传递给base.GetView(),而是传递null。在GetView()实现结束时将新增加的视图添加到父级。
答案 3 :(得分:0)
我注意到的一件事(使用Java而不是Mono进行编码)是,如果你尝试做这样的事情:
imageView.setImageResource(R.myResourceID1);
imageView.setImageResource(R.myResourceID2);
显示的图像始终为myResourceID1。为了解决这个问题,当我想设置一个已设置的imageView资源时,我合作的人建议使用此代码。所以:
imageView.setImageResource(R.myResourceID1);
imageView.setImageResource(0); //supposedly invalidates the image resource
imageView.setImageResource(R.myResourceID2);
虽然在阅读完更新后,似乎如果您在getView()方法中设置imageViews后进行过滤,那么这可能不是您的问题。以为我会分享,因为第二次通过getView()设置已经使用过的imageView资源听起来像我上面描述的问题。