用最简单且兼容性最好的方式去实现dialog的有序列表

用最简单且兼容性最好的方式去实现dialog的有序列表

最近项目开发,遇到这样一个dialog的需求,请看图:

用最简单且兼容性最好的方式去实现dialog的有序列表_第1张图片

这里有一个细节,如 2. 那条,如果文字长度超过一行,下一行文字是从序号后边对齐的。

要实现这种dialog,也厚很多种实现方式

  1. 自定义 dialog 布局,把内容写死在里边
  2. 用 html 标签来完成这种布局
  3. 自定义 LeadingMarginSpan ,用 SpannableStringBuilder 拼接字符串来实现(本篇的主要内容)

第一种方式(自定义 dialog 布局)

应该大多数人都会的,就是麻烦一点。


第二种方式(html 标签)

相比第一种简单了很多,直接用 Html.fromHtml() 来包裹 html标签的内容就可以了。起初我用的是这种方式,测试后也没问题,但在魅族手机上发现, html 标签有的不识别(文字前边的序号没有出来),对开发者来说 android 的开源有时候也会带来麻烦。。只好重新研究实现方式了。


第三种方式(自定义 LeadingMarginSpan)
/**
 * A paragraph style affecting the leading margin. There can be multiple leading
 * margin spans on a single paragraph; they will be rendered in order, each
 * adding its margin to the ones before it. The leading margin is on the right
 * for lines in a right-to-left paragraph.
 * 

* LeadingMarginSpans should be attached from the first character to the last * character of a single paragraph. */

这是 LeadingMarginSpan 的官方注释,大致意思就是 它可以影响一个段落的文字的起始 margin 值(原谅我的英语渣水平。。。)

ok,重点来了,下面就是自定义这货来实现 dialog 的有序列表了,好上代码:

public class NumberIndentSpan implements LeadingMarginSpan {

    private int gapWidth;
    private final int index;

    public NumberIndentSpan(int index) {
        this.index = index;
    }

    public int getLeadingMargin(boolean first) {
        return gapWidth;
    }

    public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout l) {
        if (first) {
            Paint.Style orgStyle = p.getStyle();

            p.setStyle(Paint.Style.FILL);

            String text1 = index + ". ";
            float width = p.measureText(text1);
            gapWidth = (int) width;
            com.orhanobut.logger.Logger.d(dir + "");
            com.orhanobut.logger.Logger.d(width + "");
            com.orhanobut.logger.Logger.d(x + "");
            c.drawText(text1, x, baseline, p);

            p.setStyle(orgStyle);
        }
    }
}
使用姿势

项目的设计是,api 成功后,返回一个 string 类型的集合,本地通过 dialog 去显示有序文本内容:

private void showSuccessTip(List completeStrs) {
        SpannableStringBuilder completeStr = new SpannableStringBuilder();
        completeStr.append("请留意:\n");
        for (int i = 0; i < completeStrs.size(); i++) {
            int contentStart = completeStr.length();
            completeStr.append(completeStrs.get(i)).append("\n");
            NumberIndentSpan numberIndentSpan = new NumberIndentSpan(i + 1);
            completeStr.setSpan(numberIndentSpan, contentStart, completeStr.length(), 0);
        }

这种方式我认为应该是最简单兼容性最好的方式了吧,


ok,今天就到这里了,如有不同意见欢迎拍砖~


更正一下一个内容

第三种自定义 LeadingMarginSpan,这种方法虽然实现了,但是发现控件测量字符串的宽度不准确了,靠近右边缘的字体有的被遮住半个,如图:

用最简单且兼容性最好的方式去实现dialog的有序列表_第2张图片

又研究了一下 LeadingMarginSpan 这个类,发现了一种神奇的东西 LeadingMarginSpan.Standard

第四种方式(LeadingMarginSpan.Standard)

Standard 类是 LeadingMarginSpan 的一个内部类,它有三个构造方法,如下:

/**
         * Constructor taking separate indents for the first and subsequent
         * lines.
         * 
         * @param first the indent for the first line of the paragraph 段落第一行距离左边的间距
         * @param rest the indent for the remaining lines of the paragraph 段落除第一行外剩下所有行距离左边的间距
         */
        public Standard(int first, int rest) {
            mFirst = first;
            mRest = rest;
        }

        /**
         * Constructor taking an indent for all lines.
         * @param every the indent of each line
         */
        public Standard(int every) {
            this(every, every);
        }

        public Standard(Parcel src) {
            mFirst = src.readInt();
            mRest = src.readInt();
        }

ok,我们用到的就是 Standard(int first, int rest) ,下边贴出使用方法:

private void showSuccessTip(List completeStrs) {
        SpannableStringBuilder completeStr = new SpannableStringBuilder();
        completeStr.append("请留意:\n");
        for (int i = 0; i < completeStrs.size(); i++) {
            int contentStart = completeStr.length();

            String leadStr = (i + 1) + ". ";
            completeStr.append(leadStr);
            completeStr.append(completeStrs.get(i));
            completeStr.append("\n");

            int contentEnd = completeStr.length();
            completeStr.setSpan(new LeadingMarginSpan.Standard(0, (int) mRightMenu.getPaint().measureText(leadStr))
                    , contentStart, contentEnd, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        }

        MaterialDialogUtil.showSendSuccessTip(_mActivity, "提问成功", completeStr
                , new MaterialDialog.SingleButtonCallback() {
                    @Override
                    public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                        pop();
                    }
                });
    }

这里不需要自定义什么类就完成了,无疑是最省事的,可见如果对 android 本身了解的不多,是要做多少无用功。。

以此自勉,继续奋进吧

你可能感兴趣的:(android)