SpannableString文本的 格式化 保存,显示,事件处理
来源:互联网 发布:ios9越狱mac 编辑:程序博客网 时间:2024/06/16 05:07
关于 spannableStrting 基本的一些用法效果在这里
http://blog.csdn.net/kongbaidepao/article/details/12087197
一、对 edittext 或 textview 中的 特殊显示效果字符进行保存 与显示
1.基本抽象方法定义基本功能
public abstract interface IMediaHandler {//处理联系人 public abstract void handleContact(SpannableStringBuilder builder, int start, int end, String name, String phone);//处理图片 public abstract void handleImage(SpannableStringBuilder builder, int start, int end, String name);//处理删除线 public abstract void handleStrike(SpannableStringBuilder builder, int start, int end);}
2.对要显示的数据进行处理
public class MediaHandler implements IMediaHandler { public void handleContact(SpannableStringBuilder builder, int start, int end, String name, String phone) { //得到 ContactImage Bitmap localBitmap = RichEditView.this.getContactImage(name); //这里设置 联系人的 TouchableSpan TouchableContactSpan span = new TouchableContactSpan(mContext, localBitmap, RichEditView.this, name, phone); //首先替换该处联系人的字符 String objStr = "\uFFFC"; builder.replace(start, end, objStr); //再替换成联系人图片(span) builder.setSpan(span, start, start + objStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } public void handleImage(SpannableStringBuilder builder, int start, int end, String name) { //同联系人 TouchableImageSpan span = new TouchableImageSpan(mContext, RichEditView.this, name); span.initialize(); String objStr = "\uFFFC"; builder.replace(start, end, objStr); builder.setSpan(span, start, start + objStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } public void handleStrike(SpannableStringBuilder builder, int start, int end) { //设置删除线 builder.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } }
3.调用
Spanned localSpanned = SpanUtils.parseSpannable(paramCharSequence.toString(), mMediaHandler);setText(localSpanned);
4. 工具类
import java.io.File;import java.util.ArrayList;import java.util.regex.Matcher;import java.util.regex.Pattern;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.text.Editable;import android.text.SpannableStringBuilder;import android.text.Spanned;import android.text.TextUtils;import android.text.style.ImageSpan;import android.text.style.StrikethroughSpan;import android.widget.TextView;public class SpanUtils { public static final char OBJ_CHAR = '\uFFFC'; //类似小图片的特殊符 public static final char NEWLINE_CHAR = '\n'; //换行符 public static final char IMG_START_CHAR = '\u263A'; //& public static final char IMG_END_CHAR = '\u263B'; //笑脸 public static final char CONTARCT_START_CHAR = '\u263E'; //符号 ( public static final char CONTARCT_END_CHAR = '\u263D'; //符号 ) public static final char CONTARCT_SPEATROR_CHAR = '\u263C'; //虫子 public static final char CHECK_CHAR = '\u221A';//对号。 public static final char BLANK_CHAR = ' '; //删除线的匹配(正则) private static final String REGEX_STRIKE_SPAN = "^" + CHECK_CHAR + "([^\n" + CHECK_CHAR + "]+)$"; //图片的匹配 (正则) private static final String REGEX_IMAGE_SPAN = IMG_START_CHAR + "([A-Za-z0-9]+)" + IMG_END_CHAR; //电话号码的匹配 , add phone number rules (正则) private static final String REGEX_CONTACT_SPAN = //电话号码的正则匹配 CONTARCT_START_CHAR + "(\\(\\d{1,4}\\)\\s\\d{1,4}-\\d{1,4}|" + "\\d{1,3}-\\d{1,8}|" + // 029 - 123456789 "\\+\\d{1,13}|" + // \\ 13484668924 "\\+\\d{2}\\s\\d{1,11}|" + // 86 123484466456 "\\+\\d{2}\\s\\d{1,4}\\s\\d{1,4}\\s\\d{1,4}|" + "\\+\\d{2}-\\d{1,11}|" + "\\+\\d{2}-\\d{1,11}-\\d{1,11}|" + "\\+\\d{2}-\\d{1,11}-\\d{1,11}\\*\\d{1,5}|" + "\\d{1,4}\\s\\d{1,4}\\s\\d{1,4}|" + "\\d{1,13}|" + "\\d{1,2}\\s\\d{1,4}-\\d{1,4}-\\d{1,4}+)" + // 11 1344-4584-7456 CONTARCT_SPEATROR_CHAR + "([^" + IMG_START_CHAR + IMG_END_CHAR + CONTARCT_START_CHAR + CONTARCT_END_CHAR + CONTARCT_SPEATROR_CHAR + CHECK_CHAR + "]+)" + CONTARCT_END_CHAR; //对数据库取出来的数据, 要在界面显示的文字进行处理 public static Spanned parseSpannable(String text, IMediaHandler handler) { SpannableStringBuilder builder = new SpannableStringBuilder(text); int start, end; //正则进行匹配先,这里是删除线 Pattern p1 = Pattern.compile(REGEX_STRIKE_SPAN, Pattern.MULTILINE); Matcher m1 = p1.matcher(builder); while (m1.find()) { String content = m1.group(1); start = m1.start(); end = m1.end(); handler.handleStrike(builder, start, end); builder.replace(start, end, content); m1.reset(builder); } //电话号码 Pattern p2 = Pattern.compile(REGEX_CONTACT_SPAN, Pattern.MULTILINE); Matcher m2 = p2.matcher(builder); while (m2.find()) { String phone = m2.group(1); String name = m2.group(2); start = m2.start(); end = m2.end(); handler.handleContact(builder, start, end, name, phone); //reset the Matcher m2.reset(builder); } //image Pattern p3 = Pattern.compile(REGEX_IMAGE_SPAN, Pattern.MULTILINE); Matcher m3 = p3.matcher(builder); while (m3.find()) { String imgName = m3.group(1); start = m3.start(); end = m3.end(); handler.handleImage(builder, start, end, imgName); //reset the Matcher m3.reset(builder); } return builder; } //单独删除线的处理(闹钟显示,widget 对从数据库中取出来的数据,正则匹配,然后还原成原来的样子), public static Spanned parseStrikethroughSpan(CharSequence showText) { SpannableStringBuilder builder = new SpannableStringBuilder(showText); Pattern p = Pattern.compile(REGEX_STRIKE_SPAN, Pattern.MULTILINE); Matcher m = p.matcher(builder); int start, end; while (m.find()) { String content = m.group(1); start = m.start(); end = m.end(); builder.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); builder.replace(start, end, content); m.reset(builder); } return builder; } // widget 和 dialog 上显示联系人 [ lilei: 1234567890 ],进行格式化 public static CharSequence normalizeSnippet(String content) { return parseStrikethroughSpan(normalizeSnippet(null, content)); } // 将图片信息删掉,将联系人信息重新组织输出,调用下面紧跟着的这个方法,用于显示在 其他不能点击的地方,比如 widget 和 dialog public static String normalizeSnippet(String content, NoteImgInfo info) { Pattern p = Pattern.compile(REGEX_IMAGE_SPAN, Pattern.MULTILINE); Matcher m = p.matcher(content); boolean bool = false; while (m.find()) { String name = m.group(1); if (!bool) { bool = true; if (info != null) info.firstImgName = name; } } return normalizeSnippet(null, content).toString(); } // 单独格式化联系人((闹钟显示, 因为闹钟提醒里面的话,不像平常文本可点击查看联系人 [ lilei: 1234567890 ] ) public static CharSequence normalizeSnippet(Context context, String content) { String out = new StringBuilder(content).toString(); Pattern p1 = Pattern.compile(REGEX_CONTACT_SPAN, Pattern.MULTILINE); Matcher m1 = p1.matcher(out); while (m1.find()) { out = m1.replaceFirst("[" + m1.group(2) + ": " + m1.group(1) + "]"); m1 = p1.matcher(out); } Pattern p2 = Pattern.compile(REGEX_IMAGE_SPAN, Pattern.MULTILINE); Matcher m2 = p2.matcher(out); if (m2.find()) out = m2.replaceAll(""); return out; } //当前的文本对spannble格式化,存入数据库 public static CharSequence buildSpannable(Editable editable) { // 此处传入的是当前edit窗口的editable的引用,不能修改,含有span对象,创建新的editable对象时需将其序列化?传入 Editable out = Editable.Factory.getInstance().newEditable( editable.subSequence(0, editable.length())); int start, end; String content; //查看是否有联系人 TouchableContactSpan[] contacts = out.getSpans(0, out.length(), TouchableContactSpan.class); for (int i = 0; i < contacts.length; i++) { start = out.getSpanStart(contacts[i]); end = out.getSpanEnd(contacts[i]); content = CONTARCT_START_CHAR + contacts[i].getPhoneNumber() + CONTARCT_SPEATROR_CHAR + contacts[i].getContactName() + CONTARCT_END_CHAR; out.replace(start, end, content); } //图片 TouchableImageSpan[] images = out.getSpans(0, out.length(), TouchableImageSpan.class); for (int i = 0; i < images.length; i++) { start = out.getSpanStart(images[i]); end = out.getSpanEnd(images[i]); content = IMG_START_CHAR + images[i].getName() + IMG_END_CHAR; if (start >= 0 && end >= 0) out.replace(start, end, content); } //删除线 StrikethroughSpan[] spans = out.getSpans(0, out.length(), StrikethroughSpan.class); for (int i = 0; i < spans.length; i++) { start = out.getSpanStart(spans[i]); end = out.getSpanEnd(spans[i]); content = out.subSequence(start, end).toString(); if (start >= 0 && out.charAt(start) != CHECK_CHAR ) out.replace(start, end, CHECK_CHAR + content); } return out; } public static class SimpleBuilder extends SpannableStringBuilder { public SimpleBuilder(String text) { super(text); } public SimpleBuilder() { super(); } public boolean isEmpty() { return TextUtils.isEmpty(this.toString()); } public void appendNewLine() { this.append("\n"); } public void appendImage(String name) { // File img = new File(name); // if (img.exists()) { // BitmapFactory.Options option = new BitmapFactory.Options(); // option.inJustDecodeBounds = false; // Bitmap bmp = BitmapFactory.decodeFile(img.getAbsolutePath(), // option); // // ImageSpan spans = new ImageSpan(bmp); // TouchableImageSpan span = new TouchableImageSpan(mContext, this, // imgName); // span.initialize(); // // ImageSpan span = new ImageSpan(getMissedDrawable()); // int start = this.length(); // this.append(OBJ_CHAR); // this.setSpan(span, start, end, // // this.setSpan(spans, start, start + 1, // Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // } this.append(IMG_START_CHAR + name + IMG_END_CHAR); } public void appendText(String text) { this.append(text); } } public static ArrayList<String> retrieveImages(Activity mActivity, CharSequence content) { ArrayList<String> out = new ArrayList<String>(); Pattern p = Pattern.compile(REGEX_IMAGE_SPAN, Pattern.MULTILINE); Matcher m = p.matcher(content); while (m.find()) { String name = m.group(1); out.add(name); } return out; } public static class NoteImgInfo { public String firstImgName; public NoteImgInfo() { firstImgName = null; } } //查看中是否有图片 public static boolean findImageInSnippet(String content) { Pattern p = Pattern.compile(REGEX_IMAGE_SPAN, Pattern.MULTILINE); Matcher m = p.matcher(content); if (m.find()) return true; return false; } public static ArrayList<String> collectImageNames(String content) { ArrayList<String> names = new ArrayList<String>(); Pattern p = Pattern.compile(REGEX_IMAGE_SPAN, Pattern.MULTILINE); Matcher m = p.matcher(content); while (m.find()) { names.add(m.group(1)); } return names; }}
二、内容事件处理
1.定义基本接口
private static abstract interface IActionDetector { public abstract boolean handleMotionEvent(MotionEvent event);}
- 联系人的处理
private class ClickContactDetector implements IActionDetector { private TouchableContactSpan nActiveSpan; private boolean nTraking; private ClickContactDetector() { } //对点击的地方处理,得到坐标进行处理 private TouchableContactSpan getActiveSpan(MotionEvent event) { Editable editable = getText(); TouchableContactSpan[] spans = (TouchableContactSpan[]) editable.getSpans(0, editable.length(), TouchableContactSpan.class); for (int i = 0; i < spans.length; i++) { if (isTouchInContactSpan(spans[i], event)) return spans[i]; } return null; } //对坐标进行判断,是否点击的是 可点击的联系人区域 private boolean isTouchInContactSpan(TouchableContactSpan span, MotionEvent event) { if (span != null) return span.isTouched((int) event.getX(), (int) event.getY()); return false; } //对接口类方法的实现,外部调用此方法 public boolean handleMotionEvent(MotionEvent event) { boolean bool = false; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: nActiveSpan = getActiveSpan(event); if (nActiveSpan != null) { nTraking = true; bool = true; } else nTraking = false; break; case MotionEvent.ACTION_UP: if (nTraking && isTouchInContactSpan(nActiveSpan, event)) { viewContact(nActiveSpan); nTraking = false; nActiveSpan = null; bool = true; } break; case MotionEvent.ACTION_MOVE: if (nTraking) break; case MotionEvent.ACTION_CANCEL: if (!nTraking) break; default: nTraking = false; nActiveSpan = null; break; } return bool; } }
调用系统联系人显示
private void viewContact(TouchableContactSpan span) { Uri localUri = Contact .getContactUri(mContext, span.getContactName(), span.getPhoneNumber()); if (localUri != null) ContactsContract.QuickContact.showQuickContact(getContext(), this, localUri, ContactsContract.QuickContact.MODE_LARGE, null); }
通过查询
public static Uri getContactUri(Context context, String name, String phoneNumber) { Cursor cursor = getContactCursor(context, name, phoneNumber); Uri uri = null; if (cursor != null) { try { if (cursor.moveToNext()) { String str = cursor.getString(0); long l = cursor.getLong(1); uri = ContactsContract.Contacts.CONTENT_LOOKUP_URI.buildUpon().appendPath(str) .appendPath(Long.toString(l)).build(); } } catch (Exception e) { // TODO: handle exception } finally { if (cursor != null) cursor.close(); } } return uri; }
查询
private static Cursor getContactCursor(Context context, String name, String phoneNumber) { Object[] arrayOfObject = new Object[2]; arrayOfObject[0] = "display_name"; arrayOfObject[1] = "data1"; String str = String.format(Locale.US, "%s=? AND PHONE_NUMBERS_EQUAL(%s,?)", arrayOfObject); String[] arrayOfString = new String[] { name, phoneNumber }; return context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, IDENTITY_PROJECTION, str, arrayOfString, null); }
2.对问题点击到图片的处理
private class ClickImageDetector implements IActionDetector { private TouchableImageSpan nActiveSpan; private boolean nTraking; private ClickImageDetector() { } private TouchableImageSpan getActiveSpan(MotionEvent event) { Editable editable = getText(); TouchableImageSpan[] spans = (TouchableImageSpan[]) editable.getSpans(0, editable.length(), TouchableImageSpan.class); for (int i = 0; i < spans.length; i++) { if (isTouchInImageSpan(spans[i], event)) return spans[i]; } return null; } private boolean isTouchInImageSpan(TouchableImageSpan paramSmartImageSpan, MotionEvent paramMotionEvent) { if (paramSmartImageSpan != null) return paramSmartImageSpan.isTouched((int) paramMotionEvent.getX(), (int) paramMotionEvent.getY()); return false; } public boolean handleMotionEvent(MotionEvent paramMotionEvent) { boolean bool = false; switch (paramMotionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: nActiveSpan = getActiveSpan(paramMotionEvent); if (nActiveSpan != null) { nTraking = true; bool = true; } else nTraking = false; break; case MotionEvent.ACTION_UP: if (nTraking && isTouchInImageSpan(nActiveSpan, paramMotionEvent)) { viewImage(nActiveSpan); nTraking = false; nActiveSpan = null; bool = true; } break; case MotionEvent.ACTION_MOVE: if (nTraking) break; case MotionEvent.ACTION_CANCEL: if (!nTraking) break; default: nTraking = false; nActiveSpan = null; break; } return bool; } }
使自定义的对点击事件的处理生效,
- 在界面创建时
mClickImageDetector = new ClickImageDetector();mClickContactDetector = new ClickContactDetector();
/* * 如果dispatchTouchEvent返回true * ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 * interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true * ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 * view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 * onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent * 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { if ((mClickImageDetector.handleMotionEvent(event)) || (mClickContactDetector.handleMotionEvent(event)) || mStrokeDetector.handleMotionEvent(event) || (super.dispatchTouchEvent(event))) return true; return false; }
1 0
- SpannableString文本的 格式化 保存,显示,事件处理
- SpannableString打造绚丽多彩的文本显示效果
- SpannableString 处理文本样式的利器
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果(TextView)
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- 用SpannableString打造绚丽多彩的文本显示效果
- Android 使用SpannableString设置金钱文本显示
- seam中格式化文本的处理
- 51 Nod 1028 大数乘法 V2 NTT 学习
- C语言C标识库学习笔记
- C++实验(一)
- 虚拟机和容器在性能上的比较_20170110
- busybox动态编译静态编译的区别
- SpannableString文本的 格式化 保存,显示,事件处理
- 关于powerdesigner链接Mysql数据库和出现的问题解决方案
- php工厂模式
- 文章标题
- spring中模板模式的应用
- 使用client-go 进行k8s相关操作-restclient(三)
- 从输入url到返回页面 的整个过程
- 无序字母对 洛谷 1341 欧拉通路/欧拉回路
- 七月算法课程《python爬虫》第六课: scrapy爬虫整体示例