当前位置: 首页 > 知识库问答 >
问题:

使用微调器从自定义listview中删除了错误的行

韦原
2023-03-14

我正在开发一个应用程序,它包含一个自定义列表视图,带有一个删除按钮,我可以从主活动中更新该按钮。

从ListView中删除一行时遇到问题,尽管我正在从自定义列表视图中删除正确的索引,并调用notifyDataChanged()方法,但GUI无法正确更新。

在这里,我写了一个示例项目,就像我在idea中的真实项目,只是更多示例:

  • 主要活动。xml(主布局)只包含名为ListView的ListView

MainActivity.java:

public class MainActivity extends Activity {
    ListView listView;
    listviewAdapter adapter;
    ArrayList<Student> students = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String[] names = new String[]{"Tom", "Ben", "Gil", "Adam", "Moshe", "Adi", "Michael", "Yasmin", "Jessica", "Caroline", "Avi", "Yael"};

        students.add(new Student());
        students.add(new Student());
        students.add(new Student());

        adapter = new listviewAdapter(this, students, names);
        listView = (ListView) findViewById(R.id.listView);
        listView.setAdapter(adapter);

    }

    public void updateStatus(int position)
    {
        View convertView = listView.getChildAt(position - listView.getFirstVisiblePosition());
        TextView tvValue = (TextView) convertView.findViewById(R.id.tv_Value);
        Spinner spName = (Spinner) convertView.findViewById(R.id.spNames);
        Spinner spGrade = (Spinner) convertView.findViewById(R.id.spGrades);

        tvValue.setText(spName.getSelectedItem().toString() + " got " + spGrade.getSelectedItem().toString());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_Add)
        {
            students.add(new Student());
            adapter.notifyDataSetChanged();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

listviewAdapter。JAVA

public class listviewAdapter extends BaseAdapter
{
    public Activity context;
    public LayoutInflater inflater;

    private ArrayList<Student> studentID;
    private String[] studentsNames;

    public listviewAdapter(Activity context, ArrayList<Student> students, String[] names)
    {
        super();
        studentID = students;
        studentsNames = names;

        this.context = context;
        this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return studentID.size();
    }

    @Override
    public Object getItem(int position) {
        return studentID.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }


    @Override
    public int getViewTypeCount() {
        return studentID.size() + 1;
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }

    public class ViewHolder {
        Spinner spNames, spGrades;
        TextView tvValue;
        Button btnSet, btnRemove;
    }

    @Override
    public View getView(int i, View view, final ViewGroup viewGroup)
    {
        final ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.listview_row, null);

            holder.spNames = (Spinner) view.findViewById(R.id.spNames);
            holder.spGrades = (Spinner) view.findViewById(R.id.spGrades);
            holder.tvValue = (TextView) view.findViewById(R.id.tv_Value);
            holder.btnSet = (Button) view.findViewById(R.id.btn_setValue);
            holder.btnRemove = (Button) view.findViewById(R.id.btn_Remove);
            view.setTag(holder);
            holder.spNames.setTag(0);
            holder.spGrades.setTag(0);
        }
        else{
            holder = (ViewHolder) view.getTag();
        }

        // pop spinner names
        ArrayAdapter<String> studentsNamesAdapater = new ArrayAdapter<>
                (view.getContext(), android.R.layout.simple_spinner_dropdown_item, studentsNames);
        studentsNamesAdapater.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        holder.spNames.setAdapter(studentsNamesAdapater);

        // pop spinner grades
        String[] grades = new String[101];
        for (int grade = 0; grade < 101; grade++)
            grades[grade] = String.valueOf(grade);

        final ArrayAdapter<String> studentsGradesAdapter = new ArrayAdapter<>
                (view.getContext(), android.R.layout.simple_spinner_dropdown_item, grades);
        studentsGradesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        holder.spGrades.setAdapter(studentsGradesAdapter);


        // select the right spNames index
        holder.spNames.setSelection((Integer) holder.spNames.getTag());
        // saving spinner index
        holder.spNames.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                holder.spNames.setTag(position);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

        // select the right spGrades index
        holder.spGrades.setSelection((Integer) holder.spGrades.getTag());
        // saving spinner index
        holder.spGrades.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                holder.spGrades.setTag(position);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

        // set (variable and textview)
        holder.btnSet.setTag(i);
        holder.btnSet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // update studentID
                int position = (Integer) v.getTag();
                Student tmp = new Student(holder.spNames.getSelectedItem().toString(), Integer.valueOf(holder.spGrades.getSelectedItem().toString()));
                studentID.set(position, tmp);
                ((MainActivity) context).updateStatus(position);
            }
        });


        // remove row
        holder.btnRemove.setTag(i);
        holder.btnRemove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = (Integer) v.getTag();
                studentID.remove(position);
                //notifyDataSetChanged();
                ((MainActivity) context).adapter.notifyDataSetChanged();

                // for debug
                String dStatus = "Vector size: " + studentID.size() + "\n";
                for (int index = 0; index < studentID.size(); index++)
                    dStatus += studentID.get(index).name + " " + studentID.get(index).grade + "\n";
                Toast.makeText(v.getContext(), dStatus, Toast.LENGTH_SHORT).show();
            }
        });

        return view;
    }
}

