赞
踩
最近公司开始做社区功能,需要输入#号后,服务器模糊查询话题,查看网上代码,始终跟预想中的有些出入,好久没有写自定义控件了,这里边写边记录,方便给需要使用的人,提供一个记录。难点就是EditText中操作话题的逻辑了
先看目前暂时实现的效果,已经完成90%的功能了
功能如下:
1.输入#号后,我这里底部隐藏了一个布局(里面展示服务器返回模糊搜索结果),通过删除和输入#来控制隐藏
2.输入后,话题字体变色
3.支持多个话题,当移动到话题部分, 自动弹框服务器返回模糊搜索结果
目前论坛上提供的思路,差不多,这里主要是细节分享
1.android 键盘有中英文#。正则需要修改[\#|#]
2.有一个功能,是选中全部删除,如果业务需要实时更新模糊输入结果,这里可不需要
3.滑动到某一个话题时,重新弹框展示服务器返回结果
思路代码
一、找到话题
private final String inputReg = "([\\#|#][\u4e00-\u9fa5a-zA-Z]+\\d{0,100})";
封装一个实体类保存
- public class TopicBean {
-
- private String topicRule = "#";// 匹配规则
- private String topicText;// 高亮文本
-
- public int start;
- public int end;
-
- }
如果使用,来匹配满足条件即为一个话题。监听addTextChangedListener事件:
- this.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
- }
-
- @Override
- public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
- }
-
- @Override
- public void afterTextChanged(Editable editablede) {
- Editable editable = getText();
- int length = editablede.toString().length();
-
- //赋值话题列表数据
- Matcher matcher = pattern.matcher(editable);
-
- mTopicList.clear();
-
- while (matcher.find()) {
- TopicBean tObject = new TopicBean();
- tObject.setTopicText(editable.toString().substring(matcher.start(), matcher.end()).trim());
- tObject.start = matcher.start();
- tObject.end = matcher.end();
- mTopicList.add(tObject);
- }
-
- //记录上一次的长度
- preTextLength = length;
-
- //刷新页面
- refreshEditTextUI(editable.toString());
- }
- });
-

这里的逻辑,其实还比较简单,while循环,找出所有文本中,符合话题#号后的字,存放在List集合中
二、话题变色
通过刷新方法refreshEditTextUI()我们来改变颜色
- private void refreshEditTextUI(String content) {
-
- /*
- * 重新设置span
- */
- Editable editable = getText();
- int textLength = editable.length();
-
- int findPosition = 0;
- if (mTopicList != null && mTopicList.size() > 0) {
- for (int i = 0; i < mTopicList.size(); i++) {
- final TopicBean object = mTopicList.get(i);
- // 文本
- String objectText = object.getTopicText();
- while (findPosition <= textLength) {
- // 获取文本开始下标
- findPosition = content.indexOf(objectText, findPosition);
- if (findPosition != -1) {
- // 设置话题内容前景色高亮
- ForegroundColorSpan colorSpan = new ForegroundColorSpan(mForegroundColor);
- editable.setSpan(colorSpan, findPosition, findPosition + objectText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- findPosition += objectText.length();
- } else {
- break;
- }
- }
-
- }
- }
-
- }

这块代码我就直接引用原作者代码片段了,这里ForegroundColorSpan就是改变颜色的
三、如果找到#标识
EditText中可以选择当前的光标位置,所以我们要重写onSelectionChanged这个方法,这个是当前光标移动的方法
1.如何知道用户输入了什么
char charAt = getText().toString().charAt(selEnd - 1);
所以通过以上可以确定2个事件,一个是#开始,一个结束(结束可以已除中文数字外,其余都算结束)
这里我临时测试写了一份,可以替换成正则实现:
- if (value.equals("#") || value.equals("#")) {
- Log.e("测试代码","onSelectionChanged 检查到光标前一位是 # 或者# 当前位置是" + selEnd);
- mStartSymbolPosition = selEnd - 1;
- if (mListener != null) {
- mListener.onUserInputStart(selEnd);
- }
- return;
- } else if (value.equals(" ") || value.equals("\n")) {
- Log.e("测试代码","onSelectionChanged 最后一位状态");
- mLastSymbolPosition = selEnd;
- if (mListener != null) {
- mListener.onUserInputEnd(selEnd);
- }
- mStartSymbolPosition = 0;
- mLastSymbolPosition = 0;
- } else if (mStartSymbolPosition >= selEnd) {
- Log.e("测试代码","onSelectionChanged 用户做了删除动作并且删除到#号了 ");
- if (mListener != null) {
- mListener.onUserInputEnd(selEnd);
- }
- }

四、支持多个话题监听
这里还有一个场景,如果一个文章里有3个话题,那么如何做到,滑动到话题,我们就弹出话题模糊搜索呢,这里就需要在光标移动的时候做处理了。判定坐标,在某一个话题位置范围内。代码如下:
- if (mTopicList != null) {
- for (int i = 0; i < mTopicList.size(); i++) {
- Log.e(TAG, "onSelectionChanged = " + mTopicList.get(i));
- if (selEnd == mTopicList.get(i).getEnd()) {
- //表示用户回到了话题最后的位置,我们又要进入输入模式
- if (mListener != null) {
- mListener.onUserInputStart(mTopicList.get(i).getStart());
- }
- mStartSymbolPosition = mTopicList.get(i).getStart();
- mLastSymbolPosition = mTopicList.get(i).getEnd();
- }
- if (selEnd > mTopicList.get(i).getEnd()) {
- if (mListener != null) {
- mListener.onUserInputEnd(mTopicList.get(i).getEnd());
- }
- }
- }
- }

逻辑也比较简单,光标等于其中一个光标时,我就展示弹框,表示用户正在输入。反之隐藏
到这里,就可以完成小红书功能啦~细节部分需要修改。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。