zoukankan      html  css  js  c++  java
  • 仿小米便签图文混排 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); 
  • 相关阅读:
    C++调用web服务(java事例供参考)
    ASP.NET1.1与2.0如何引入MagicAjax (转载自http://hi.baidu.com/zzticzh)
    爱,在世界末日时
    Why Google Chrome is Multiprocess Architecture
    Chrome
    Code Reuse in Google Chrome
    Google V8 JavaScrit 研究(1)
    第一篇文章
    User Experience
    WPF
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/4206515.html
Copyright © 2011-2022 走看看