AlertDialog.Builder+SpannableStringBuilder自定义单选框

Posted 碎格子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AlertDialog.Builder+SpannableStringBuilder自定义单选框相关的知识,希望对你有一定的参考价值。


在项目开发的时候,产品汪希望我们做出这种样式的dialog,要做出单选Dialog很简单,网上例子一搜一大把。而我们常用的AlertDialog.Builder也有实现这样的方法:

setSingleChoiceItems(ListAdapter adapter, int checkedItem, final OnClickListener)

我们就用这个方法弹一个单选框看看:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Please check out separately :");
ArrayList<String> chooseTypeList = new ArrayList<>();
chooseTypeList.add("Check out A (A post paid)");
chooseTypeList.add("Check out B (B prepaid)");
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_single_choice, chooseTypeList);   builder.setSingleChoiceItems(adapter, 0, new DialogInterface.OnClickListener() 
    @Override
    public void onClick(DialogInterface dialog, int which) 
        //do something
    
);
builder.show();

看看实际效果:

虽然大概样子出来了,但是产品汪表示多个细节不满意:

  • Dialog的title没跟下面的选项对齐
  • 单选项后面备注文案应该是灰色的
  • 单选项的按钮可不可以换个颜色?

那我们就按照产品汪的需要来改:
第一个很容易,AlertDialog.Builder有个自定义title的方法setCustomTitle(View view),将我们自定义的View设置进去就行了

TextView textView = new TextView(MainActivity.this);
textView.setText("Please check out separately :");
textView.setTextSize(16);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setTextColor(Color.BLACK);
float dp_px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()); //dp转px
textView.setPadding((int) (dp_px * 16), (int) (dp_px * 24), (int) (dp_px * 12), 0);
builder.setCustomTitle(textView);

第二点似乎有点不大容易实现,前一段字黑色,后一段字灰色,如果是不用两个TextView的话,怎么实现呢?突然想到前段时间使用过SpannableStringBuilder来对文字进行分割设置,这里的话可不可以用这样的方法实现呢?看了一下SpannableString和SpannableStringBuilder都实现了CharSequence,那它的实现应该跟String大同小异的,既然Adapter里可以设置String的list,我们声明一个SpannableStringBuilder的list添加进Adapter里试试:

ArrayList<SpannableStringBuilder> chooseTypeList = new ArrayList<>();
SpannableStringBuilder builder1 = new SpannableStringBuilder();
SpannableString ss = new SpannableString("Check out A (A post paid)");
ss.setSpan(new ForegroundColorSpan(Color.GRAY), "Check out A ".length(), ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
builder1.append(ss);
SpannableStringBuilder builder2 = new SpannableStringBuilder();
SpannableString ss2 = new SpannableString("Check out B (B prepaid)");
ss2.setSpan(new ForegroundColorSpan(Color.GRAY), "Check out B ".length(), ss2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
builder2.append(ss2);
chooseTypeList.add(builder1);
chooseTypeList.add(builder2);
ArrayAdapter<SpannableStringBuilder> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_single_choice, android.R.id.text1, chooseTypeList);
builder.setSingleChoiceItems(adapter, 0, new DialogInterface.OnClickListener() 
    @Override
    public void onClick(DialogInterface dialog, int which) 
        //do something
    
);

果然可以!接下来就是最后一个需求:换按钮。
其实不难发现,在创建adapter的时候,传入了一个android.R.layout.simple_list_item_single_choice的layout,从这一长串名字可以看出这是android的layout,打开这个布局文件可以看到:

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeightSmall"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:checkMark="?android:attr/listChoiceIndicatorSingle"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />

忽略其他的设置,直接看我们想要更改的按钮样式android:checkMark=”?android:attr/listChoiceIndicatorSingle”
这一句就是默认按钮的设置,如果我们要设置我们自定义的样式的话,需要新建一个布局文件,然后将android:checkMark的属性设置成为我们想要的:
select_dialog_singlechoice.xml

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/text1"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeightSmall"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:checkMark="@drawable/selector_register_cb"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />

这里我将android:checkMark属性换成了我自己写的一个selector文件,然后java代码中改一下adapter的参数:

ArrayAdapter<SpannableStringBuilder> adapter = new ArrayAdapter<>(this, R.layout.select_dialog_singlechoice, R.id.text1, chooseTypeList);

大功告成,产品汪终于表示很满意 : )
tips:

  • SpannableStringBuilder这个类其实非常实用功能也非常大,不仅可以提供分段设置字体颜色,还可以设置字体大小,字体样式,前景色背景色等等,总之就是使用得当的话这个类对减少布局层级非常有帮助。
  • SpannableStringBuilder如果声明为成员变量的话,记得在每一次append之前先clear一下。

其实开发中的实际效果图是这样的,描述文案折行并且字体调小了,使用SpannableStringBuilder都可以实现。

我在这里有一个疑问,设计想让我们checkout 按钮变成橙色,以及将cancel按钮置灰,我能想到的粗暴一点的方式是重写Dialog自定义按钮颜色,不知道大家有没有更好的建议和办法,如果有的话可以在下面评论留言,不胜感激 :)

以上是关于AlertDialog.Builder+SpannableStringBuilder自定义单选框的主要内容,如果未能解决你的问题,请参考以下文章

带有Edittext setView的Android AlertDialog Builder在底部显示?

android dialog怎么关闭

Android运用Builder来创建Alertdialog

AlertDialog.Builder+SpannableStringBuilder自定义单选框

AlertDialog.Builder#show 上的“android.view.WindowManager$BadTokenException”即使有保护措施

AlertDialog创建对话框的测试