【问题标题】:Android Handling many EditText fields in a ListViewAndroid 处理 ListView 中的许多 EditText 字段
【发布时间】:2011-11-13 23:54:11
【问题描述】:

只是一个基本问题:如果我有几十个 EditText 字段是 ListAdapter 的一部分,那么各个 EditText 字段如何知道它们属于哪一行?

目前我正在使用 TextWatcher 来监听文本输入。我已经尝试扩展 TextWatcher,以便可以将 EditText 的位置传递给 TextWatcher 的构造函数。

但是,当软键盘弹出时,各个EditText字段对应的位置会随机排列。

如何将 EditText 字段跟踪到正确位置?

我正在使用 GridView 进行布局。每个item的布局都是一个ImageView,下面有一个TextView和EditText字段。

每个 EditText 的文本都保存在称为字符串的全局字符串数组中。它最初是空的,由我的 TextWatcher 类更新。

public void initList()
    {
        ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.shape, strings)
        {
            @Override
            public View getView(final int position, View convertView, ViewGroup parent)  {
                if (convertView == null)  {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.shape, null);
                }
                final String theData = getItem(position);
                final EditText editText = (EditText) convertView.findViewById(R.id.shape_edittext);
                editText.setText(theData);
                editText.addTextChangedListener(
                        new MyTextWatcher(position, editText)
                );

                ImageView image = (ImageView) convertView.findViewById(R.id.shape_image);
                image.setBackgroundResource(images[position]);

                TextView text = (TextView) convertView.findViewById(R.id.shape_text);
                if (gameType == SHAPES_ABSTRACT)
                    text.setText("Seq:");
                else
                    text.setVisibility(View.GONE);  

                return convertView;
            }

            @Override
            public String getItem(int position) {        return strings[position];       }
        };

        grid.setAdapter(listAdapter);
    }


private class MyTextWatcher implements TextWatcher {
    private int index;
    private EditText edittext;
    public MyTextWatcher(int index, EditText edittext) { 
               this.index = index; 
               this.edittext = edittext;    
        }
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    public void onTextChanged(CharSequence s, int start, int before, int count) {}
    public void afterTextChanged(Editable s) {  strings[index] = s.toString();      }
    public void setIndex(int newindex) {  index = newindex;    }
}

当我点击第一个 EditText(见图)时,EditText 会转移到笑脸下方的那个。

