Android富文本编辑器总结(一)

Android的EditText很强大,支持文本缩进,字体设置以及图片的插入,需求很简单,参照有道云笔记……说得简单,有道云笔记反编译出来,看到libynote_lib.so和libynote_lib_img.so这两个库文件心顿时就凉了一半,我们这几只小菜鸟还只是处于应用层开发,不过拼死拼活了大半个月,总算马马虎虎的做出来了,现对这个做一个总结。总结的目的是对该任务的一个记录,该文章也只是个建议及引导,希望对读者有所帮助。


  1. 功能需求
  2. 方案的选择
  3. 实现
  4. 遇到的问题及解决方法
  5. 总结

  1. 需求:可以使用有道云笔记大致玩一玩,不得不说这个app确实做得好,虽说也有很多bug,但是使用简便,功能强大,对于那些bug自然而然也就不在意了。

    a. 序号排版:1.支持段落编号,当当前行有编号时,点击回车键,下一行能够自动显示编号并且+1;2.支持多级缩进编号。
    b.图片的添加:1.支持添加@XXX,@XXX作为一个整体,光标只能选择在这个整体之前或者之后,删除的时候必须整体删除;2.支持添加大图片功能。
    c.字体设置:1.支持文本的加粗、斜体、颜色、下划线等。
    d.键盘的显示和隐藏:1.支持点击打开键盘,再次点击关闭键盘。

  2. 方案的选择
    a. 使用多个EditText纵向排列,每个作为一个对象,每个可以管理自己的二级段落,递归管理。这样的好处是方便管理,并且添加的图片可以以控件的形式添加,放大缩小功能等都容易实现;缺点也很明显,无法跨多个EditText选择文本。
    b. span相关使用,详情请点这里→_→《Spans,一个强大的概念》,牛人的总结非常详细;这个可以很好地实现我们想要的效果,但是也有一定的缺陷。

  3. 实现
    a.编号的序号。
    编号分三类,序号类1234,abcd,I II罗马数字;无序类●○□;无编号类。其中无序类容易实现,序号类比较麻烦,先给出序号类编号算法。
    先给出接口父类IOrderIndex.java

public interface IOrderIndex {
    public String getIndexString(int index);
}

数字类NumberIndex.java

public class NumberIndex implements IOrderIndex{

    @Override
    public String getIndexString(int index) {

        return index + "";
    }

}

英文字母类EnglishLetterIndex.java

public class EnglishLetterIndex implements IOrderIndex {

    String[] array = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };

    @Override
    public String getIndexString(int index) {

        String result = "";
        result = switchNumToLetter(index);
        return result;
    }

    public String switchNumToLetter(int index) {
        if (index <= 0) {
            return "";
        }
        String out = "";
        int count = 26;
        if (index > 0 && index <= count) {
            out = array[index - 1];
            return out;
        } else {
            if (index % count == 0) {
                out = switchNumToLetter(index / count - 1) + array[count - 1];
            } else {
                out = switchNumToLetter(index / count) + switchNumToLetter(index - (index / count) * count);
            }
        }
        return out;
    }

}

罗马数字类RomanNumberIndex.java

public class RomanNumberIndex implements IOrderIndex{

    public static final String TAG = "note";

    @Override
    public String getIndexString(int index) {
        String result = "";
        result = intToRoman(index);
        return result;
    }

    /**
     * @param s
     *            - String Roman
     * @return int number
     */
    public int romanToInt(String s) {
        if (s.length() < 1)
            return 0;
        int result = 0;
        int current = 0;
        int pre = singleRomanToInt(s.charAt(0));
        int temp = pre;
        for (int i = 1; i < s.length(); i++) {
            current = singleRomanToInt(s.charAt(i));
            if (current == pre)
                temp += current;
            else if (current > pre) {
                temp = current - temp;
            } else if (current < pre) {
                result += temp;
                temp = current;
            }
            pre = current;
        }
        result += temp;
        return result;

    }

    /**
     * @param c
     *            single Roman
     * @return single number
     */
    public int singleRomanToInt(char c) {
        switch (c) {
        case 'I':
            return 1;
        case 'V':
            return 5;
        case 'X':
            return 10;
        case 'L':
            return 50;
        case 'C':
            return 100;
        case 'D':
            return 500;
        case 'M':
            return 1000;
        default:
            return 0;
        }
    }

    /**
     * @param n
     *            - input single int
     * @param nth
     *            must start from 1; 1 <= nth <= 4
     * @return String single Roman
     */
    public String singleDigitToRoman(int n, int nth) {
        if (n == 0) {
            return "";
        }
        nth = 2 * nth - 1; // nth must start from 1
        char singleRoman[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M', 'Z', 'E' }; // never
                                                                                // use
                                                                                // 'Z'
                                                                                // &
                                                                                // 'E'
        StringBuilder rsb = new StringBuilder("");
        if (n <= 3) {
            for (int i = 0; i < n; i++) {
                rsb.append(singleRoman[nth - 1]);
            }
            return rsb.toString();
        }
        if (n == 4) {
            rsb.append(singleRoman[nth - 1]);
            rsb.append(singleRoman[nth]);
            return rsb.toString();
        }
        if (n == 5) {
            return singleRoman[nth] + "";
        }
        if (n >= 6 && n <= 8) {
            rsb.append(singleRoman[nth]);
            for (int i = 0; i < (n - 5); i++) {
                rsb.append(singleRoman[nth - 1]);
            }
            return rsb.toString();
        }
        if (n == 9) {
            rsb.append(singleRoman[nth - 1]);
            rsb.append(singleRoman[nth + 1]);
            return rsb.toString();
        }
        return "ERROR!!!";
    }

    /**
     * @param num
     *            - input number within range 1 ~ 3999
     * @return String Roman number
     */
    public String intToRoman(int num) {
        if (num < 1 || num > 3999) {
            Log.e(TAG, "ERROR input number is 1 ~ 3999");
            return "";
        }
        int temp = num;
        String singleRoman[] = { "", "", "", "" };
        StringBuilder result = new StringBuilder("");
        int digits = 0; // 1 ~ 4
        while (temp != 0) {
            temp = temp / 10;
            digits++;
        }
        temp = num;
        int[] singleInt = new int[digits];
        for (int i = 0; i < digits; i++) {
            singleInt[i] = temp % 10;
            singleRoman[i] = singleDigitToRoman(temp % 10, i + 1);
            temp /= 10;
        }
        for (int i = digits - 1; i >= 0; i--) {
            result.append(singleRoman[i]);
        }
        return result.toString();
    }
}

无序类非常简单
空心圆,属于特殊字符CircleHollowPointIndex.java

public class CircleHollowPointIndex implements IOrderIndex{

    @Override
    public String getIndexString(int index) {
        // TODO Auto-generated method stub
        return "○";
    }

}

实心圆CircleSolidPointIndex.java

public class CircleSolidPointIndex implements IOrderIndex{

    @Override
    public String getIndexString(int index) {
        // TODO Auto-generated method stub
        return "●";
    }

}

正方形实心SquareSolidPointIndex.java

public class SquareSolidPointIndex implements IOrderIndex{

    @Override
    public String getIndexString(int index) {
        // TODO Auto-generated method stub
        return "■";
    }

}

最后是空类型NoneIndex.java

public class NoneIndex implements IOrderIndex{

    @Override
    public String getIndexString(int index) {
        // TODO Auto-generated method stub
        return "";
    }
}

编号的基本生成编码完成,下一篇使用抽象工厂将这些东西组合起来,使用起来更方便。

你可能感兴趣的:(android)