仿小米便签图文混排 EditText解决尾部插入文字bug

一直想实现像小米便签那样的图文混排效果,收集网上的办法无非三种:
1、自定义布局,每张图片是一个ImageView,插入图片后插入EditText,缺点是实现复杂,不能像小米便签那样同时选中图片和文字
2、通过Html.fromHtml(source),可以将图片加载写进ImageGetter,实现后无bug,但是只能显示Html,当EditText setText后,想取出之前的HTML格式
     图片得到的是一个obj的字符,查看了很多博客,包括stackoverflow也没给出办法从editable中解析出spanned对象。若谁有方法希望不吝啬告诉我。
3、通过ImageSpan和SpannableString,这是我实现的方法,而且较为理想,不但可以写入EditText,也可以从EditText中解析出图文混排排版。

1、插入图片到光标位置

/**
     * 将图片路径映射到Bitmap,再通过SpannableString 和 ImageSpan显示到EditText
     */
    private void setImageView() {
        // 如果EditText中已经有相同资源的ImageSpan,则不再读取图片
        ImageSpan imageSpan = getImageSpanFromExistence(imagePath);
        if (imageSpan != null) {
            insertIntoEditor(imageSpan, imagePath);
            return;
        }

        if (imagePath != null && (!imagePath.equals("null"))
                && (!"".equals(imagePath))) {
            insertIntoEditor(imagePath);
            /*
             * 不再用缓存模式
             */
        }
    }

/**
     * 从当前的EditText获取ImageSpan,如果存在则返回否则返回Null
     *
     * @return
     */
    private ImageSpan getImageSpanFromExistence(String source) {
        Editable edit = contentText.getText();
        ImageSpan[] spans = edit.getSpans(0, edit.length(), ImageSpan.class);
        for (ImageSpan ip : spans) {
            int start = edit.getSpanStart(ip);
            int end = edit.getSpanEnd(ip);
            String path = edit.toString().substring(start, end);
            path = path.substring(5, path.length() - 5);

            if (source.equals(path)) {
                Logg.D("find existed ImageSpan");
                return new ImageSpan(ip.getDrawable(), ImageSpan.ALIGN_BASELINE);
            }
        }
        return null;
    }

