Android 仿小红书话题功能

        最近公司开始做社区功能,需要输入#号后,服务器模糊查询话题,查看网上代码,始终跟预想中的有些出入,好久没有写自定义控件了,这里边写边记录,方便给需要使用的人,提供一个记录。难点就是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());
                    }
                }
            }
        }

逻辑也比较简单,光标等于其中一个光标时,我就展示弹框,表示用户正在输入。反之隐藏

到这里,就可以完成小红书功能啦~细节部分需要修改。

       

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值