【问题讨论】:

    标签: android gridview android-edittext listadapter textwatcher


    【解决方案1】:

    不考虑这是否是一个好的 UI 设计,你会这样做:

    public class TestList
    {
        public void blah()
        {
            ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
            {
    
                @Override
                public View getView(int position, View convertView, ViewGroup parent)
                {
                    if (convertView == null)
                    {
                        convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
                    }
    
                    final DataBucket dataBucket = getItem(position);
                    final EditText editText = (EditText) convertView.findViewById(R.id.theText);
                    editText.setText(dataBucket.getSomeData());
                    editText.addTextChangedListener(new TextWatcher()
                    {
                        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
                        {
    
                        }
    
                        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
                        {
    
                        }
    
                        public void afterTextChanged(Editable editable)
                        {
                            dataBucket.setSomeData(editable.toString());
                        }
                    });
    
                    return convertView;
                }
            };
        }
    
        public static class DataBucket
        {
            private String someData;
    
            public String getSomeData()
            {
                return someData;
            }
    
            public void setSomeData(String someData)
            {
                this.someData = someData;
            }
        }
    }
    

    'DataBucket' 是一个占位符。您需要使用您创建的任何类来存储在编辑文本中放入和编辑的数据。 TextWatcher 将具有对所引用数据对象的引用。当您滚动时,编辑文本框应该使用当前数据进行更新,并且应该保存文本更改。您可能想要跟踪用户更改了哪些对象,以提高数据/网络更新的效率。

    * 编辑 *

    要使用 int 位置而不是直接引用对象:

    ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
    {
    
        @Override
        public View getView(final int position, View convertView, ViewGroup parent)
        {
            if (convertView == null)
            {
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
            }
    
            final DataBucket dataBucket = getItem(position);
            final EditText editText = (EditText) convertView.findViewById(R.id.theText);
            editText.setText(dataBucket.getSomeData());
            editText.addTextChangedListener(new TextWatcher()
            {
                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
                {
    
                }
    
                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
                {
    
                }
    
                public void afterTextChanged(Editable editable)
                {
                    getItem(position).setSomeData(editable.toString());
                }
            });
    
            return convertView;
        }
    };
    

    * 再次编辑 *

    我不得不为后代说,我实际上不会这样编码。我猜您想要比字符串数组更结构化的数据,并且您在外部维护字符串数组以及 ArrayAdapter,因此这是一种奇怪的并行情况。但是,这将正常工作。

    我的数据在单个字符串数组中,而不是多维数组中。原因是因为支持 GridView 的数据模型只是一个简单的列表。这可能违反直觉,但事实就是如此。 GridView 应该自己进行布局,如果留给它自己的设备,将使用可变数量的单元格填充行,具体取决于您拥有多少数据以及屏幕的宽度(AFAIK)。

    聊够了。代码:

    public class TestList extends Activity
    {
        private String[] guess;
    
        //Other methods in here, onCreate, etc
    
        //Call me from somewhere else. Probably onCreate.
        public void initList()
        {
            ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, /*some resourse id*/, guess)
            {
    
                @Override
                public View getView(final int position, View convertView, ViewGroup parent)
                {
                    if (convertView == null)
                    {
                        convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
                    }
    
                    final String theData = getItem(position);
                    final EditText editText = (EditText) convertView.findViewById(R.id.theText);
                    editText.setText(theData);
                    editText.addTextChangedListener(
                            new MyTextWatcher(position)
                    );
    
                    return convertView;
                }
            };
    
            gridView.setAdapter(listAdapter);
        }
    
        class MyTextWatcher extends TextWatcher {
             private int position;
    
             public MyTextWatcher(int position) {
                     this.position = position;
             }
    
             public void afterTextChanged(Editable s) {
                     guess[position] = s.toString();
             }
    
         // other methods are created, but empty
        }
    }
    

    【讨论】:

    • 只使用标签或ID来识别EditTexts会更简单吗?我不知道实现是如何工作的,但是可以以简单的方式完成吗?
    • 我不确定这是否简单,但我会看看。
    • 使用位置值而不是直接引用对象。如果您的意思是更简单,例如不使用内部匿名 Java 类,我认为您应该习惯“复杂性”;)
    • 这很复杂,老实说我不知道​​你的代码在做什么,我一般是列表适配器的新手。对我来说,简单意味着为 EditText 对象本身分配一个数字,或者通过标签/id(无论是什么),或者扩展 EditText 类以保存与其所在行相对应的额外变量。其中任何一个可行?
    • 就像我说的,你应该习惯这些结构。从概念上讲,它们比你所说的更简单,一旦你习惯了它们,你就会在 Android 中到处看到这种东西。我不太确定你想要做什么,但是扩展 EditText 作为我正在做的事情的替代方案对我来说听起来很复杂。不推荐。
    【解决方案2】:

    要跟踪行号,EditText 中的每个侦听器都必须保留对列表中项目的引用,并使用getPosition(item) 获取ListView 中的位置。我的示例使用Button,但我认为它可以应用于EditText

    class DoubleAdapter extends ArrayAdapter<Double> {
        public DoubleAdapter(Context context, List<Double> list) {
            super(context, android.R.layout.simple_list_item_1, list);
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_row, null);
            }
    
            // keep a reference to an item in a list
            final Double d = getItem(position);
    
            TextView lblId = (TextView) convertView.findViewById(R.id.lblId);
            lblId.setText(d.toString());
    
            Button button1 = (Button) convertView.findViewById(R.id.button1);
            button1.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    // the button listener has a reference to an item in the list
                    // so it can know its position in the ListView
                    int i = getPosition(d);
                    Toast.makeText(getContext(), "" + i, Toast.LENGTH_LONG).show();
                    remove(d);
                }
            });
    
            return convertView;
        }
    }
    

    【讨论】:

    • 如果列表元素不是 Double 会怎样?如果多个元素具有相同的值会发生什么?我认为这里的目标是更新列表中的值,而不是删除它们,对吧?这段代码会有问题,除非数据是 Double,并且您确定没有两个值是相同的。我想我们不知道。
    • 如果列表元素不是Double,则将代码中的所有Double替换为元素的类型。而且,您可以通过引用 d 更新元素的值。
    • 如果您有两个(或更多)具有相同值的元素怎么办?
    • 如果它们是同一个对象,那么两者都会被改变。否则,只会更改一个元素。
    • 对。如果这是一个值列表,我怀疑您是否希望同时更改这两个对象。
    【解决方案3】:

    是否需要将编辑文本存储在列表单元格中可能值得考虑?当用户一次只编辑一个时,这似乎有点不必要。

    虽然我不知道您的应用程序是如何设计的,但我建议您稍微重新考虑您的用户体验,以便在按下列表项时显示单个文本编辑供他们编辑。这样,您就可以像通常使用列表适配器一样获取列表项引用,在用户编辑时存储它并在完成时更新它。

    【讨论】:

    • EditText 这么多为什么会被人看不起?我认为我的实例不适合只弹出一个。仅仅是外观,还是对手机内存也有负担?
    • 主要原因是在滚动过程中,ListViews 回收每个项目一旦从屏幕上隐藏,并使用回收的视图显示列表中的下一个项目。如果回收的视图包含数据,就像您的 EditText 将包含文本一样,那么当您滚动浏览 ListView 时,这些数据很可能会丢失或放错位置。
    【解决方案4】:

    我不确定这是否是一个不错的设计,因为一旦滚动列表视图,EditText 内容很可能会出现问题(随机播放内容、丢失文本)。考虑试试 m6tt 的想法。

    但是,如果您真的想按照自己的方式行事,您可以发布一些代码,特别是您的 TextWatcher 的代码吗?

    【讨论】:

      【解决方案5】:

      我试图解决这个问题,如您所见,有一个简单的方法 - 我在这里发布答案,因为它可能对某人有用。

      列表视图时无法获取位置 -> 编辑文本有文本观察器。

      这是对我有用的解决方案:

      在获取视图中-

      当我添加文本观察监听器来编辑文本时,我还添加了以下行

      edittext.setTag(R.id.position<any unique string identitiy>, position)
      

      在你的 afterTextChanged -

       int position = edittext.getTag(R.id.position) 
      

      给出正确的位置编号,您可以根据位置编号进行修改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-23
        • 1970-01-01
        • 2020-12-06
        • 2010-12-02
        • 2016-03-19
        • 2011-09-27
        • 1970-01-01
        相关资源
        最近更新 更多