/**
     * 向光标位置插入ImageSpan,针对EditText已经有ImageSpan的情况
     *
     * @param ip
     *            ImageSpan
     * @param path
     *            路径
     */
    private void insertIntoEditor(ImageSpan span, String path) {
        if(("<img " + path + " img>").length()+contentText.getText().length() > MAX_CONTENT){
            Toast.makeText(getApplicationContext(), R.string.toast_reached_max_text, 2000).show();
            return;
        }
        SpannableString ss = new SpannableString("<img " + path + " img>");
        if (span == null)
            throw new NullPointerException("span cant be null");
        ss.setSpan(span, 0, ("<img " + path + " img>").length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        Editable et = contentText.getText();// 先获取Edittext中的内容
        int start = contentText.getSelectionStart();
        et.insert(start, ss);// 设置ss要添加的位置
        contentText.setSelection(start + ss.length());// 设置Edittext中光标在最后面显示
        Logg.D("insertIntoEditor by using existed ImageSpan");
    }

/**
     * 向光标位置插入ImageSpan,针对EditText没有图片的情况
     *
     * @param path
     *            图片路径
     */
    private void insertIntoEditor(String path) {
        if(("<img " + path + " img>").length()+contentText.getText().length() > MAX_CONTENT){
            Toast.makeText(getApplicationContext(), R.string.toast_reached_max_text, 2000).show();
            return;
        }
        SpannableString ss = new SpannableString("<img " + path + " img>");
        // 不再用缓存模式
        // Bitmap bm = mEditorHelper.getImage(path);
        Bitmap bm = PictureHelper.getImageFromPath(imagePath,
                screenWidth * 0.7F, screenWidth * 0.7F, false, 100,
                Editor.this, imgPadding, false);
        if (bm == null) {
            throw new NullPointerException("bm cant be null");
        }

        ImageSpan span = new ImageSpan(this, bm, ImageSpan.ALIGN_BASELINE);
        ss.setSpan(span, 0, ("<img " + path + " img>").length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        Editable et = contentText.getText();// 先获取Edittext中的内容
        int start = contentText.getSelectionStart();
        et.insert(start, ss);// 插入图片到光标处
//        contentText.setSelection(start + ss.length());// 设置Edittext中光标在最后面显示
        Logg.D("insertIntoEditor by loading new");
    }

以上插入图片前会查找edittext有没有相同地址的ImageSpan,如果有则不再读取新的Bitmap,直接复用drawable

2、解决尾部插入Bug\

Bug来源:http://www.baidufe.com/item/65fd7eba51123bbe80bc.html
一直没能理解作者说的半角站位
我实现了一个方法,当光标到达图片末尾,直接跳转至正确位置
实现:http://mxw3755.iteye.com/admin/blogs/2164905
当光标嵌入spannableString的字符从末尾前一位,我们可以将光标位置+1,这样光标会在两张图之间
3、如何保存解析图文混排的EditText

可以将ImageSpan的位置保存到Arraylist中,怎么保存至数据库请参考 http://mxw3755.iteye.com/admin/blogs/2165147

 android 图文结合,使用SpannableString和ImageSpan类

    Drawable drawable = getResources().getDrawable(id);
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        //需要处理的文本,[smile]是需要被替代的文本
        SpannableString spannable = new SpannableString(getText().toString()+"[smile]");
        //要让图片替代指定的文字就要用ImageSpan
        ImageSpan span = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
        //开始替换,注意第2和第3个参数表示从哪里开始替换到哪里替换结束(start和end)
       //最后一个参数类似数学中的集合,[5,12)表示从5到12,包括5但不包括12
        spannable.setSpan(span, getText().length(),getText().length()+"[smile]".length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        setText(spannable); 
时间: 2024-08-08 01:27:58

仿小米便签图文混排 EditText解决尾部插入文字bug的相关文章

超全css解决方案之图文混排解决方案

第一种方法:背景图片法 这种方法适用于非动态内容,图片用于装饰的情况下.主要是设置父元素的padding的宽度为背景图片的宽度加上图片和文字的间距,然后把背景图片定位到padding里面就可以了 图文混排demo1,背景图片法    //因是转载的,我又是菜鸟,下面图片乱了,正确的是图片跟文字都在一行. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pel

使用android SpannableStringBuilder实现图文混排,查看更多

项目开发中需要实现这种效果 多余两行,两行最后是省略号,省略号后面是下拉更多 之前用过的是Html.fromHtml去处理图文混排的,仅仅是文字后图片或者文字颜色字体什么的, 但是这里需要在最后文字的省略号后面添加图片. 直接上代码吧,代码注释很多,慢慢研究 private void toggleEllipsize(final TextView tv,final String desc){ if(desc == null){ return; } tv.getViewTreeObserver().

仿QQ聊天图文混排流程图【适用于XMPP】

图文混排流程图.graffle4.8 KB 下面附上图片素材: 表情.zip692.5 KB 下面是字符串与图片的详细对应关系: "[呲牙]"字符串对应于图片名    f000.gif; "[调皮]"字符串对应于图片名    f001.gif; "[流汗]"字符串对应于图片名    f002.gif; "[偷笑]"字符串对应于图片名    f003.gif; "[再见]"字符串对应于图片名    f004.

关于仿网易新闻中详细页图文混排功能的实现

最近在了解关于新闻内容的图文混排的效果,网上有人开源一个仿网易新闻的代码,本文就是简单记录学习其详细页面显示的效果实现: 下载地址:https://github.com/dsxNiubility/SXNews 效果图: 其原理:通过网络请求获得相关的信息,再通过手机端进行拼HTML,然后在WebView进行展示,此处还对文章中的图片增加点击效果,可以保存到相册中:文章的样式已经存在项目中,直接去调用: 1:首先了解两个相关的实体对象,一个是新闻的主体内容,另外一个就是图片的相关信息实体: 1:主

Android图文混排(一)-实现EditText图文混合插入上传

前段时间做了一个Android会议管理系统,项目需求涉及到EditText的图文混排,如图: 在上图的"会议详情"中,需要支持文本和图片的混合插入,下图演示输入的示例: 当会议创建完成以后,保存数据到服务器,然后查看刚刚创建好的会议,如图: 一.明确需求 首先,点击"会议详情"文本框中,正常输入文本,然后点击左下角的图片图标,进入系统的相册用来选择一张图片并插入到文本框中,你还可以将光标停留在任意的文字中间,完成图片的插入,回退建即可以逐个删除文字,也可以删除图片.

EditText图文混排

下面就具体说一下我遇到的问题,首先是EditText里面的图文混排问题,这个问题的难点就是三点: 1.怎么插图片 2.怎么保存插入的图片和文字 3.怎么解析回图片和文字 解决: 一.怎么插入图片 在这里定义了两个Button按钮和一个EditText,插入图片的话,就是点击插入图片按钮然后从sd卡中选择一张图片出来.下面是实现代码: 首先是button的监听事件: btn_insertImage.setOnClickListener(new OnClickListener() { @Overri

Android图文混排-实现EditText图文混合插入上传

前段时间做了一个Android会议管理系统,项目需求涉及到EditText的图文混排,如图: 在上图的"会议详情"中.须要支持文本和图片的混合插入,下图演示输入的演示样例: 当会议创建完毕以后,保存数据到server.然后查看刚刚创建好的会议.如图: 一.明白需求 首先.点击"会议详情"文本框中,正常输入文本,然后点击左下角的图片图标.进入系统的相冊用来选择一张图片并插入到文本框中,你还能够将光标停留在随意的文字中间,完毕图片的插入.回退建即能够逐个删除文字,也能够

Android Json数据的解析+ListView图文混排+缓存算法Lrucache 仿知乎

前几天心血来潮,打算根据看知乎的API自己做一个小知乎,定制的过程遇到ListView的优化问题及图片未缓存重加载等等许多问题,解决了以后打算和博友分享一下. 接口数据:http://api.kanzhihu.com/getpostanswers/20150925/archive 首先,Json数据太常用,相信每一位开发者Json的解析都是必备的.我们要准备以下知识: JavaBean,枚举你需要的元素,用来存储数据. 异步加载网络内容的必备途径,多线程加载+AsyncTask两种方式. Jso

DIV+CSS 图文混排的图片居中办法

不少人为了让 Div 图文混排的图片可以居中,给 IMG 套各式各样的 SPAN.DIV.LI 等等,以便于使用 text-align来进行居中. 1 <div>图文混排 2 <br> 3 <span style="text-align:center"><img src="http://www.baidu.com/img/baidu_jgylogo3.gif"></span> 4 </div>