我的问题是图形用户界面没有正确更新,图形用户界面上被删除的项目仍然出现在屏幕上,如下所示:

有人能告诉我如何从GUI中删除正确的行吗?

编辑

  1. 我更新我的listview适配器,并使用标签,你回答我,不工作。
  2. 当我试图在删除一个学生后添加学生时,我也发现了奇怪的问题。出于某种原因,它“记住”最后一个学生,并返回他完整的数据,正如你在更新图片中看到的。

编辑

如果有人想尝试,我添加学生类和XML源:

Student.java

public class Student
{
    public String name;
    public int grade;

    public Student()
    {
        name = "";
        grade = 0;
    }

    public Student(String _name, int _grade)
    {
        name = _name;
        grade = _grade;
    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/listView"
        android:layout_gravity="center_horizontal"
        android:dividerHeight="2dp" />
</LinearLayout>

listview_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#c4e0ff">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Spinner
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/spNames" />

        <Spinner
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:id="@+id/spGrades"
            android:layout_marginLeft="10dp" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Set Value"
            android:id="@+id/btn_setValue" />
    </LinearLayout>

    <LinearLayout
        android:orientation="horizontal"
        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/tv_Value" />

        <Button
            style="?android:attr/buttonStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Remove"
            android:id="@+id/btn_Remove"
            android:layout_marginLeft="30dp" />

    </LinearLayout>

</LinearLayout>

共有3个答案

法和安
2023-03-14

基本上,这个问题是由于视图回收而发生的。将这两个方法添加到适配器类中

 @Override
 public int getViewTypeCount() {
     return studentID.size() + 1;
 }

 @Override
 public int getItemViewType(int position) {
     return position;
 }

下面的链接解释了为什么要添加这两种方法。通过列表视图检查动态生成的复选框时出现问题

我希望有帮助!

宗安翔
2023-03-14

我建议您在列表视图中使用setOnItemClickListener方法。有一些优点:

  • 您不必在每次呈现项目时创建新的OnClickListener
  • 您可以直接访问视图的位置和视图本身:onItemClick(AdapterView

然后,您可以使用该位置从适配器中移除项目。

濮阳国兴
2023-03-14

问题在于

holder.spNames.setTag(position); 

holder.spNames.setSelection((Integer) holder.spNames.getTag());

在“onItemSelected()”中为name设置标记时。当你删除该项目时,你会从学生列表中删除该项目,但是标签呢。

假设您在0处删除了该项目。

现在,当调用“notifyDataSetChanged()”时,它将根据可用的数据重新填充listview。现在,在这里

else{
        holder = (ViewHolder) view.getTag();
    }

正在被调用。当getView()中的i=0时,您将获得前一个填充列表的第0个索引的视图。因此,“(整数)holder.spNames.get标签()”将指向前一个标签(即前一个列表的0)。这可能是问题的原因。

我正在发布更新的代码

listviewAdapter

public class ListviewAdapter extends BaseAdapter
{
public Activity context;
public LayoutInflater inflater;
private ArrayList<Student> studentID;
private String[] studentsNames;
private boolean isDeleted;
public ListviewAdapter(Activity context, ArrayList<Student> students, String[] names)
{
    super();
    studentID = students;
    studentsNames = names;

    this.context = context;
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public int getCount() {
    return studentID.size();
}

@Override
public Student getItem(int position) {
    return studentID.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}




public class ViewHolder {
    Spinner spNames, spGrades;
    TextView tvValue;
    Button btnSet, btnRemove;
    int index;
}

@Override
public View getView(int i, View view, final ViewGroup viewGroup)
{
    final ViewHolder holder;
    if (view == null) {
        holder = new ViewHolder();
        view = inflater.inflate(R.layout.listview_row, null);

        holder.spNames = (Spinner) view.findViewById(R.id.spNames);
        holder.spGrades = (Spinner) view.findViewById(R.id.spGrades);
        holder.tvValue = (TextView) view.findViewById(R.id.tv_Value);
        holder.btnSet = (Button) view.findViewById(R.id.btn_setValue);
        holder.btnRemove = (Button) view.findViewById(R.id.btn_Remove);
        Log.e("IAM", "CALLED");
        view.setTag(holder);
        //holder.spNames.setTag(0);
        //holder.spGrades.setTag(0);
    }
    else{
        holder = (ViewHolder) view.getTag();
    }
    holder.index=i;
   if(isDeleted){
       holder.tvValue.setText(getItem(holder.index).getName()+ " got " + getItem(holder.index).getGrade()); 
            }
    // pop spinner names
    ArrayAdapter<String> studentsNamesAdapater = new ArrayAdapter<String>
            (view.getContext(), android.R.layout.simple_spinner_dropdown_item, studentsNames);
    studentsNamesAdapater.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    holder.spNames.setAdapter(studentsNamesAdapater);

    // pop spinner grades
    String[] grades = new String[101];
    for (int grade = 0; grade < 101; grade++)
        grades[grade] = String.valueOf(grade);

    final ArrayAdapter<String> studentsGradesAdapter = new ArrayAdapter<String>
            (view.getContext(), android.R.layout.simple_spinner_dropdown_item, grades);
    studentsGradesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    holder.spGrades.setAdapter(studentsGradesAdapter);


    // select the right spNames index
    //holder.spNames.setSelection((Integer) holder.spNames.getTag());
    holder.spNames.setSelection(getItem(holder.index).getNameIndex());
    // saving spinner index
    holder.spNames.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            //holder.spNames.setTag(position);
            getItem(holder.index).setNameIndex(position);
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    });

    // select the right spGrades index
   // holder.spGrades.setSelection((Integer) holder.spGrades.getTag());

    holder.spGrades.setSelection(getItem(holder.index).getGrageIndex());
    // saving spinner index
    holder.spGrades.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
           // holder.spGrades.setTag(position);
            getItem(holder.index).setGrageIndex(position);
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    });

    // set (variable and textview)
    holder.btnSet.setTag(i);
    holder.btnSet.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // update studentID
            //final int position = getRowPosition(v);
            int position = (Integer) v.getTag();
           // Student tmp = new Student(holder.spNames.getSelectedItem().toString(), Integer.valueOf(holder.spGrades.getSelectedItem().toString()));
           // studentID.set(position, tmp);
            getItem(position).setName(holder.spNames.getSelectedItem().toString());
            getItem(position).setGrade(Integer.valueOf(holder.spGrades.getSelectedItem().toString()));
            holder.tvValue.setText(getItem(position).getName()+ " got " + getItem(position).getGrade());
            //((MainActivity) context).updateStatus(position);
        }
    });


    // remove row
    holder.btnRemove.setTag(i);
    holder.btnRemove.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //final int position = getRowPosition(v);
            int position = (Integer) v.getTag();
            studentID.remove(position);
            notifyDataSetChanged();
            //((MainActivity) context).adapter.notifyDataSetChanged();
            isDeleted=true;
            // for debug
            String dStatus = "Vector size: " + studentID.size() + "\n";
            for (int index = 0; index < studentID.size(); index++)
                dStatus += studentID.get(index).name + " " + studentID.get(index).grade + "\n";
            Toast.makeText(v.getContext(), dStatus, Toast.LENGTH_SHORT).show();
        }
    });

    return view;
}

