來自網路上的網由提供的一個技術 : (待整理)
這段時間在做一個短信專案,需要實現短信中插入表情的功能,本一位非常困難,經過一段時間的研究,發現還是比較簡単的,現在總結如下。
以短信輸入框為例,短信的輸入框是一個EditText,它的append方法不僅可以加入字串,還可以添加HTML標記。以下就是使用HTML標記添加表情的具體操作。
首先需要構建一個ImageGetter,作用是通過HTML標記獲得對應在res目錄下的圖片:
ImageGetter imageGetter = new ImageGetter() {
@Override
public Drawable getDrawable(String source) {
int id = Integer.parseInt(source);
//根據id從資源檔中獲取圖片物件
Drawable d = getResources().getDrawable(id);
d.setBounds(0, 0, d.getIntrinsicWidth(),d.getIntrinsicHeight());
return d;
}
};
然後就可以直接往EditText視圖中添加
inputLable.append(Html.fromHtml(\"<img src=\'\"+clickedImageId+\"\'/>\", imageGetter, null));
其中 Html.fromHtml(\"<img src=\'\"+clickedImageId+\"\'/>\"就是HTML的圖片標記,在Android中支援了部分HTML標記的使用(這方面我還在繼續研究),HTML標記必須被Html.fromHtml修飾。imageGetter即為之前創建的ImageGetter類型的對象。
很簡單的幾句代碼就解決了問題,不僅在EditText中,在TextView中同樣可以這樣插入圖片。
android 的短信實現方式普通使用者適應的話需要長時間的使用才能習慣,將andorid的短信模式設置成我們常用的(一般人用戶)的習慣。在查看字元轉圖片的過程中可以猜測出騰訊的QQ表情的原理應該是一樣的
只是在傳送非常用的表情時是將byte資料轉換為image.
/***
*
* 此方法描述的是: 注意此方法在做表情轉換的準備了
* @author:wujun@cqghong.com,ppwuyi@sohu.com
* @version: 2010-5-13 下午03:31:13
*/
private void bindCommonMessage(final MessageItem msgItem) {
if (mDownloadButton != null) {
mDownloadButton.setVisibility(View.GONE);
mDownloadingLabel.setVisibility(View.GONE);
}
// Since the message text should be concatenated with the sender's
// address(or name), I have to display it here instead of
// displaying it by the Presenter.
mBodyTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
// Get and/or lazily set the formatted message from/on the
// MessageItem. Because the MessageItem instances come from a
// cache (currently of size ~50), the hit rate on avoiding the
// expensive formatMessage() call is very high.
CharSequence formattedMessage = msgItem.getCachedFormattedMessage();
if (formattedMessage == null) { //肯定為null應為msgItem.formattedMessage從誕生來就沒被注意過一次
formattedMessage = formatMessage(msgItem.mContact, msgItem.mBody, //重點到了
msgItem.mSubject, msgItem.mTimestamp,
msgItem.mHighlight);
msgItem.setCachedFormattedMessage(formattedMessage);
}
mBodyTextView.setText(formattedMessage);
if (msgItem.isSms()) {
hideMmsViewIfNeeded();
} else {
Presenter presenter = PresenterFactory.getPresenter(
"MmsThumbnailPresenter", mContext,
this, msgItem.mSlideshow);
presenter.present();
if (msgItem.mAttachmentType != WorkingMessage.TEXT) {
inflateMmsView();
mMmsView.setVisibility(View.VISIBLE);
setOnClickListener(msgItem);
drawPlaybackButton(msgItem);
} else {
hideMmsViewIfNeeded();
}
}
drawLeftStatusIndicator(msgItem.mBoxId);
drawRightStatusIndicator(msgItem);
}
//------------------------------------------------------------------------------
/***
*
* 此方法描述的是: 開始轉換了哦
* @author:wujun@cqghong.com,ppwuyi@sohu.com
* @version: 2010-5-13 下午03:32:52
*/
private CharSequence formatMessage(String contact, String body, String subject,
String timestamp, String highlight) {
CharSequence template = mContext.getResources().getText(R.string.name_colon); //遇到鬼了 <主題:<xliff:g id="SUBJECT">%s</xliff:g>>"
SpannableStringBuilder buf = //把他當作StringBuffer只是它可以放的不是 String 而已他能放跟多類型的東西
new SpannableStringBuilder(TextUtils.replace(template,
new String[] { "%s" },
new CharSequence[] { contact })); //替換成連絡人
boolean hasSubject = !TextUtils.isEmpty(subject); //主題
if (hasSubject) {
buf.append(mContext.getResources().getString(R.string.inline_subject, subject)); //buff先在是 連絡人 主題 XXXX eg wuyi <主題:dsadasdsa> 我愛我家
}
if (!TextUtils.isEmpty(body)) {
if (hasSubject) {
buf.append(" - "); //如果內容有主題有就+ " - " eg wuyi <主題:sdsadsadsa> -
}
SmileyParser parser = SmileyParser.getInstance(); //獲得表情類了哦
buf.append(parser.addSmileySpans(body)); //追查 急切關注中
}
if (!TextUtils.isEmpty(timestamp)) {
buf.append("\n");
int startOffset = buf.length();
// put a one pixel high spacer line between the message and the time stamp as requested
// by the spec.
//把之間的資訊和時間戳記的要求間隔一個圖元的高線
//由規範
buf.append("\n");
buf.setSpan(new AbsoluteSizeSpan(3), startOffset, buf.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
startOffset = buf.length();
buf.append(timestamp);
buf.setSpan(new AbsoluteSizeSpan(12), startOffset, buf.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Make the timestamp text not as dark 改變某區域顏色 時間的地方為特殊顏色
int color = mContext.getResources().getColor(R.color.timestamp_color);
buf.setSpan(new ForegroundColorSpan(color), startOffset, buf.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (highlight != null) {
int highlightLen = highlight.length();
String s = buf.toString().toLowerCase();
int prev = 0;
while (true) {
int index = s.indexOf(highlight, prev);
if (index == -1) {
break;
}
buf.setSpan(new StyleSpan(Typeface.BOLD), index, index + highlightLen, 0);
prev = index + highlightLen;
}
}
return buf;
}
//------------------------------------------------------------
/**
* Adds ImageSpans to a CharSequence that replace textual emoticons such
* as :-) with a graphical version.
*
* @param text A CharSequence possibly containing emoticons
* @return A CharSequence annotated with ImageSpans covering any
* recognized emoticons.
* 添加ImageSpans一個CharSequence的表情符號代替文字等 *如用圖形版本:-)。
* 核心是把表情字元替換成ImageSpans的物件
*/
public CharSequence addSmileySpans(CharSequence text) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
Matcher matcher = mPattern.matcher(text);
while (matcher.find()) {
int resId = mSmileyToRes.get(matcher.group());
//注意下面的一塊有點不好理解哦但是是核心
builder.setSpan(new ImageSpan(mContext, resId), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return builder;
}
總結:
android 在將字元轉化為表情圖像其核心代碼為
builder.setSpan(new ImageSpan(mContext, resId), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
原理過程是先匹配到表情字元然後通過new ImageSpan(上下文,表情位址)繪製出一個ImageView然後替換掉表情字元。
以短信輸入框為例,短信的輸入框是一個EditText,它的append方法不僅可以加入字串,還可以添加HTML標記。以下就是使用HTML標記添加表情的具體操作。
首先需要構建一個ImageGetter,作用是通過HTML標記獲得對應在res目錄下的圖片:
ImageGetter imageGetter = new ImageGetter() {
@Override
public Drawable getDrawable(String source) {
int id = Integer.parseInt(source);
//根據id從資源檔中獲取圖片物件
Drawable d = getResources().getDrawable(id);
d.setBounds(0, 0, d.getIntrinsicWidth(),d.getIntrinsicHeight());
return d;
}
};
然後就可以直接往EditText視圖中添加
inputLable.append(Html.fromHtml(\"<img src=\'\"+clickedImageId+\"\'/>\", imageGetter, null));
其中 Html.fromHtml(\"<img src=\'\"+clickedImageId+\"\'/>\"就是HTML的圖片標記,在Android中支援了部分HTML標記的使用(這方面我還在繼續研究),HTML標記必須被Html.fromHtml修飾。imageGetter即為之前創建的ImageGetter類型的對象。
很簡單的幾句代碼就解決了問題,不僅在EditText中,在TextView中同樣可以這樣插入圖片。
android 的短信實現方式普通使用者適應的話需要長時間的使用才能習慣,將andorid的短信模式設置成我們常用的(一般人用戶)的習慣。在查看字元轉圖片的過程中可以猜測出騰訊的QQ表情的原理應該是一樣的
只是在傳送非常用的表情時是將byte資料轉換為image.
/***
*
* 此方法描述的是: 注意此方法在做表情轉換的準備了
* @author:wujun@cqghong.com,ppwuyi@sohu.com
* @version: 2010-5-13 下午03:31:13
*/
private void bindCommonMessage(final MessageItem msgItem) {
if (mDownloadButton != null) {
mDownloadButton.setVisibility(View.GONE);
mDownloadingLabel.setVisibility(View.GONE);
}
// Since the message text should be concatenated with the sender's
// address(or name), I have to display it here instead of
// displaying it by the Presenter.
mBodyTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
// Get and/or lazily set the formatted message from/on the
// MessageItem. Because the MessageItem instances come from a
// cache (currently of size ~50), the hit rate on avoiding the
// expensive formatMessage() call is very high.
CharSequence formattedMessage = msgItem.getCachedFormattedMessage();
if (formattedMessage == null) { //肯定為null應為msgItem.formattedMessage從誕生來就沒被注意過一次
formattedMessage = formatMessage(msgItem.mContact, msgItem.mBody, //重點到了
msgItem.mSubject, msgItem.mTimestamp,
msgItem.mHighlight);
msgItem.setCachedFormattedMessage(formattedMessage);
}
mBodyTextView.setText(formattedMessage);
if (msgItem.isSms()) {
hideMmsViewIfNeeded();
} else {
Presenter presenter = PresenterFactory.getPresenter(
"MmsThumbnailPresenter", mContext,
this, msgItem.mSlideshow);
presenter.present();
if (msgItem.mAttachmentType != WorkingMessage.TEXT) {
inflateMmsView();
mMmsView.setVisibility(View.VISIBLE);
setOnClickListener(msgItem);
drawPlaybackButton(msgItem);
} else {
hideMmsViewIfNeeded();
}
}
drawLeftStatusIndicator(msgItem.mBoxId);
drawRightStatusIndicator(msgItem);
}
//------------------------------------------------------------------------------
/***
*
* 此方法描述的是: 開始轉換了哦
* @author:wujun@cqghong.com,ppwuyi@sohu.com
* @version: 2010-5-13 下午03:32:52
*/
private CharSequence formatMessage(String contact, String body, String subject,
String timestamp, String highlight) {
CharSequence template = mContext.getResources().getText(R.string.name_colon); //遇到鬼了 <主題:<xliff:g id="SUBJECT">%s</xliff:g>>"
SpannableStringBuilder buf = //把他當作StringBuffer只是它可以放的不是 String 而已他能放跟多類型的東西
new SpannableStringBuilder(TextUtils.replace(template,
new String[] { "%s" },
new CharSequence[] { contact })); //替換成連絡人
boolean hasSubject = !TextUtils.isEmpty(subject); //主題
if (hasSubject) {
buf.append(mContext.getResources().getString(R.string.inline_subject, subject)); //buff先在是 連絡人 主題 XXXX eg wuyi <主題:dsadasdsa> 我愛我家
}
if (!TextUtils.isEmpty(body)) {
if (hasSubject) {
buf.append(" - "); //如果內容有主題有就+ " - " eg wuyi <主題:sdsadsadsa> -
}
SmileyParser parser = SmileyParser.getInstance(); //獲得表情類了哦
buf.append(parser.addSmileySpans(body)); //追查 急切關注中
}
if (!TextUtils.isEmpty(timestamp)) {
buf.append("\n");
int startOffset = buf.length();
// put a one pixel high spacer line between the message and the time stamp as requested
// by the spec.
//把之間的資訊和時間戳記的要求間隔一個圖元的高線
//由規範
buf.append("\n");
buf.setSpan(new AbsoluteSizeSpan(3), startOffset, buf.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
startOffset = buf.length();
buf.append(timestamp);
buf.setSpan(new AbsoluteSizeSpan(12), startOffset, buf.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Make the timestamp text not as dark 改變某區域顏色 時間的地方為特殊顏色
int color = mContext.getResources().getColor(R.color.timestamp_color);
buf.setSpan(new ForegroundColorSpan(color), startOffset, buf.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (highlight != null) {
int highlightLen = highlight.length();
String s = buf.toString().toLowerCase();
int prev = 0;
while (true) {
int index = s.indexOf(highlight, prev);
if (index == -1) {
break;
}
buf.setSpan(new StyleSpan(Typeface.BOLD), index, index + highlightLen, 0);
prev = index + highlightLen;
}
}
return buf;
}
//------------------------------------------------------------
/**
* Adds ImageSpans to a CharSequence that replace textual emoticons such
* as :-) with a graphical version.
*
* @param text A CharSequence possibly containing emoticons
* @return A CharSequence annotated with ImageSpans covering any
* recognized emoticons.
* 添加ImageSpans一個CharSequence的表情符號代替文字等 *如用圖形版本:-)。
* 核心是把表情字元替換成ImageSpans的物件
*/
public CharSequence addSmileySpans(CharSequence text) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
Matcher matcher = mPattern.matcher(text);
while (matcher.find()) {
int resId = mSmileyToRes.get(matcher.group());
//注意下面的一塊有點不好理解哦但是是核心
builder.setSpan(new ImageSpan(mContext, resId), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return builder;
}
總結:
android 在將字元轉化為表情圖像其核心代碼為
builder.setSpan(new ImageSpan(mContext, resId), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
原理過程是先匹配到表情字元然後通過new ImageSpan(上下文,表情位址)繪製出一個ImageView然後替換掉表情字元。
沒有留言:
張貼留言