Android仿微信@好友功能 输入@跳转、删除整块
最近在做聊天功能的时候,有一个需求是仿照微信做@好友的功能,本来以为挺简单,但是做到这块的时候,发现和想象的有点不一样,什么整块删除,块可编辑,总之,加个@的功能很简单,但是要做和微信的一样还是费了一些功夫,下面是一个demo仅供参考,防止遗忘
先上个效果图
就是这么个功能
1. 分析需求
输入@跳转到联系人界面,选中一个或者多个好友返回到当前界面
按退格键删除整块内容
块内的内容可编辑,编辑完了之后将不附带@功能,只是单纯的文字
2. 开始编码
既然是文本输入首先继承EditText自定义一个控件
public class MsgEditText extends AppCompatEditText {
public MsgEditText(Context context) {
super(context);
}
public MsgEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MsgEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
到底从哪里开始入手呢,首先完成变成块的需求,
无意中看到这个项目https://github.com/g707175425/CloudEditText ,他是这么写的
private void generateOneSpan(Spannable spannableString, UnSpanText unSpanText) {
//生成一个TextView
View spanView = getSpanView(getContext(), unSpanText.showText.toString(), getMeasuredWidth());
//再将TextView转换为一个图片
BitmapDrawable bitmpaDrawable = (BitmapDrawable) UIUtils.convertViewToDrawable(spanView);
bitmpaDrawable.setBounds(0, 0, bitmpaDrawable.getIntrinsicWidth(), bitmpaDrawable.getIntrinsicHeight());
//最后将这个图片放到Span里,
MyImageSpan what = new MyImageSpan(bitmpaDrawable, unSpanText.showText.toString(),unSpanText.returnText);
final int start = unSpanText.start;
final int end = unSpanText.end;
spannableString.setSpan(what, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//设置一个Span
spannableString.setSpan(touchableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
看到这里我们就记得了一个关于SpanableString的用法,它可以设置图片,可以随意的设置文字的背景的前景,等等一系列比较酷炫的效果,而且只需要一个TextView,如果需要深入了解Span,可自行百度和Google,关于Span的进阶用法,于是就有了下面的实现
//这个是需要成块删除的内容
private class MyTextSpan extends MetricAffectingSpan {
private String showText;
private long userId;
//userId是为了适应需求,如果不需要请自行去掉
public MyTextSpan(String showText, long userId) {
this.showText = showText;
this.userId = userId;
}
public String getShowText() {
return showText;
}
public long getUserId() {
return userId;
}
@Override
public void updateMeasureState(TextPaint p) {
}
@Override
public void updateDrawState(TextPaint tp) {
}
}
//这个是非整块删除的内容,当然你如果想也是可以删除的
private class UnSpanText {
int start;
int end;
String returnText;
UnSpanText(int start, int end, String returnText) {
this.start = start;
this.end = end;
this.returnText = returnText;
}
}
刚开始我是这么写的
//外部调用一个增加Span的方法
public void addSpan(String showText, String returnText, long userId) {
getText().append(showText);
SpannableString spannableString = new SpannableString(getText());
makeSpan(spannableString, new UnSpanText(spannableString.length() - showText.length(), spannableString.length(), showText, returnText), userId);
setText(spannableString);
setSelection(spannableString.length());
}
//生成一个需要整体删除的Span
private void makeSpan(Spannable sps, UnSpanText unSpanText, long userId) {
MyTextSpan what = new MyTextSpan(unSpanText.returnText, userId);
int start = unSpanText.start;
int end = unSpanText.end;
sps.setSpan(what, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
写到现在这个整块添加已经做好了,下面开始做整块删除,刚开始的时候我是模仿上面的CloudEditText写的,但我发现好像会用各种问题,于是想了一种方法
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
//向前删除一个字符,@后的内容必须大于一个字符,可以在后面加一个空格
if (lengthBefore == 1 && lengthAfter == 0) {
MyTextSpan[] spans = getText().getSpans(0, getText().length(), MyTextSpan.class);
for (MyTextSpan myImageSpan : spans) {
if (getText().getSpanEnd(myImageSpan) == start && !text.toString().endsWith(myImageSpan.getShowText())) {
getText().delete(getText().getSpanStart(myImageSpan), getText().getSpanEnd(myImageSpan));
break;
}
}
}
}
上面的意思就是,如果你在EditText中执行删除一个字符的时候,判断前面一个是否是一个Span,如果是自定义的Span就把Span一同删除,关于这个,我可是测试可各种操作才定为这样的
最后是获取需要@的人员名单
//获取用户Id列表,这只是个参考,可根据需求修改
public String getUserIdString() {
MyTextSpan[] spans = getText().getSpans(0, getText().length(), MyTextSpan.class);
StringBuilder builder = new StringBuilder();
for (MyTextSpan myTextSpan : spans) {
String realText = getText().toString().substring(getText().getSpanStart(myTextSpan), getText().getSpanEnd(myTextSpan));
String showText = myTextSpan.getShowText();
if (realText.equals(showText)) {
builder.append(myTextSpan.getUserId()).append(",");
}
}
if (!TextUtils.isEmpty(builder.toString())) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.toString();
}
最后我就大方的放个地址你们自己看吧
https://github.com/ddssingsong/AtFriend
总结
以上所述是小编给大家介绍的Android仿微信@好友功能 输入@跳转、删除整块,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对ZaLou.Cn网站的支持!
- WCF技术剖析之六:为什么在基于ASP.NET应用寄宿(Hosting)下配置的BaseAddress无效
- 微信发布了小游戏,这一次腾讯 vs 世界
- .Net 转战 Android 4.4 日常笔记(5)--新软件Android Studio 0.5.8安装与配置及问题解决
- 第2章 对象激活上下文-对象激活
- .Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化
- .Net 转战 Android 4.4 日常笔记(3)--目录结构分析
- .Net 转战 Android 4.4 日常笔记(2)--HelloWorld入门程序
- 读书笔记(二)对象激活和上下文
- 程序员的噩梦有哪些?除了改需求,还有这些…
- UC Berkeley提出新型分布式执行框架Ray:有望取代Spark
- 卡奇话爬虫使用方法以及下载地址
- flash读取XML 背景自动适应大小
- 记录一个发邮件的cs文件
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(56)-插件---单文件上传与easyui使用fancybox
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Hexo+Gitee pages搭建个人博客
- ubuntu设置定时任务的三种方法
- Centos7 离线安装MySQL
- springboot 事务,多张表的操作事务回滚
- 移动硬盘显示盘符但是打不开,提示加密
- GORM V2 模型定义、约定、标签
- 字符串:简单的反转还不够!
- TypeScript 实战算法系列(七):实现图的遍历
- 63. Vue MUI的基本使用
- 初学web自动化测试--笔记1
- R语言作图——Line plot with error
- Python自学成才之路 玩转虚拟环境
- 基于腾讯云的 Rust 和 WebAssembly 函数即服务
- 谷歌开源NLP模型可视化工具LIT,模型训练不再「黑箱」
- Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方案