Keywords: Android TextView
github:https://github.com/rockerhieu/emojicon
emojicon开源库是一个关于表情输入相关的,主要是Span运用,这里把代码分为两部分学习emoji、其他。先从emoji包开始,这里面主要是一些基础数据和Emojicon类
Nature、Objects、People、Places、Symbols都是基础数据略过,Emojicon类提供了上面这些基础数据的转换方法,实现了序列化,那么,为什么要序列化?
-
永久性保存对象,保存对象的字节序列到本地文件中;
-
通过序列化对象在网络中传递对象;
-
通过序列化在进程间传递对象。
以上都不是重点,重点是在Emojicon类中发现了一段诡异的代码(对自己而言),枚举为什么要这样用呢,为什么要用注解呢?
@IntDef({DynamicDrawableSpan.ALIGN_BASELINE, DynamicDrawableSpan.ALIGN_BOTTOM})
public @interface Alignment {
}
@IntDef({TYPE_UNDEFINED, TYPE_PEOPLE, TYPE_NATURE, TYPE_OBJECTS, TYPE_PLACES, TYPE_SYMBOLS})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {
}
public static final int TYPE_UNDEFINED = 0;
public static final int TYPE_PEOPLE = 1;
public static final int TYPE_NATURE = 2;
public static final int TYPE_OBJECTS = 3;
public static final int TYPE_PLACES = 4;
public static final int TYPE_SYMBOLS = 5;
public static Emojicon[] getEmojicons(@Type int type) {
switch (type) {
case TYPE_PEOPLE:
return People.DATA;
case TYPE_NATURE:
return Nature.DATA;
case TYPE_OBJECTS:
return Objects.DATA;
case TYPE_PLACES:
return Places.DATA;
case TYPE_SYMBOLS:
return Symbols.DATA;
}
throw new IllegalArgumentException("Invalid emojicon type: " + type);
}
带着疑问差了些许资料,从内存效率方面考虑,上面这种方式最优,这里不再重复叙述,提供相关资料链接,有兴趣者可以自行参阅
http://developer.android.com/training/articles/memory.html#Overhead
https://noobcoderblog.wordpress.com/2015/04/12/java-enum-and-android-intdefstringdef-annotation/
这里再多提一点,注解在开发中有很大用处,android-support-annotations库用处很大,例如@Nullable 会对代码进行检查,如果传入值为null就会有警告提示
Utils类主要是关于keyboardView 、屏幕的宽高获取,还有个生成viewId方法,这里面用到了一个相对陌生的类AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
AtomicInteger相关API
//获取当前的值
public final int get()
//取当前的值,并设置新的值
public final int getAndSet(int newValue)
//获取当前的值,并自增
public final int getAndIncrement()
//获取当前的值,并自减
public final int getAndDecrement()
//获取当前的值,并加上预期的值
public final int getAndAdd(int delta)
Emojicon库主要用的控件组合:Fragment+ViewPager+GridView,这个流程大致梳理一下:Tab被点击了执行ViewPager的Item切换,即切换Fragment,表情GridViewItem被点击了执行回调函数
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mOnEmojiconClickedListener != null) {
mOnEmojiconClickedListener.onEmojiconClicked((Emojicon) parent.getItemAtPosition(position));
}
}
onEmojiconClicked主要是回调输入内容,我们通过EmojiconsFragment.input(mEditEmojicon, emojicon)方法完成Text赋值
public static void input(EditText editText, Emojicon emojicon) {
if (editText == null || emojicon == null) {
return;
}
int start = editText.getSelectionStart();
int end = editText.getSelectionEnd();
if (start < 0) {
editText.append(emojicon.getEmoji());
} else {
editText.getText().replace(Math.min(start, end), Math.max(start, end), emojicon.getEmoji(), 0, emojicon.getEmoji().length());
}
}
以上流程主要是对于直接的EditText而言,而他的直接、间接子类TextView 、AppCompatMultiAutoCompleteTextView又略有不同,提供了自定义控件:EmojiconTextView、EmojiconMultiAutoCompleteTextView,他们主要是修改setText、setEmojiconSize方法实现,这两个方法都涉及到一个类EmojiconHandler,他们都调用了EmojiconHandler.addEmojis(),由于addEmojis函数过长就不贴代码了,这里面主要是Span的包装,最后设置到控件,所以得出一个结论:
Emojicon库的核心就是自定义EmojiconSpan和自定义组合控件。
EmojiconSpan继承DynamicDrawableSpan,那么问题来了,Span的直接子类那么多为什么非要DynamicDrawableSpan?我们来看看Span的一些子类的具体用途,看过之后真相即将明了
-
BackgroundColorSpan 背景色
-
ClickableSpan 文本可点击,有点击事件
-
ForegroundColorSpan 文本颜色(前景色)
-
MaskFilterSpan 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
-
MetricAffectingSpan 父类,一般不用
-
RasterizerSpan 光栅效果
-
StrikethroughSpan 删除线(中划线)
-
SuggestionSpan 相当于占位符
-
UnderlineSpan 下划线
-
AbsoluteSizeSpan 绝对大小(文本字体)
-
DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
-
ImageSpan 图片
-
RelativeSizeSpan 相对大小(文本字体)
-
ReplacementSpan 父类,一般不用
-
ScaleXSpan 基于x轴缩放
-
StyleSpan 字体样式:粗体、斜体等
-
SubscriptSpan 下标(数学公式会用到)
-
SuperscriptSpan 上标(数学公式会用到)
-
TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
-
TypefaceSpan 文本字体
-
URLSpan 文本超链接
以上内容为上午学习所得,分享出来,希望各位朋友喜欢。如果你觉得博主这篇博客还行,还请不吝"❤"一个,谢谢!
交流群初创,欢迎各位加入
网友评论