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

来源:互联网 发布:知乎qq不能登陆了 编辑:程序博客网 时间:2024/06/03 12:42

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

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

这里写图片描述

这里有一个细节,如 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. * <p> * 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<String> 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,这种方法虽然实现了,但是发现控件测量字符串的宽度不准确了,靠近右边缘的字体有的被遮住半个,如图:

这里写图片描述

又研究了一下 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<String> 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 本身了解的不多,是要做多少无用功。。

以此自勉,继续奋进吧

阅读全文
0 0