public void printS() {
    for (int i = 0; i <studentID.size(); i++) {
        Log.e("NAME", ""+studentID.get(i).getName());
        Log.e("GRADE", ""+studentID.get(i).getGrade());
    }
}
}

学生

public class Student {
public String name;
public int grade;
private int nameIndex;
private int grageIndex;

public Student()
{
    name = "";
    grade = 0;
}

public Student(String _name, int _grade)
{
    name = _name;
    grade = _grade;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getGrade() {
    return grade;
}

public void setGrade(int grade) {
    this.grade = grade;
}

public int getNameIndex() {
    return nameIndex;
}

public void setNameIndex(int nameIndex) {
    this.nameIndex = nameIndex;
}

public int getGrageIndex() {
    return grageIndex;
}

public void setGrageIndex(int grageIndex) {
    this.grageIndex = grageIndex;
}
}
 类似资料:
  • 我通过SDK成功地创建了一个自定义度量,但无法删除它我无法从web控制台找到删除它的选项(从SDK中也无法找到删除/取消它的方法) 它创建了一个名为“MyCompany/MyResources”的度量,但我无法删除它

  • 我对下面的Java程序有问题。我在Ubuntu系统上使用带有JDK-1.8u25的JavaFX。我想显示一个ListView,并从列表中删除突出显示的条目。我创建了一个列表,并将其与一个可观察列表配对,以通知侦听器事件。然而,通过删除下面的“orderOvList.remove(i,i 1)”项来更改列表似乎会生成另一个侦听器事件。所以,我似乎在侦听器代码的主体中递归。我想过将list元素从nor

