Android添加@联系人功能
2017-02-20 16:09
246 查看
Android添加@联系人功能
年后聊天项目加了个@联系人功能的需求,网上找了几个Demo都不尽人意,按照需求需要处理的细节很多觉得稍显繁复,后来想到@功能也就和短信的添加收件人的功能差不多,就自己动手写了一个,这里分享出来给以供参考!效果图
需求分析
@联系人高亮
数据保存和还原
检测用户输入@跳转到联系人选择
@块删除时作为一个整体删除,用户点击时光标不可出现在@块内部
点击@块跳转
思路整理
看似功能并不复杂,但实际操作起来就会发现蜀道之难啊,数据高亮这点简单不必细说,数据的保存和还原只需要根据数据规则利用正则表达式处理即可,需求要求@块作为一个整体删除,同时光标不可以出现在@块内部,网上一般的思路是使用ForegroundColorSpan来高亮突出@块,同时重写EditeText的方法监听输入和删除,虽然也能达到效果但是需要写的代码有点多,这时候想到能不能像处理表情一样使用一个类似于ImageSpan的东西来做呢,但是@后的数据多变并不确定,所以需要自定义一个ImageSpan能根据内容变化,这样只需要自定义一个Span类型就可以,不用特意处理删除光标等问题。
代码实现
自定义Span
这个自定义的ViewSpan来自短信项目的收件人控件,继承自ReplacementSpan,当控件显示的时候会使用指定的View替代指定的字符串显示,而当getText().toString()的时候获得是原始字符串。
public class ViewSpan extends ReplacementSpan { protected View view; private int maxWidth; public ViewSpan(View v, int maxWidth) { super(); this.maxWidth = maxWidth; view = v; view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } private void prepView() { int widthSpec = View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST); int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); view.measure(widthSpec, heightSpec); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); } @Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom,@NonNull Paint paint) { prepView(); canvas.save(); //Centering the token looks like a better strategy that aligning the bottom int padding = (bottom - top - view.getBottom()) / 2; canvas.translate(x, bottom - view.getBottom() - padding); //这一句是重点,将view画在指定canvas上 view.draw(canvas); canvas.restore(); } @Override public int getSize(@NonNull Paint paint, CharSequence charSequence, int i, int i2, Paint.FontMetricsInt fm) { prepView(); if (fm != null) { //We need to make sure the layout allots enough space for the view int height = view.getMeasuredHeight(); int need = height - (fm.descent - fm.ascent); if (need > 0) { int ascent = need / 2; //This makes sure the text drawing area will be tall enough for the view fm.descent += need - ascent; fm.ascent -= ascent; fm.bottom += need - ascent; fm.top -= need / 2; } } return view.getRight(); } }
数据的存储和还原
这里使用正则表达式匹配@字符串,规则是"@user:"+手机号,这个可以根据情况随便改
//匹配的正则 public static final String regEx = "(.|\\n)*@user:1[3,5,7,8]\\d{9}(.|\\n)*"; //分割字符串的正则 public static final String splitRegex = "@user:1[3,5,7,8]\\d{9}";
生成Span的方法
public static SpannableString getSpan(final TextView textView, String usrStr){ final String phone = usrStr.split(":")[1]; String str; User user = findUser(phone); if(user == null){ str = "@" + phone; }else { str = "@" + user.name; } SpannableString spanText = new SpannableString(usrStr); TextView spanTv = (TextView) LayoutInflater.from(textView.getContext()).inflate(R.layout.item_at, (ViewGroup) textView.getParent(), false); spanTv.setText(str); //第二个参数其实应该是用textView的最大宽度,这里的300是随便写的 ViewSpan span = new ViewSpan(spanTv,300); spanText.setSpan(span, 0, spanText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); //添加点击事件 ClickableSpan clickableSpan = new ClickableSpan() { @Override public void onClick(View widget) { Toast.makeText(textView.getContext(), phone, Toast.LENGTH_SHORT).show(); } }; spanText.setSpan(clickableSpan,0, spanText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); return spanText; }
显示数据
根据正则表达式匹配分割字符串然后截取替换再重新组合
public static void setText(TextView textView, String str){ if(str.matches(regEx)){ textView.setText(""); String[] splitStrs = str.split(splitRegex); int num = splitStrs.length; int temp = 0; for(int i =0; i < num; i++){ textView.append(splitStrs[i]); if((i+1) != num){ int n = splitStrs[i].length(); n += temp; int m = str.indexOf(splitStrs[i+1], n); String usr = str.substring(n, m); temp = n + usr.length(); textView.append(getSpan(textView,usr)); Log.d("@Span",usr); } } }else{ textView.setText(str); } }
如果要获取textView中的原始字符串只需要使用
textView.getText().toString()即可。
监听EditText的输入事件当用户输入@的时候跳转到联系人选择
editText.addTextChangedListener(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) { Log.d("onTextChanged","start="+start+" before="+before+" count="+count); if(start==s.length()-1 && s.toString().endsWith("@")){ //TODO 用户输入@ } } @Override public void afterTextChanged(Editable s) { } });
==注意事项==
如果要给@块添加点击事件需要添加下面的代码
//TextView textView.setMovementMethod(LinkMovementMethod.getInstance()); //EditText editText.setMovementMethod(LinkMovementMethod.getInstance());
如果有保存草稿的功能,当草稿以“@”结尾的时候,还原草稿不应该触发EditText的监听,所以应该在还原草稿之后再添加监听事件,这个时候如果已经添加了TextWatcher的话应该先调用
editText.removeTextChangedListener()移除监听。
Demo下载地地址 http://download.csdn.net/detail/w804518214/9758786
下载到的文件是个AndroidStudio Module请在你自己的新建工程内选择import module;
相关文章推荐
- Android 添加联系人发短信以及打电话功能实现
- Android手机联系人源码(添加联系人页面一个功能)修改
- android 联系人中添加手机铃声功能的实现
- Android编程实现通讯录中联系人的读取,查询,添加功能示例
- Android编程实现通讯录中联系人的读取,查询,添加功能示例
- 在Android 中调用选择图片、视频、添加音频、录音、拍摄视频、拍照等其他的功能
- android reboot 功能的添加
- android 中如何添加新的键值,实现更多功能
- android 中如何添加新的键值,实现更多功能
- 为android程序添加版本自动更新功能(转+详细分析) -转自eoeandroid
- Android 删除手机联系人,添加手机联系人,更新手机联系人信
- Android 添加删除联系人2.0之前与2.0之后
- 【Android自学笔记】为Android应用程序添加Rate功能
- android2.3 -添加自定义按键:作唤醒功能
- Android中实现Launcher功能之二 ----- 添加窗口小部件以及AppWidget的创建详解
- Android中实现Launcher功能之一 ----- 添加快捷方式
- 向Android系统自带的联系人界面添加数据
- 在Android 中调用选择图片、视频、添加音频、录音、拍摄视频、拍照等其他的功能
- 调用系统联系人的添加界面-android
- 为Android应用程序添加社会化分享功能