匹配表情、关键字、Url的Textview
来源:互联网 发布:北京夺冠马布里数据 编辑:程序博客网 时间:2024/05/23 13:00
源码Demo下载
http://download.csdn.net/detail/u014620028/9609661
注:在Edittext和Textview中,不要加下面2个属性中的任何一种。否则,当行数大于1行以后会发生表情、图片对不齐的情况
android:lineSpacingExtra=""android:lineSpacingMultiplier=""
效果图:
输入:
展示效果:
注:为了举例,把“我”当成关键字,“你”当成要凸显出来的字。比如搜索“你”,在结果中,把“你”字变红
把下面的代码,都复制到自己项目下,改改包名什么的,就可以直接用了
代码:
1、布局文件
activity_main_12:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:fitsSystemWindows="true" android:orientation="vertical"> <EditText android:id="@+id/et_word_message" android:layout_width="match_parent" android:layout_height="200dp" android:layout_margin="8dp" android:layout_marginTop="10dp" android:background="#dedede" android:gravity="top|left" android:hint="输入内容" android:maxLength="300" android:textSize="20sp" /> <TextView android:id="@+id/show_result_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/et_word_message" android:layout_marginTop="5dp" android:background="#00ff00" android:gravity="center" android:padding="5dp" android:text="显示" android:textSize="20sp"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_gravity="bottom" android:orientation="vertical" android:paddingBottom="5dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#dedede"> <ImageView android:id="@+id/iv_expression" android:layout_width="25dp" android:layout_height="25dp" android:layout_alignParentLeft="true" android:layout_marginLeft="10dp"/> <TextView android:id="@+id/tv_show_residue_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:text="" android:textColor="#999999" android:textSize="17sp" /> </RelativeLayout> <android.support.v4.view.ViewPager android:id="@+id/show_emoji_viewPager" android:layout_width="match_parent" android:layout_height="180dp" android:visibility="gone"/> </LinearLayout></RelativeLayout>
emoji_gridview:
<?xml version="1.0" encoding="utf-8"?><GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gridView_Expression" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="#ffffff" android:numColumns="7"></GridView>
restul_layout:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="5dp" > <com.chen.customviewdemo.view.MyTextView android:id="@+id/result_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:text="" android:textSize="20sp"/></RelativeLayout>
工具等:
Expressions:
package com.chen.customviewdemo.view;import com.chen.customviewdemo.R;import java.util.ArrayList;import java.util.List;/** * 处理表情 */public class Expressions { public static List<int[]> emojiIdList = new ArrayList<int[]>(); public static List<String[]> emojiNameList = new ArrayList<String[]>(); public static final int[] emojID = new int[]{R.mipmap.emoji_0, R.mipmap.emoji_1, R.mipmap.emoji_2, R.mipmap.emoji_3, R.mipmap.emoji_4, R.mipmap.emoji_5, R.mipmap.emoji_6, R.mipmap.emoji_7, R.mipmap.emoji_8, R.mipmap.emoji_9, R.mipmap.emoji_10, R.mipmap.emoji_11, R.mipmap.emoji_12, R.mipmap.emoji_13, R.mipmap.emoji_14, R.mipmap.emoji_15, R.mipmap.emoji_16, R.mipmap.emoji_17, R.mipmap.emoji_18, R.mipmap.emoji_19, R.mipmap.emoji_20, R.mipmap.emoji_21, R.mipmap.emoji_22, R.mipmap.emoji_23, R.mipmap.emoji_24, R.mipmap.emoji_25, R.mipmap.emoji_26, R.mipmap.emoji_27, R.mipmap.emoji_28, R.mipmap.emoji_29, R.mipmap.emoji_30, R.mipmap.emoji_31, R.mipmap.emoji_32, R.mipmap.emoji_33, R.mipmap.emoji_34, R.mipmap.emoji_35, R.mipmap.emoji_36, R.mipmap.emoji_37, R.mipmap.emoji_38, R.mipmap.emoji_39, R.mipmap.emoji_40, R.mipmap.emoji_41, R.mipmap.emoji_42, R.mipmap.emoji_43, R.mipmap.emoji_44, R.mipmap.emoji_45, R.mipmap.emoji_46, R.mipmap.emoji_47, R.mipmap.emoji_48, R.mipmap.emoji_49, R.mipmap.emoji_50, R.mipmap.emoji_51, R.mipmap.emoji_52, R.mipmap.emoji_53, R.mipmap.emoji_54, R.mipmap.emoji_55, R.mipmap.emoji_56, R.mipmap.emoji_57, R.mipmap.emoji_58, R.mipmap.emoji_59, R.mipmap.emoji_60, R.mipmap.emoji_61, R.mipmap.emoji_62, R.mipmap.emoji_63, R.mipmap.emoji_64, R.mipmap.emoji_65, R.mipmap.emoji_66, R.mipmap.emoji_67, R.mipmap.emoji_68, R.mipmap.emoji_69, R.mipmap.emoji_70, R.mipmap.emoji_71, R.mipmap.emoji_72, R.mipmap.emoji_73, R.mipmap.emoji_74, R.mipmap.emoji_75, R.mipmap.emoji_76, R.mipmap.emoji_77, R.mipmap.emoji_78, R.mipmap.emoji_79, R.mipmap.emoji_80, R.mipmap.emoji_81, R.mipmap.emoji_82, R.mipmap.emoji_83, R.mipmap.emoji_84, R.mipmap.emoji_85, R.mipmap.emoji_86, R.mipmap.emoji_87, R.mipmap.emoji_88, R.mipmap.emoji_89, R.mipmap.emoji_90, R.mipmap.emoji_91, R.mipmap.emoji_92, R.mipmap.emoji_93, R.mipmap.emoji_94, R.mipmap.emoji_95, R.mipmap.emoji_96, R.mipmap.emoji_97, R.mipmap.emoji_98, R.mipmap.emoji_99, R.mipmap.emoji_100, R.mipmap.emoji_101, R.mipmap.emoji_102, R.mipmap.emoji_103, R.mipmap.emoji_104}; public static final String[] emojName = new String[]{"[/微笑]", "[/撇嘴]", "[/色]", "[/发呆]", "[/得意]", "[/流泪]", "[/害羞]", "[/闭嘴]", "[/睡]", "[/大哭]", "[/尴尬]", "[/发怒]", "[/调皮]", "[/呲牙]", "[/惊讶]", "[/难过]", "[/酷]", "[/冷汗]", "[/抓狂]", "[/吐]", "[/偷笑]", "[/可爱]", "[/白眼]", "[/傲慢]", "[/饥饿]", "[/困]", "[/惊恐]", "[/流汗]", "[/憨笑]", "[/大兵]", "[/奋斗]", "[/咒骂]", "[/疑问]", "[/嘘...]", "[/晕]", "[/折磨]", "[/衰]", "[/骷髅]", "[/敲打]", "[/再见]", "[/擦汗]", "[/抠鼻]", "[/鼓掌]", "[/糗大了]", "[/坏笑]", "[/左哼哼]", "[/右哼哼]", "[/哈欠]", "[/鄙视]", "[/委屈]", "[/快哭了]", "[/阴险]", "[/亲亲]", "[/吓]", "[/可怜]", "[/菜刀]", "[/西瓜]", "[/啤酒]", "[/篮球]", "[/乒乓]", "[/咖啡]", "[/饭]", "[/猪头]", "[/玫瑰]", "[/凋谢]", "[/示爱]", "[/爱心]", "[/心碎]", "[/蛋糕]", "[/闪电]", "[/炸弹]", "[/刀]", "[/足球]", "[/瓢虫]", "[/便便]", "[/月亮]", "[/太阳]", "[/礼物]", "[/拥抱]", "[/强]", "[/弱]", "[/握手]", "[/胜利]", "[/抱拳]", "[/勾引]", "[/拳头]", "[/差劲]", "[/爱你]", "[/NO]", "[/OK]", "[/爱情]", "[/飞吻]", "[/跳跳]", "[/发抖]", "[/怄火]", "[/转圈]", "[/磕头]", "[/回头]", "[/跳绳]", "[/挥手]", "[/激动]", "[/街舞]", "[/献吻]", "[/左太极]", "[/右太极]"}; static { emojiIdList.add(emojID); emojiNameList.add(emojName); } /** * 由表情名称获得表情图片id * * @param name * @return */ public static int getIdAsName(String name) throws NullPointerException { for (int i = 0; i < emojName.length; i++) { if (emojName[i].equals(name)) { return emojID[i]; } } return 0; }}
EmotionBean
package com.chen.customviewdemo.bean;/** * 表情bean */public class EmotionBean { private int Id; // 表情对应的Id private String Name; // 表情对应的名字 public int getId() { return Id; } public void setId(int id) { Id = id; } public String getName() { return Name; } public void setName(String name) { Name = name; }}
KeyBean
package com.chen.customviewdemo.bean;/** * 关键字bean。 * 包含显式内容和隐式内容。 * 如:在界面上显示“百度”,点击了它,就去一个界面打开百度的网页。要打开网页,肯定需要Url。这就需要,在点击的时候,把Url传递过去。 * 这个时候,这个Url,就是隐式内容了。不必让用户看到,只是在触发后,隐含的做一定操作就行 */public class KeyBean { public KeyBean(String content, String hide_content) { this.content = content; this.hide_content = hide_content; } /** * 内容 */ public String content; /** * 隐藏的内容,点击内容后,要传递的值或者要做的事 */ public String hide_content; public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getHide_content() { return hide_content; } public void setHide_content(String hide_content) { this.hide_content = hide_content; }}
ExpressionUtil
package com.chen.customviewdemo.utils;import android.content.Context;import android.graphics.drawable.Drawable;import android.text.Spannable;import android.text.SpannableString;import android.text.style.ImageSpan;import com.chen.customviewdemo.view.Expressions;import java.util.regex.Matcher;import java.util.regex.Pattern;public class ExpressionUtil { public static SpannableString getSpannableString(String str, Context context, int size) { SpannableString spannableString = new SpannableString(str); String string = "\\[(.+?)\\]"; Pattern patten = Pattern.compile(string, Pattern.CASE_INSENSITIVE); try { dealSpannableString(context, spannableString, patten, 0, size); } catch (Exception e) { } return spannableString; } private static void dealSpannableString(Context context, SpannableString spannableString, Pattern patten, int start, int emojiSize) { Matcher matcher = patten.matcher(spannableString); while (matcher.find()) { String key = matcher.group(); if (matcher.start() < start) { continue; } int id = Expressions.getIdAsName(key); if (id != 0) { Drawable drawable = context.getResources().getDrawable(id); drawable.setBounds(0, 0, Utils.sp2px(context, emojiSize), Utils.sp2px(context, emojiSize)); ImageSpan imgSpan = new ImageSpan(drawable); int end = matcher.start() + key.length(); spannableString.setSpan(imgSpan, matcher.start(), end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); if (end < spannableString.length()) { //如果整个字符串还未验证完,则继续。。 dealSpannableString(context, spannableString, patten, end, emojiSize); } break; } } }}
Utils
package com.chen.customviewdemo.utils;import android.app.Activity;import android.content.Context;import android.text.TextUtils;import android.util.DisplayMetrics;/** * 工具类 */public class Utils { /** * 检查字符串是否是空 * * @param str * @return true:字符串为空 */ public static boolean checkStringIsEmpty(String str) { if (TextUtils.isEmpty(str) || "null".equals(str)) { return true; } else { return false; } } /** * 将sp值转换为px值 */ public static int sp2px(Context context, float spValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); }}
CHEN
package com.chen.customviewdemo.utils;/** * 用于保存全局变量值 */public class CHEN { /** * 要被传递的文字 */ public static String Str = ""; /** * 要变红的字。一般用于搜索,如:把搜索的字变为红色用于突出显示 */ public static String toRedWord = ""; /** * 网址要被替换成的文字 */ public static String REPLACEMENT_STRING = "*点击链接"; /** * 匹配网址的正则表达式。以http://为例 */ public static String urlRegex = "(http://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|([a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)"; /** * 匹配网址的正则表达式。有http://、https://、ftp://这3中开头的 */ // public static String urlRegex = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|([a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)";}
EmotionGridViewAdapter
package com.chen.customviewdemo.adapter;import android.app.Activity;import android.content.Context;import android.util.DisplayMetrics;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView.LayoutParams;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.ImageView.ScaleType;import com.chen.customviewdemo.R;import com.chen.customviewdemo.bean.EmotionBean;import com.chen.customviewdemo.view.Expressions;import java.util.ArrayList;import java.util.List;/** * 每一个表情页的adapter */public class EmotionGridViewAdapter extends BaseAdapter { private List<EmotionBean> list; private Context context; private String tag; public EmotionGridViewAdapter(Context context, int page) { this.context = context; this.list = new ArrayList<EmotionBean>(); setData1(page); } private void setData1(int page) { switch (page) { case 0: case 1: case 2: case 3: case 4: int len = 20; // 每页显示20个表情,一个删除键 for (int i = 0 + (len * page); i < len + (len * page); i++) { EmotionBean bean = new EmotionBean(); bean.setId(Expressions.emojID[i]); bean.setName(Expressions.emojName[i]); list.add(bean); } EmotionBean bean = new EmotionBean(); bean.setId(R.mipmap.emoji_del); list.add(bean); break; case 5: // 最后一页,显示5个表情和一个删除键 for (int i = 100; i < 105; i++) { EmotionBean bean1 = new EmotionBean(); bean1.setId(Expressions.emojID[i]); bean1.setName(Expressions.emojName[i]); list.add(bean1); } EmotionBean bean1 = new EmotionBean(); bean1.setId(R.mipmap.emoji_del); list.add(bean1); break; } } public void setData(List<EmotionBean> list) { this.list = list; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { final EmotionBean bean = list.get(position); int itemWidth = getWindowPX(); int padding = itemWidth / 6; ImageView iv = new ImageView(context); LayoutParams params = new LayoutParams(itemWidth, itemWidth); iv.setLayoutParams(params); iv.setScaleType(ScaleType.FIT_CENTER); iv.setPadding(padding, 0, padding, 0); iv.setImageResource(bean.getId()); return iv; } private int getWindowPX() { Activity activity; if (context instanceof Activity) { activity = (Activity) context; DisplayMetrics dm = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; return width / 8; } else { return 200; } }}
ShowEmojiViewPagerAdapter
package com.chen.customviewdemo.adapter;import android.support.v4.view.PagerAdapter;import android.view.View;import android.view.ViewGroup;import android.widget.GridView;import java.util.List;/** * 展示表情的viewpager的adapter */public class ShowEmojiViewPagerAdapter extends PagerAdapter { private List<GridView> mGridlist; public ShowEmojiViewPagerAdapter(List<GridView> mList) { super(); this.mGridlist = mList; } @Override public int getCount() { return mGridlist.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0==arg1; } @Override public void destroyItem(View container, int position, Object object) { ((ViewGroup)container).removeView(mGridlist.get(position)); } @Override public Object instantiateItem(View container, int position) { ((ViewGroup)container).addView(mGridlist.get(position)); return mGridlist.get(position); }}
MyTextView
package com.chen.customviewdemo.view;import android.content.Context;import android.graphics.drawable.Drawable;import android.text.SpannableString;import android.text.Spanned;import android.text.TextPaint;import android.text.TextUtils;import android.text.method.LinkMovementMethod;import android.text.style.ClickableSpan;import android.text.style.ImageSpan;import android.util.AttributeSet;import android.view.View;import android.widget.TextView;import android.widget.Toast;import com.chen.customviewdemo.R;import com.chen.customviewdemo.bean.KeyBean;import com.chen.customviewdemo.utils.CHEN;import com.chen.customviewdemo.utils.ExpressionUtil;import com.chen.customviewdemo.utils.Utils;import java.util.ArrayList;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * 自定义textview,用于处理url、表情、文字等 */public class MyTextView extends TextView { private Context context = null; public MyTextView(Context context, AttributeSet attr) { super(context, attr); this.context = context; } public MyTextView(Context context) { super(context); this.context = context; } /** * TextView显示有颜色的字,并添加点击事件,适用于一段文字中有多个内容要处理 */ public void handleText(String str, final ArrayList<KeyBean> keyBeanList, int size) { String content = str; //处理匹配的url Pattern p = Pattern.compile(CHEN.urlRegex); Matcher m = p.matcher(content); ArrayList<String> urlList = new ArrayList<String>(); while (m.find()) { String urlStr = m.group(); if (urlStr.contains("http://")) { //如果末尾有英文逗号或者中文逗号等,就去掉 while (urlStr.endsWith(",") || urlStr.endsWith(",") || urlStr.endsWith(".") || urlStr.endsWith("。") || urlStr.endsWith(";") || urlStr.endsWith(";") || urlStr.endsWith("!") || urlStr.endsWith("!") || urlStr.endsWith("?") || urlStr.endsWith("?")) { urlStr = urlStr.substring(0, urlStr.length() - 1); } urlList.add(urlStr); content = content.replace(urlStr, CHEN.REPLACEMENT_STRING); } } final SpannableString spannableString = ExpressionUtil.getSpannableString(content, context, size); content = spannableString.toString(); //处理链接 if (urlList.size() > 0) { int urlStartNew = 0; int urlStartOld = 0; String urlTemp = content; for (int i = 0; i < urlList.size(); i++) { final String regexUrl = urlList.get(i); spannableString.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { // TODO Auto-generated method stub super.updateDrawState(ds); ds.setColor(context.getResources().getColor(R.color.linkcolor)); ds.setUnderlineText(false); } @Override public void onClick(View widget) { Toast.makeText(context, regexUrl, Toast.LENGTH_SHORT).show(); } }, urlStartOld + urlTemp.indexOf(CHEN.REPLACEMENT_STRING), urlStartOld + urlTemp.indexOf(CHEN.REPLACEMENT_STRING) + CHEN.REPLACEMENT_STRING.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); try { //“点击链接”前面的回形针图片。大小可自己调整 Drawable drawable = context.getResources().getDrawable(R.mipmap.web_link); drawable.setBounds(0, 0, Utils.sp2px(context, size), Utils.sp2px(context, size)); ImageSpan imgSpan = new ImageSpan(drawable); spannableString.setSpan(imgSpan, urlStartOld + urlTemp.indexOf(CHEN.REPLACEMENT_STRING), urlStartOld + urlTemp.indexOf(CHEN.REPLACEMENT_STRING) + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } catch (Exception e) { //异常以后,就不加小图片了 } setText(spannableString); setMovementMethod(LinkMovementMethod.getInstance()); urlStartNew = urlTemp.indexOf(CHEN.REPLACEMENT_STRING) + CHEN.REPLACEMENT_STRING.length(); urlStartOld += urlStartNew; urlTemp = urlTemp.substring(urlStartNew); } } //处理文本中的关键字 if (keyBeanList != null && keyBeanList.size() > 0) { for (int i = 0; i < keyBeanList.size(); i++) { final String data = keyBeanList.get(i).getContent(); final String hide_content = keyBeanList.get(i).getHide_content(); String temp = content; int startNew = 0; int startOld = 0; if (temp.contains(data)) { while (temp.contains(data)) { spannableString.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { // TODO Auto-generated method stub super.updateDrawState(ds); ds.setColor(context.getResources().getColor(R.color.linkcolor)); ds.setUnderlineText(false); } @Override public void onClick(View widget) { Toast.makeText(context, hide_content, Toast.LENGTH_SHORT).show(); } }, startOld + temp.indexOf(data), startOld + temp.indexOf(data) + data.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); setText(spannableString); setMovementMethod(LinkMovementMethod.getInstance()); startNew = temp.indexOf(data) + data.length(); startOld += startNew; temp = temp.substring(startNew); } } else { setText(spannableString); } } } else { setText(spannableString); } //处理要变红的字 if (!TextUtils.isEmpty(CHEN.toRedWord)) { //只要把关键字变红就行了,不需要加点击事件。如果需要,可以自己加 String temp = content; int startNew = 0; int startOld = 0; while (temp.contains(CHEN.toRedWord)) { spannableString.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { // TODO Auto-generated method stub super.updateDrawState(ds); ds.setColor(0xffff0000); ds.setUnderlineText(false); } @Override public void onClick(View widget) { } }, startOld + temp.indexOf(CHEN.toRedWord), startOld + temp.indexOf(CHEN.toRedWord) + CHEN.toRedWord.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); setText(spannableString); setMovementMethod(LinkMovementMethod.getInstance()); startNew = temp.indexOf(CHEN.toRedWord) + CHEN.toRedWord.length(); startOld += startNew; temp = temp.substring(startNew); } } else { setText(spannableString); } }}
Activity中使用
BaseActivity
package com.chen.customviewdemo;import android.app.Activity;import android.os.Bundle;import android.view.Window;/** * 基础Activity */public abstract class BaseActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //不显示title requestWindowFeature(Window.FEATURE_NO_TITLE); initview(); } abstract void initview();}
MainActivity_12
package com.chen.customviewdemo;import android.app.Instrumentation;import android.content.Context;import android.content.Intent;import android.support.v4.view.ViewPager;import android.text.Editable;import android.text.SpannableString;import android.text.TextUtils;import android.text.TextWatcher;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.View;import android.view.inputmethod.InputMethodManager;import android.widget.AdapterView;import android.widget.EditText;import android.widget.GridView;import android.widget.ImageView;import android.widget.TextView;import com.chen.customviewdemo.adapter.EmotionGridViewAdapter;import com.chen.customviewdemo.adapter.ShowEmojiViewPagerAdapter;import com.chen.customviewdemo.utils.CHEN;import com.chen.customviewdemo.utils.ExpressionUtil;import com.chen.customviewdemo.view.Expressions;import java.util.ArrayList;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * 输入文字和表情的界面 */public class MainActivity_12 extends BaseActivity implements View.OnClickListener { private Context mContext; // 表情 private ImageView iv_expression; // 显示表情的ViewPager private ViewPager show_emoji_viewPager; // 装载表情的viewPager的Adapter private ShowEmojiViewPagerAdapter showEmojiViewPagerAdapter; /** * 装载表情的viewPager的Adapter的每一页,都是一个gridview,这些gridview,用集合管理起来 */ private List<GridView> mGridList; /** * 文本输入框 */ private EditText et_word_message; /** * 当前是否显示表情键盘 */ private boolean isShowEmotion = false; private final String reg = "^[\u4e00-\u9fa5\u0020-\u007E\uFE30-\uFFA0。、……“”‘’《》——¥~]*$"; private Pattern pattern = Pattern.compile(reg); /** * 显示动态的剩余字数 */ private TextView tv_show_residue_num; /** * 动态内容剩余字数。以300为例 */ private int dynamicContentResidueNum = 300; /** * 展示输入结果的按钮 */ private TextView show_result_tv; /** * 动态输入框的监听 */ private TextWatcher watcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { String dynicContent = s.toString(); int contentCount = dynicContent.length(); if (TextUtils.isEmpty(dynicContent) || contentCount < 250) { tv_show_residue_num.setText(""); dynamicContentResidueNum = 300; } else if (contentCount >= 250 && contentCount <= dynamicContentResidueNum) { int tempCount = dynamicContentResidueNum - contentCount; tv_show_residue_num.setText("还能输入" + tempCount + "字"); } else if (contentCount > dynamicContentResidueNum) { tv_show_residue_num.setText(dynamicContentResidueNum - contentCount + ""); } } @Override public void afterTextChanged(Editable s) { } }; @Override void initview() { setContentView(R.layout.activity_main_12); mContext = this; //默认。以此为例 CHEN.toRedWord = "你"; show_result_tv = (TextView) findViewById(R.id.show_result_tv); mGridList = new ArrayList<GridView>(); mGridList.clear(); tv_show_residue_num = (TextView) findViewById(R.id.tv_show_residue_num); iv_expression = (ImageView) findViewById(R.id.iv_expression); iv_expression.setBackgroundResource(R.mipmap.biao_qing); show_emoji_viewPager = (ViewPager) findViewById(R.id.show_emoji_viewPager); initGridViews(); // 填充 表情的ViewPager的adapter showEmojiViewPagerAdapter = new ShowEmojiViewPagerAdapter(mGridList); show_emoji_viewPager.setAdapter(showEmojiViewPagerAdapter); et_word_message = (EditText) findViewById(R.id.et_word_message); et_word_message.addTextChangedListener(watcher); iv_expression.setOnClickListener(this); show_result_tv.setOnClickListener(this); et_word_message.setOnClickListener(this); } /** * 初始化表情键盘的Grideview */ private void initGridViews() { mGridList = new ArrayList<GridView>(); LayoutInflater inflater = LayoutInflater.from(mContext); mGridList.clear(); for (int i = 0; i < 6; i++) { final int j = i; GridView gridView = (GridView) inflater.inflate( R.layout.emoji_gridview, null); gridView.setAdapter(new EmotionGridViewAdapter(mContext, i)); mGridList.add(gridView); gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (position == 20 || position == 40 || position == 60 || position == 80 || position == 100 || (j == 5 && position == 5)) {//处理删除键 int selectionStart = et_word_message.getSelectionStart(); String text = et_word_message.getText().toString(); if (!TextUtils.isEmpty(text)) { String body = et_word_message.getText().toString(); String tempStr = body.substring(0, selectionStart); int i = tempStr.lastIndexOf("]");// 获取最后一个表情的位置 if (i == tempStr.length() - 1) {// 说明光标刚好停在这个表情之后 int j = tempStr.lastIndexOf("[");// 将这两个之间的字符删掉 et_word_message.getEditableText().delete(j, selectionStart); } else { Matcher matcher = pattern.matcher(text); if (!matcher.matches()) { new Thread(new Runnable() { @Override public void run() { Instrumentation instrumentation = new Instrumentation(); instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DEL); } }) { }.start(); } else { et_word_message.getEditableText().delete( tempStr.length() - 1, selectionStart); } } } } else { //表情会被转换成字符串。防止最后输入一个表情,超出字数显示 if ((300 - et_word_message.getText().toString().trim().length()) < 5) { return; } String emotionString = Expressions.emojName[position + j * 20]; String text = et_word_message.getText() + emotionString; SpannableString spannableString = ExpressionUtil .getSpannableString(text, mContext, 23); et_word_message.setText(spannableString); Editable b = et_word_message.getText(); et_word_message.setSelection(b.length()); } } }); } showEmojiViewPagerAdapter = new ShowEmojiViewPagerAdapter(mGridList); show_emoji_viewPager.setAdapter(showEmojiViewPagerAdapter); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.iv_expression: // 点击表情的按钮,弹出表情 if (isShowEmotion) { iv_expression.setBackgroundResource(R.mipmap.biao_qing); show_emoji_viewPager.setVisibility(View.GONE); showKeyBoard(); } else if (!isShowEmotion) { iv_expression.setBackgroundResource(R.mipmap.keyboard); show_emoji_viewPager.setVisibility(View.VISIBLE); hideKeyBoard(v); } isShowEmotion = !isShowEmotion; break; case R.id.et_word_message: if (isShowEmotion) { iv_expression.setBackgroundResource(R.mipmap.biao_qing); show_emoji_viewPager.setVisibility(View.GONE); forceShowKeyBoard(et_word_message); isShowEmotion = !isShowEmotion; } break; case R.id.show_result_tv: //去展示结果的界面 CHEN.Str = et_word_message.getText().toString().trim(); startActivity(new Intent(this, ShowWordAndEmojiDataActivity.class)); break; default: break; } } /** * 强制显示软键盘 */ public void forceShowKeyBoard(View v) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(v, InputMethodManager.SHOW_FORCED); } /** * 隐藏软键盘 * @param v */ public void hideKeyBoard(View v) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } /** * 显示软键盘 */ public void showKeyBoard() { InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); }}
ShowWordAndEmojiDataActivity
package com.chen.customviewdemo;import com.chen.customviewdemo.bean.KeyBean;import com.chen.customviewdemo.utils.CHEN;import com.chen.customviewdemo.view.MyTextView;import java.util.ArrayList;/** * 展示输入结果的Activity */public class ShowWordAndEmojiDataActivity extends BaseActivity { MyTextView result_tv; ArrayList<KeyBean> keyBeanList; @Override void initview() { setContentView(R.layout.restul_layout); keyBeanList = new ArrayList<KeyBean>(); //还有关键字的话,可以继续加 keyBeanList.add(new KeyBean("我", "哈哈")); result_tv = (MyTextView) findViewById(R.id.result_tv); result_tv.handleText(CHEN.Str, keyBeanList, 23); } @Override protected void onDestroy() { super.onDestroy(); CHEN.toRedWord = ""; }}
清单文件:
<activity android:name=".MainActivity_12" android:configChanges="orientation|keyboardHidden" android:screenOrientation="portrait" android:windowSoftInputMode="adjustResize"/> <activity android:name=".ShowWordAndEmojiDataActivity" android:screenOrientation="portrait"/>
0 0
- 匹配表情、关键字、Url的Textview
- iOS textView的emoji表情过滤
- 匹配表情
- textview 前面有标签,textview里面关键字标红,有小表情
- 匹配URL的正则
- URL的正则匹配
- httpd的url匹配
- Textview\EditText添加表情
- textView表情代码相关
- 表情匹配机制
- webpy的url动态匹配
- url-pattern的匹配规则
- python解析url的关键字
- 35特殊字符匹配表情的工具类
- Android项目 匹配Text里面的Emoji 和 QQ表情
- android的TextView中显示url
- EditText TextView中显示表情
- android TextView,EditText插入表情
- FreeSwitch下载和编译
- MySQL5.7.14解压版安装与配置
- 远程连接linux桌面之XDMCP配置
- mysql join 链接方式
- Quartz 2D 参考-文本
- 匹配表情、关键字、Url的Textview
- Redis设计与实现之复制
- UVALive 6912 I Want That Cake
- android中图片的放大缩小ZoomControls的使用范例(亲测)
- DIV+CSS中图片和文字混排居中问题解决方案
- windows SDK程序的框架分析
- nodejs死亡笔记之溯本归源--node4.0+与ECMAScript6新特性(two)
- bash的expr 0会引起退出?
- C语言中结构体的剖析