文章目录
效果图代码实现效果图
一般来说每个 app 都有这个用户协议阅读相关的功能,之前做的都是一个协议,也都是单行的,完全没有复杂度,可以一个 checkbox 加上一个 textview 来搞定,那么像图上这种复杂的该怎们实现呢。
代码实现
1. 模拟一个协议数据,创建一个是否阅读的变量
String[] protocols = {"《创客中心产品认购合同》","《创客中心注册申请合同》","《创客中心系统服务合同》","《创客中心服务合同》","《代理协议》"};private boolean isChecked;
2. 创建一个该字符串的 SpannableStringBuilder
final String string = " 已阅读并同意";//图标(默认位选中)spannableStringBuilder = new SpannableStringBuilder(string);setIconSapn(spannableStringBuilder, R.mipmap.app_login_unchecked);//选择按钮的点击事件ClickableSpan imagClick = new ClickableSpan() {@Overridepublic void onClick(View widget) {//显示协议内容if (isChecked) {setIconSapn(spannableStringBuilder, R.mipmap.app_login_unchecked);} else {setIconSapn(spannableStringBuilder, R.mipmap.app_login_checked);}isChecked = !isChecked;mView.setProtocl(spannableStringBuilder);}@Overridepublic void updateDrawState(TextPaint ds) {super.updateDrawState(ds);ds.setUnderlineText(false);ds.setColor(Color.WHITE);}};spannableStringBuilder.setSpan(imagClick, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
3. setIconSapn方法
/*** 设置徐泽状态图标** @param spannableStringBuilder* @param resId*/private void setIconSapn(SpannableStringBuilder spannableStringBuilder, int resId) {MyImageSpan imageSpan = new MyImageSpan(mContext, BitmapFactory.decodeResource(mView.getResources(), resId), 2);spannableStringBuilder.setSpan(imageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}
4. 自定义一个 ImageSpan,重写 draw 方法
@Overridepublic void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom,Paint paint) {//draw 方法是重写的ImageSpan父类 DynamicDrawableSpan中的方法,在DynamicDrawableSpan类中,虽有getCachedDrawable(),// 但是私有的,不能被调用,所以调用ImageSpan中的getrawable()方法,该方法中 会根据传入的drawable ID ,获取该id对应的// drawable的流对象,并最终获取drawable对象Drawable drawable = getDrawable(); //调用imageSpan中的方法获取drawable对象canvas.save();//获取画笔的文字绘制时的具体测量数据Paint.FontMetricsInt fm = paint.getFontMetricsInt();//系统原有方法,默认是Bottom模式)int transY = bottom - drawable.getBounds().bottom;if (mVerticalAlignment == ALIGN_BASELINE) {transY -= fm.descent;} else if (mVerticalAlignment == ALIGN_FONTCENTER) {//此处加入判断, 如果是自定义的居中对齐//与文字的中间线对齐(这种方式不论是否设置行间距都能保障文字的中间线和图片的中间线是对齐的)// y+ascent得到文字内容的顶部坐标,y+descent得到文字的底部坐标,(顶部坐标+底部坐标)/2=文字内容中间线坐标transY = ((y + fm.descent) + (y + fm.ascent)) / 2 - drawable.getBounds().bottom / 2;}canvas.translate(x, transY);drawable.draw(canvas);canvas.restore();}
5. 遍历拿到的协议组
for (int i = 0; i < protocols.length; i++) {final String protocol = protocols[i];SpannableStringBuilder protocolStringBuild = new SpannableStringBuilder(protocol);//协议//点击spanfinal int finalI = i;ClickableSpan clickableSpan = new ClickableSpan() {@Overridepublic void onClick(View widget) {//显示协议内容mView.showProtocol(protocol, finalI, protocols.length);}@Overridepublic void updateDrawState(TextPaint ds) {super.updateDrawState(ds);ds.setUnderlineText(false);ds.setColor(Color.WHITE);}};protocolStringBuild.setSpan(clickableSpan, 0, protocol.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//前景ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(mView.getResources().getColor(R.color.colorPrimary));protocolStringBuild.setSpan(foregroundColorSpan, 0, protocol.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);spannableStringBuilder.append(protocolStringBuild);//点if (i != protocols.length - 1) {SpannableStringBuilder dotStringBuild = new SpannableStringBuilder("、");ForegroundColorSpan dotSpan = new ForegroundColorSpan(mView.getResources().getColor(R.color.color_66));dotStringBuild.setSpan(dotSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);spannableStringBuilder.append(dotStringBuild);}}return spannableStringBuilder;