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 文本超鏈接
以上內容爲上午學習所得,分享出來,希望各位朋友喜歡。如果你覺得博主這篇博客還行,還請不吝"❤"一個,謝謝!
交流羣初創,歡迎各位加入