  • 我很难从自定义对象的ArrayList中删除重复项。 删除重复项 自定义对象等于() 删除重复项后的输出 关于为什么它实际上没有删除重复项,有什么提示吗?或者它实际上是通过将副本替换为原始副本来删除副本?不知道这里发生了什么。

  • 我有一个JTable,其中添加了一个JButton(Delete button)和一个JComboBox作为两列上的自定义单元格编辑器。现在,当我在组合框中选择一个项目并单击Delete按钮时,所选行被删除,但已删除行的组合框在该行上呈现。我是否也必须从表中删除单元编辑器。如果我不选择我的组合框,代码就可以正常工作。请帮帮我。 我的代码是这样的:- 我在main中实例化了我的类的一个对象,然后单击

  • 我已经在TestCase下创建了一些属性列表。例如,看下面的截图。 我试图通过以下groovy脚本teststep删除Testcase_Property属性: 当我重新加载项目时,当我单击测试用例名称时,Testcase_Property属性仍然存在于Custom Properties选项卡中。 谢谢 卡鲁纳加拉·潘迪

  • 我使用下面的布局实现了一个加载微调器图标: 但这使用默认的Android微调器。我想用我从preloaders.net得到的加载图标来替换微调器,如下所示: 如何用此自定义微调器替换默认的Android微调器?