【问题标题】:Use of different TextWatcher-implementations inside RecyclerView.Adapter在 RecyclerView.Adapter 中使用不同的 TextWatcher 实现
【发布时间】:2017-04-13 16:13:10
【问题描述】:

目前我使用 RecyclerView 来表示动态配置列表表单。

每个配置项(RecyclerView 列表中的条目)都包含一个 EditText 项。 为了避免错误的用户输入(某些字段只允许整数,而其他字段只允许逗号后的一位),我实现了两个不同的 TextWatcher 过滤器来纠正非法输入(“DecimalFilterDigitsAfterComma”和“DecimalFilterInteger”)。 我的RecyclerView一共有16个配置项,但一次最多只能显示8个。

我的问题是 TextWatchers 被分配给特定的项目(整数和小数点文本编辑)。但是当我稍微滚动时,它们会改变顺序,以便交换十进制和整数过滤器。

TextWatcher 项目将在 RecyclerView.Adapter 的 ConfigurationAdapter 内创建。我已经通过使用 mListConfigInit 管理每个条目只为每个条目创建一次 TextWatcher,该条目是项目的布尔标志列表。

ConfigurationAdapter.java:

public class ConfigurationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    /*
    ...
    */

    private List<ConfigItem> mConfiguration = new ArrayList<>();

    // make sure that DecimalFilter is only created once for each item
    private List<Boolean> mListConfigInit = new ArrayList<>();
    public ConfigurationAdapter() {
    }


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.listitem_configuration,
                parent,
                false);

        final ConfigurationViewHolder vh = new ConfigurationViewHolder(v);


        /*
        ...
        */

        return vh;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        final ConfigurationViewHolder vh = (ConfigurationViewHolder) holder;
        ConfigItem config = mConfiguration.get(position);

    if(config.ShowValueAsFloat()) {
        vh.SetTextWatcherType(ConfigurationViewHolder.TextWatcherType.type_FloatActive);
    } else {
        vh.SetTextWatcherType(ConfigurationViewHolder.TextWatcherType.type_IntActive);
    }


        // set name and unit
        vh.mName.setText(config.mName);
        vh.mUnit.setText(config.mUnit);

        /*
        ...
        */
    }

    @Override
    public int getItemCount() {
        return mConfiguration.size();
    }

    public void addConfigItem(ConfigItem item) {
        mConfiguration.add(item);
        mListConfigInit.add(new Boolean(false));
        notifyItemInserted(mConfiguration.size() - 1);
        //notifyDataSetChanged();
    }

    /*
    ...
    */


}

ConfigurationViewHolder.java(根据pskink-cmets修改):

public final class ConfigurationViewHolder extends RecyclerView.ViewHolder implements TextWatcher {
    public TextView mName;
    public CheckBox mCheckbox;
    public SeekBar mSeekbar;
    public EditText mValueEditText;
    public TextView mUnit;


    private List<TextWatcher> mListTextWatchers = new ArrayList<>();

    public enum TextWatcherType {
        type_FloatActive(0),
        type_IntActive(1);

        private int mValue;

        TextWatcherType(int value) {
            mValue = value;
        }

        int val() { return mValue; }
    }

    private TextWatcherType mTextWatcherType = TextWatcherType.type_FloatActive;

    public ConfigurationViewHolder(View itemView) {
        super(itemView);

        mName = (TextView) itemView.findViewById(R.id.textView_configuration_name);
        mValueEditText = (EditText) itemView.findViewById(R.id.editText_configuration_value);
        mUnit = (TextView) itemView.findViewById(R.id.textView_configuration_unit);
        mCheckbox = (CheckBox) itemView.findViewById(R.id.checkbox_configuration);
        mSeekbar = (SeekBar) itemView.findViewById(R.id.seekBar_configuration);

        mListTextWatchers.add(0, new DecimalFilterDigitsAfterComma(mValueEditText, 1));
        mListTextWatchers.add(1, new DecimalFilterInteger(mValueEditText));
        mValueEditText.addTextChangedListener(this);
    }

