美文网首页
今天我要好好说道说道TextInputEditText

今天我要好好说道说道TextInputEditText

作者: CalvinNing | 来源:发表于2017-06-29 16:00 被阅读113次

这是一篇记叙文

记叙文六要素:人物、时间、地点、事件发生的起因、经过、结果

人物:

保密

时间:

2017-06-28

地点:

保密

  • 上来就贴代码
    <android.support.design.widget.TextInputLayout
        android:id="@+id/til_new_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="5"
        android:gravity="center_vertical"
        android:hint="提示的话"
        app:counterEnabled="true"
        app:counterMaxLength="10"
        app:counterOverflowTextAppearance="@style/TextAppearance.Design.Counter.Overflow"
        app:counterTextAppearance="@style/TextAppearance.Design.Counter">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/et_new_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:digits="0123456789ABCDEFabcdef"
            android:maxLength="10"
            android:singleLine="true"
            android:textSize="24sp"
            tools:text="00FF010206"/>
    </android.support.design.widget.TextInputLayout>
  • 对应的图图
Paste_Image.png
TextInputLayout继承自LinearLayout,TextInputEditText继承自AppCompatEditText,二者结合使用就是为了实现上图的风骚效果的。需要依赖Design包compile 'com.android.support:design:25.3.1'

起因:

我想通过继承TextInputEditText自定义一个TadIDEditText,在上图风骚效果的基础上实现TagID号(eg:0102030405)每两位后面自动加一个空格(Space)的效果,代码如下

public class TadIDEditText extends TextInputEditText {
    private boolean shouldStopChange = false;

    public TadIDEditText(Context context) {
        super(context);
    }

    public TadIDEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TadIDEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private TextWatcher mTagIDEidtTextWatcher = new TextWatcher() {
        @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 void afterTextChanged(Editable s) {
            if (shouldStopChange) {
                shouldStopChange = false;
                return;
            }
            shouldStopChange = true;
            String str = s.toString().trim().replaceAll(" ", "");
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < str.length(); i++) {
                sb.append(str.charAt(i));
                if (i % 2 == 1 && i != str.length() - 1) {
                    sb.append(" ");
                }
            }
            setText(sb);
            setSelection(sb.length());
        }
    };

    @Override
    public void addTextChangedListener(TextWatcher watcher) {
        super.addTextChangedListener(mTagIDEidtTextWatcher);
    }

    @Override
    public void removeTextChangedListener(TextWatcher watcher) {
        super.removeTextChangedListener(mTagIDEidtTextWatcher);
    }

    public String getInputTagIDText() {
        return getText().toString().replace(" ", "").trim();
    }

    public TextWatcher getTagIDEditTextWatcher() {
        return mTagIDEidtTextWatcher;
    }
}

经过:

  • 先说明一下shouldStopChange的作用。
    因为是在afterTextChanged方法中判断、添加空格的,所以执行完afterTextChanged方法后,EditText的Text又变了,又会触发TextChanged,如果不通过这个变量控制,就会进入死循环,界面卡死,方法栈溢出。
  • addTextChangedListener(TextWatcher watcher)的源码(在TextView中)如下
    public void addTextChangedListener(TextWatcher watcher) {
        if (mListeners == null) {
            mListeners = new ArrayList<TextWatcher>();
        }
        mListeners.add(watcher);
    }
    void sendAfterTextChanged(Editable text) {
        if (mListeners != null) {
            final ArrayList<TextWatcher> list = mListeners;
            final int count = list.size();
            for (int i = 0; i < count; i++) {
                list.get(i).afterTextChanged(text);
            }
        }
        hideErrorIfUnchanged();
    }

也就是你可以给TextView及其继承者们添加多个TextWatcher,当其中的Text发生变化时,会依次调用这些TextWatcher中的几个方法。
注意:依次、依次、依次

  • 为了实现良好的封装,我希望添加空格的逻辑写在TadIDEditText中,鉴于此,我写好了一个mTagIDEidtTextWatcher,为了让我这个EditText功能专一,我重写了addTextChangedListener,如下,就是让它只能设置这一个监听器。
@Override
    public void addTextChangedListener(TextWatcher watcher) {
        super.addTextChangedListener(mTagIDEidtTextWatcher);
    }

