由 TextView.BufferType.EDITABLE 引发的血案
3865 点击·0 回帖
![]() | ![]() | |
![]() | 提示: 注意到 TextView 控件设置文本时的参数有TextView.BufferType.EDITABLE 和 TextView.BufferType.SPANNABLE 但是不知道具体啥差别, 于是决定窥探 google 代码,看个究竟。 一、在 TextView 类中找到 setText 方法关于 BufferType 的主要代码: java代码 // Editable 是一个接口,作者巧妙的在接口中实现了工厂方法。 private Editable.Factory mEditableFactory = Editable.Factory.getInstance(); private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance(); // Editable 是一个接口,作者巧妙的在接口中实现了工厂方法。 private Editable.Factory mEditableFactory = Editable.Factory.getInstance(); private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance(); java代码 if (type == BufferType.EDITABLE || mInput != null || needEditableForNotification) { Editable t = mEditableFactory.newEditable(text); text = t; setFilters(t, mFilters); InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) imm.restartInput(this); } else if (type == BufferType.SPANNABLE || mMovement != null) { text = mSpannableFactory.newSpannable(text); } else if (!(text instanceof CharWrapper)) { text = TextUtils.stringOrSpannedString(text); } if (type == BufferType.EDITABLE || mInput != null || needEditableForNotification) { Editable t = mEditableFactory.newEditable(text); text = t; setFilters(t, mFilters); InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) imm.restartInput(this); } else if (type == BufferType.SPANNABLE || mMovement != null) { text = mSpannableFactory.newSpannable(text); } else if (!(text instanceof CharWrapper)) { text = TextUtils.stringOrSpannedString(text); } 可以看出根据不同 BufferType ,用类工厂的模式创建控件,那么为什么不直接 new 一个控件呢?首先想到的是减少与实现类的耦合,提高可维护性。 二、带着上面的问题,在 TextView 类中找到下面的代码,提供了更换 Factory 的可能,使得开发者方便做不同的控件实现。 java代码 public final void setEditableFactory(Editable.Factory factory) { mEditableFactory = factory; setText(mText); } public final void setSpannableFactory(Spannable.Factory factory) { mSpannableFactory = factory; setText(mText); } public final void setEditableFactory(Editable.Factory factory) { mEditableFactory = factory; setText(mText); } public final void setSpannableFactory(Spannable.Factory factory) { mSpannableFactory = factory; setText(mText); } 三、那么如何自定义控件的实现呢,需要新写一个接口继承 Editable, 并且覆盖掉 Editable 中下面的方法: java代码 public static class Factory { private static Editable.Factory sInstance = new Editable.Factory(); public static Editable.Factory getInstance() { return sInstance; } public Editable newEditable(CharSequence source) { return new SpannableStringBuilder(source); } } public static class Factory { private static Editable.Factory sInstance = new Editable.Factory(); public static Editable.Factory getInstance() { return sInstance; } public Editable newEditable(CharSequence source) { return new SpannableStringBuilder(source); } } 四、TextView.BufferType.EDITABLE 和 TextView.BufferType.SPANNABLE 有什么区别呢?我们透过UML瞧一下, Editable 类似于StringBuilder可追加字符, 也就是说getText后可调用append方法设置文本内容。Spannable 则可在给定的字符区域使用样式。有意思的是 Editable 继承了 Spannable 所以具备较多的功能。 ![]() | |
![]() | ![]() |