    public void SetTextWatcherType(TextWatcherType textWatcherType) {
        mTextWatcherType = textWatcherType;
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void afterTextChanged(Editable editable) {
        mListTextWatchers.get(mTextWatcherType.val()).afterTextChanged(editable);
    }
}

DecimalFilterInteger.java

public class DecimalFilterInteger implements TextWatcher {
    private final static String TAG = ConfigurationAdapter.class.getSimpleName();
    private final EditText mEditText;
    private String mLastTextValue = new String("");

    public DecimalFilterInteger(EditText editText) {
        this.mEditText = editText;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    }

    @Override
    public synchronized void afterTextChanged(final Editable text) {
        String strInput = text.toString().trim();
        if(strInput.isEmpty()) {
            return;
        }

        if(strInput.equals(mLastTextValue)) {   // return when same value as last time to avoid endless loop
            return;
        }

        if ((strInput.charAt(0) == '.')) {  // handle dot at beginning
            strInput = "";
        }

        if(strInput.contains(".")){         // cut trailing comma
            String numberBeforeDecimal = strInput.split("\\.")[0];
            strInput = numberBeforeDecimal;
        }
        mEditText.removeTextChangedListener(this);

        mEditText.getText().clear();    // do not use setText here to avoid changing the keyboard
        mEditText.append(strInput);     // back to default (e. g. from 123-mode to abc-mode),
                                        // see: http://stackoverflow.com/questions/26365808/edittext-settext-changes-the-keyboard-type-to-default-from-123-to-abc
        mLastTextValue = mEditText.getText().toString();

        mEditText.setSelection(mEditText.getText().toString().trim().length());
        mEditText.addTextChangedListener(this);
    }
}

非常感谢您的帮助!

【问题讨论】:

  • 每次调用onBindViewHolder时都必须调用addTextChangedListener(当然是在删除旧的之后)
  • 或者最好在ConfigurationViewHolder 中实现TextWatcher 并根据项目类型调用两个观察者之一(整数/浮点数,逗号后有一位)
  • 所以在你的ConfigurationViewHolder中实现TextWatcher,你不需要任何Map,只需在onBindViewHolder中更改“类型”
  • 所以现在你 addTextChangedListenerConfigurationViewHolderTextWatcher 中只需要根据当前状态变量调用当前观察者。
  • 顺便说一句,你不应该使用TextWatchers 而不是android.text.InputFilter吗?文档:InputFilters can be attached to Editables to constrain the changes that can be made to them.

标签: android android-recyclerview adapter textwatcher


【解决方案1】:

RecyclerView 中两个不同的 TextWatcher 实现的交换/切换行为的原因是我在它们的 afterTextChanged 方法中调用了 removeTextChangedListeneraddTextChangedListener,以避免重新触发 afterTextChanged 方法。

避免重新触发的最佳方法是简单检查自上次调用后文本是否发生更改:

public class DecimalFilterInteger implements TextWatcher {
    private final static String TAG = ConfigurationAdapter.class.getSimpleName();
    private final EditText mEditText;
    private String mLastTextValue = new String("");

    // ...

    @Override
    public synchronized void afterTextChanged(final Editable text) {
        String strInput = text.toString().trim();
        if(strInput.isEmpty()) {
            return;
        }

        if(strInput.equals(mLastTextValue)) {   // return when same value as last time to avoid endless loop
            return;
        }

        if ((strInput.charAt(0) == '.')) {  // handle dot at beginning
            strInput = "";
        }

        if(strInput.contains(".")){         // cut trailing comma
            String numberBeforeDecimal = strInput.split("\\.")[0];
            strInput = numberBeforeDecimal;
        }
        //mEditText.removeTextChangedListener(this);    // CAUSE OF SWAP-ERROR !!!

        mEditText.getText().clear();    // do not use setText here to avoid changing the keyboard
        mEditText.append(strInput);     // back to default (e. g. from 123-mode to abc-mode),
                                        // see: http://stackoverflow.com/questions/26365808/edittext-settext-changes-the-keyboard-type-to-default-from-123-to-abc
        mLastTextValue = mEditText.getText().toString();

        mEditText.setSelection(mEditText.getText().toString().trim().length());
        //mEditText.addTextChangedListener(this);       // CAUSE OF SWAP-ERROR !!!
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    相关资源
    最近更新 更多