如何在不失去列表项中EditText的焦点的情况下更新ListView?(Android)

3
我有一个ListView,每个条目都包含多个EditText。我正在定义一个比例,因此其中一个EditText依赖于上面一项的EditText。在下面的示例中,当编辑A时,B被设置为与A相同的值。因此,用户实际上不使用右列。
我能够监听A中的事件并更新B,然后相应地调用notifyDataSetChanged(),但是随着ListView的重绘,我失去了我的EditText的焦点。
底线是,我想要的是:编辑字段A,然后当我点击字段C时,我希望A的值应用于B,并且我希望焦点转移到C
最后,我遇到了困难的部分是"焦点转移到C"。

p.s. 实际上还有另一个EditText在行上,因此焦点不会总是移动到具有A和C的列。

编辑:这是我的适配器的getItemId()方法,以帮助回答@aniv的评论。

@Override
    public Object getItem(int arg0) {
        return arg0;
    }

编辑2:在覆盖hasStableIds()以返回true后,当我从A转到另一个项目中的第三列时,它可以很好地工作,但是当我从A转到C时却不行。我认为我的onFocusChange覆盖正在搞砸某些东西,因为它只在该列中更改焦点时表现奇怪(它们共享同一个onFocusChange方法)。这是我的自定义onFocusChangeListener。

private class MyFocusChangeListener implements View.OnFocusChangeListener{
    private EditText et;
      private ScaleItem item;
      private Integer pos;

      private MyFocusChangeListener(ScaleItem item, Integer pos){
          this.item = item;
          this.pos = pos;
      }

      @Override
      public void onFocusChange(View v, boolean hasFocus){
          if(!hasFocus){
              et = (EditText) v;
              Activity_EditCourseGPA a = (Activity_EditCourseGPA) activity;
              a.updateMaxOnTextChange(item, pos, et.getText().toString());
          } else {

          }
      }
}

我在活动中使用的it函数(用于使用EditText字段更新底层数据)....

public void updateMaxOnTextChange(ScaleItem item, Integer pos, String str){
    if(pos < scaleItems.size()){
        scaleItems.get(pos + 1).setMax(Double.valueOf(str));
        scaleListAdapter.notifyDataSetChanged();
    }
}

我使用EditText位置和内容同时更新底层数据的相同位置。以下是在同一列中更改焦点时发生的情况。非常奇怪。
图片描述:输入文本框中输入内容后,再在同一列中移动光标,原来填写的内容被清空了。

你的适配器有稳定的ID吗? - alanv
@alanv hasStableIds() 返回 false。我认为我可以得到一致的 getItemId() 值--我已经在上面发布了我的代码。这是什么意思,它如何影响我正在尝试做的事情? - NSouth
稳定的ID允许ListView在数据集更改后执行布局时重用相同的视图。它还允许尝试保留焦点。尝试覆盖hasStableIds()以返回true。 - alanv
@MSaudi,我最终放弃了ListView并使用了LinearLayouts数组,因为我总是知道确切的行数。由于这个视图是静态而不是动态的,所以焦点表现得更好。 - NSouth
@NSouth 谢谢您的回复。在我的情况下这是不可行的,我仍在努力解决它。这是一个奇怪的问题。 - MSaudi
显示剩余5条评论
1个回答

0
首先,您需要一个自定义类Grade
public class GradeInfo {
  boolean enabled;
  String gpa, perc1, perc2;
}

你需要创建一个 List<GradeInfo> 对象,其中包含一系列的 GradeInfo 对象,每个对象代表一行。你可以在列表视图的适配器中使用这个 List。你的适配器应该像这样:
private class GradeAdap extends BaseAdapter { 

    @Override
    public int getCount() {
        return gradeList.getSize();
    }

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

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        if(convertView == null)
            convertView = getLayoutInflater().inflate(R.layout.row_grade, null);

        return loadGradeRow(convertView, position);
    }
}

是的,适配器的getView方法会调用另一个方法loadGradeRow

private View loadGradeRow(final View rowView, final int position) { 
  CheckBox chk= (CheckBox ) rowView.findViewById(R.id.chk);
  ...// Declare and initialize other views

  listIsRefreshing = true; // Explained below
  chk.setChecked(gradeList.get(position).enabled);
  ...// set views accordingly 
  listIsRefreshing = false;

  txtGpa.addTextChangedListener(new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {                   
        }
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {                    
        }
        @Override
        public void afterTextChanged(Editable s) {

            if(listIsRefreshing) //JUST REFRESHING, DON'T MIND
                return;

            gradeList.get(position).perc1 = s.toString();

            if(position == gradeList.size()-1) //Dont assign if its the last row
                return;


            gradeList.get(position+1).perc2 = s.toString();

            loadGradeRow(listview.getChildAt(position+1), position+1);
        }
    });

}

listIsRefreshing 是一个布尔值,需要在您的活动中声明。它是必需的,以确保只有当用户手动输入值时才为 perc2 分配值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接