结果造成了下面的问题

  • 使用TadIDEditText的时候,多次调用addTextChangedListener会造成多次添加mTagIDEidtTextWatcher,比如添加了2次,依据上面的分析我shouldStopChange这个变量就失去作用了,照样造成死循环、方法栈溢出。

  • 我在Activity中调用了一次addTextChangedListener,结果还是界面卡死、方法栈溢出了。然后通过一个简单的log,我发现尽管我只调用了一次,但是addTextChangedListener执行了两次,而且即使我不调用,addTextChangedListener也会执行一次。这就奇怪了???而且TextInputLayout右下角的计数也不计数了,这下就明白了,TextInputLayout和TextInput搭配使用,之所以能计数,不就是加了一个TextWatcher吗?看源码,果不其然。终于在TextInputLayout中发现了问题所在。以下贴出TextInputLayout中的几个方法。

@Override
    public void addView(View child, int index, final ViewGroup.LayoutParams params) {
        if (child instanceof EditText) {
            // Make sure that the EditText is vertically at the bottom, so that it sits on the
            // EditText's underline
            FrameLayout.LayoutParams flp = new FrameLayout.LayoutParams(params);
            flp.gravity = Gravity.CENTER_VERTICAL | (flp.gravity & ~Gravity.VERTICAL_GRAVITY_MASK);
            mInputFrame.addView(child, flp);

            // Now use the EditText's LayoutParams as our own and update them to make enough space
            // for the label
            mInputFrame.setLayoutParams(params);
            updateInputLayoutMargins();

            setEditText((EditText) child);<<<<<<<<<<<<<<<<<<<重点看这里
        } else {
            // Carry on adding the View...
            super.addView(child, index, params);
        }
    }
private void setEditText(EditText editText) {
        // If we already have an EditText, throw an exception
            ......
        // Add a TextWatcher so that we know when the text input has changed
        mEditText.addTextChangedListener(new TextWatcher() {<<<<<<<<<<<<<<<<<<<重点看这里
            @Override
            public void afterTextChanged(Editable s) {
                updateLabelState(!mRestoringSavedState);
                if (mCounterEnabled) {
                    updateCounter(s.length());//更新计数
                }
            }

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

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

        // Use the EditText's hint colors if we don't have one set
            ......
    }

看到这儿总算找出了我的bug,看来我这种写法问题多多啊,不过也通过问题对这两个控件了解了一下。

结果:

我想想还能怎么改。继续撸码。

相关文章

  • 今天我要好好说道说道TextInputEditText

    这是一篇记叙文 记叙文六要素:人物、时间、地点、事件发生的起因、经过、结果 人物: 保密 时间: 2017-06-...

  • 《说道说道》

    “说不出来的苦,才是真正的苦‘’ 这句话,我是深有体会!心中的那种苦,谁又能够明白呢?谁又能体会的到呢?既...

  • 说道说道

    宛风•茶•香•夜话: 说道说道: 说道与宗教,不要混淆了 说道不知道,不学胡八道 说道不做道,离道渐远了 说道要做...

  • 说道说道(2)

    想了很长时间,一直无法取一个合适的书名,最后只好取“大道至简”“和合文化”之意暂时将名字定为《简和》。 ...

  • 说道说道(1)

    在开始之前,我将会用三章《说道说道》的篇幅来交代一些基本问题,就算是序言吧! 一、 ...

  • 说道说道(3)

    既然是说道,最后一章就来说说“道”吧,当然这只是我的理解,只代表我自己,是我的“心”即“吾道”,只属于我,写...

  • 说道说道面相学

    面相学在东方最早记载于《礼记》,在西方最早可追溯到古希腊时期。面相就是人脸所表现出的景象,它是一种透过观看...

  • 《就想说道说道》

    最近听到这么一段话,说教育就是培养终身运动者、责任承担者、问题解决者、优雅生活者。人到中年,我不得不说,我是被教育...

  • 今天咱们来说道说道长寿老人

    齐帆齐微刊 今天就来说道说道长寿老人,我们村曾经出现过长达108岁的老人,现在还有一个103岁的老人,他都还能够生...

  • 说道

    你我皆凡人,并无大不同。 不同亦有时,无相有对中。

网友评论

      本文标题:今天我要好好说道说道TextInputEditText

      本文链接:https://www.haomeiwen.com/subject/auimcxtx.html