ListView过滤器..图像不遵循过滤器

时间:2011-07-26 16:12:54

标签: c# android filter mono android-listview

我为listview创建了一个自定义适配器,可以扩展自定义视图,并允许用户过滤列表。

这一切都运行正常,但问题是我在listview项目中放置的图标没有跟随过滤后的数据。

实施例

No Filtering Correctly Filtering names but not icons

请注意,图标不会更改位置,但会正确过滤名称。

这是我的自定义适配器,可以完成自定义列表视图

我正在使用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

4 个答案:

答案 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资源听起来像我上面描述的问题。