码迷,mamicode.com
首页 > 其他好文 > 详细

高仿SinaWeibo新浪微博发布页面话题效果

时间:2015-08-10 00:18:19      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:edittext   微博   话题   话题变色   android   

最近做了一个仿新浪微博话题效果的功能,网上搜索了几个效果,都存在一定问题,最终借鉴别人的思路,完成这一套效果.

首先,我们拆分逻辑以及开发顺序.

1,实现话题变色效果
2,实现插入话题效果
3,实现话题选中删除效果
4,实现点击话题,光标在话题之后

技术分享

下面我们就一步一步实现效果.


一,实现话题变色

实现逻辑主要是通过EditTextaddTextChangedListener()来进行监听文本变动,通过正则表达式来匹配出文本中的话题.

利用正则表达式获取全部话题:
//正则表达式,一定要和服务器以及 iOS 端统一
private static final String topicRegex = "#([^#]+?)#";
public static ArrayList<String> findTopic(String s) {

        Pattern p = Pattern.compile(topicRegex);
        Matcher m = p.matcher(s);

        ArrayList<String> list = new ArrayList<>();
        while (m.find()) {
            list.add(m.group());
        }

        return list;
}
通过正则表达式匹配出的话题集合,遍历出每个话题的 startIndex 位置(后来发现Matcher方法是有获取 index 的方法),并且通过EditText.getText()方法获取的Editable直接对文本进行操作:
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
        Log.i("MainActivity", "onTextChanged");
        if (TextUtils.isEmpty(s)) return;
        //1,查找话题
        String content = s.toString();
        mTopicList.clear();
        mTopicList.addAll(findTopic(s.toString()));

        //2,为查找出的变色
        //首先要为editable,去除之前设置的colorSpan
        Editable editable = mEditText.getText();
        for (int i = 0; i < mColorSpans.size(); i++) {
            editable.removeSpan(mColorSpans.get(i));
        }
        mColorSpans.clear();
        //为editable,中的话题加入colorSpan
        int findPos = 0;
        int size = mTopicList.size();
        for (int i = 0; i < size; i++) {//便利话题
            String topic = mTopicList.get(i);
            findPos = content.indexOf(topic, findPos);
            if (findPos != -1) {
                ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.BLUE);
                editable.setSpan(colorSpan, findPos, findPos = findPos + topic.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                mColorSpans.add(colorSpan);
            }
        }
}

二,实现插入话题效果

新浪微博的插入话题效果,是开启一个新的页面,点击一个话题后,插入光标所在的位置.这里我用一个按钮模仿了这个动作.要注意的是,要记录插入之前光标的位置,并且在插入话题后,把光标放置在话题之后:

if (v.getId() == R.id.button) {
            //插入话题
            int selectionStart = mEditText.getSelectionStart();
            //下面这些操作也可以直接替换为操作 EditText 的Editable实现,下面的代码 review 后看起来由点蠢,直接调用 insert 方法比较巧妙
            String content = mEditText.getText().toString();

            String firstStr = content.substring(0, selectionStart);
            String secondStr = content.substring(selectionStart, content.length());

            String insertTopic = "#这是一个插入的话题#";
            mEditText.setText(firstStr + insertTopic + secondStr);
            mEditText.setSelection(selectionStart + insertTopic.length());
}

三,实现话题选中删除效果

这里也是要时时判断光标所在的位置,当光标出现在话题之后,再次点击删除,就截获为选中话题效果,实现起来也是很简单的.

但是要注意的是,我们不能利用 activity 里面的onKeyDown()onKeyUp()两个回调,通过 log 发现文本变动和按键点击的回调顺序为beforeTextChanged->onTextChanged->afterTextChanged->onKeyDown->onKeyUp.

这也说明了如果通过 拦截onKeyDown()onKeyUp()两个回调时,文本是已经删除之后的文本,并能有效的达到我们要实现的目的,那么有没有是文本改变之前就能截取到按键的方法呢?

其实我们可以通过监听EditTextsetOnKeyListener()方法来监听按键(onKey->beforeTextChanged->onTextChanged->afterTextChanged->onKeyDown->onKeyUp):

@Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        Log.i("MainActivity", "onKey");
        if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN && mCheckBox2.isChecked()) {

            int selectionStart = mEditText.getSelectionStart();
            int selectionEnd = mEditText.getSelectionEnd();
            //如果光标起始和结束在同一位置,说明是选中效果,直接返回 false 交给系统执行删除动作
            if (selectionStart != selectionEnd) {
                return false;
            }

            Editable editable = mEditText.getText();
            String content = editable.toString();
            int lastPos = 0;
            int size = mTopicList.size();
            //遍历判断光标的位置
            for (int i = 0; i < size; i++) {
                String topic = mTopicList.get(i);
                lastPos = content.indexOf(topic, lastPos);
                if (lastPos != -1) {
                    if (selectionStart != 0 && selectionStart >= lastPos && selectionStart <= (lastPos + topic.length())) {
                        //选中话题
                        mEditText.setSelection(lastPos, lastPos + topic.length());
                        return true;
                    }
                }
                lastPos += topic.length();
            }
        }
        return false;
    }

四,实现点击话题,光标在话题之后

逻辑处理就是监听EditText的点击事件,处理光标所在位置,如果在位置在话题内,立即放置在话题的后面,逻辑比较简单,直接上代码:

if (v.getId() == R.id.editText && mCheckBox1.isChecked()) {
            int selectionStart = mEditText.getSelectionStart();

            int lastPos = 0;
            int size = mTopicList.size();
            for (int i = 0; i < size; i++) {
                String topic = mTopicList.get(i);
                lastPos = mEditText.getText().toString().indexOf(topic, lastPos);

                if (lastPos != -1) {
                    if (selectionStart >= lastPos && selectionStart <= (lastPos + topic.length())) {
                        //在这position 区间就移动光标
                        mEditText.setSelection(lastPos + topic.length());
                    }
                }
                lastPos = lastPos + topic.length();
            }
        }

最终还是有点小遗憾没有完成.当拷贝一段已经变色的话题,再粘贴到文本后,无法删除掉拷贝进来文本的变色效果,尝试调用Editable.clearSpans()去除全部 span 也无法实现,并且这个方法会导致直接卡死.后来直接使用EditText.setText()控制文本,确实达到了效果,但是当输入法是类似 mx4默认输入法效果时(效果大概是,输入的拼音直接显示在 EditText 里面,点击被选汉字,替换掉拼音),会把输入的拼音放入到文本里,所以上面的代码,我一般是直接操作 Editable.

如果有更好的方法或者修复了上面的小遗憾,请留言指教.

转载请注明出处:http://www.kennethyo.me/post/android/2015-08-09

版权声明:本文为博主原创文章,未经博主允许不得转载。

高仿SinaWeibo新浪微博发布页面话题效果

标签:edittext   微博   话题   话题变色   android   

原文地址:http://blog.csdn.net/kennethyo/article/details/47377353

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!