简书链接:【原创】基于默认dialogsetSingleChoiceItems对话框自定义布局增加颜色
文章字数:326,阅读全文大约需要1分钟
由于强迫症,想不完整定义自定义单选布局对话框就用setSingleChoiceItems实现,于是进行了一些研究,
经过appcompat包源码分析,AlertController类使用了主题,
构造函数中
75769474936c8bf569d5e971b2fc0fe.jpg

1
this.mSingleChoiceItemLayout = a.getResourceId(styleable.AlertDialog_singleChoiceItemLayout, 0);
1
2
3
4
5
6
7
8
9
<style name="Base.AlertDialog.AppCompat" parent="android:Widget">
<item name="android:layout">@layout/abc_alert_dialog_material</item>
<item name="listLayout">@layout/abc_select_dialog_material</item>
<item name="listItemLayout">@layout/select_dialog_item_material</item>
<item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_material</item>
<item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_material</item>
<item name="buttonIconDimen">@dimen/abc_alert_dialog_button_dimen</item>
</style>

单选对话框默认使用的是select_dialog_singlechoice_material
进一步分析,发现根布局判断是否是checkable,如果改用普通view,则无法实现check效果,因此我用跟布局实现checkable,然后代理事件转发给子viewCheckedTextView实现了转发选中事件的逻辑。

关于check的逻辑,在AbsListView.updateOnScreenCheckedViews有实现,

关于 如何找到textview以及修改怎么获取文本内容 的呢?
实际上是根据adapter的构造函数传递textViewResourceId实现的,因此构造函数进行了一下调整,
而获取文本内容使用的是泛型类的toString(),所以toString()直接返回标题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Checkable;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.sotrun.app.R;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ColorSelectAdapter extends ArrayAdapter<ColorSelectAdapter.Bean> {
public ColorSelectAdapter(@NonNull Context context, int resource) {
super(context, resource, android.R.id.text1);
}

public ColorSelectAdapter(@NonNull Context context, int resource, int textViewResourceId) {
this(context, resource, textViewResourceId, new ArrayList<>());
}

public ColorSelectAdapter(@NonNull Context context, int resource, @NonNull Bean[] objects) {
this(context, resource, android.R.id.text1, Arrays.asList(objects));
}

public ColorSelectAdapter(@NonNull Context context, int resource, int textViewResourceId, @NonNull Bean[] objects) {
this(context, resource, textViewResourceId, Arrays.asList(objects));
}

public ColorSelectAdapter(@NonNull Context context, int resource, @NonNull List<Bean> objects) {
this(context, resource, android.R.id.text1, objects);
}

public ColorSelectAdapter(@NonNull Context context, int resource, int textViewResourceId, @NonNull List<Bean> objects) {
super(context, resource, textViewResourceId, objects);
}


@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (view instanceof CheckableProxyView) {

} else {
ViewGroup temp = new CheckableProxyView(getContext());
temp.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT));
temp.addView(view);
view = temp;

}
CheckableProxyView checkableProxyView = (CheckableProxyView) view;
Checkable tvTitle = view.findViewById(android.R.id.text1);
checkableProxyView.setCheckNotify(new CheckableProxyView.CheckNotify() {
@Override
public void setChecked(boolean checked) {
tvTitle.setChecked(checked);
}

@Override
public boolean isChecked() {
return tvTitle.isChecked();
}

@Override
public void toggle() {
tvTitle.toggle();
}
});
Bean item = getItem(position);
View viewColor = view.findViewById(R.id.view_color);
viewColor.setBackgroundColor(getContext().getResources().getColor(item.color));
return view;
}

public static class CheckableProxyView extends FrameLayout implements Checkable {

public CheckableProxyView(Context context) {
super(context);
}

public CheckableProxyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

public CheckableProxyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public CheckableProxyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public void setChecked(boolean checked) {
if (checkNotify != null) {
checkNotify.setChecked(checked);
}
}

@Override
public boolean isChecked() {
if (checkNotify != null) {
return checkNotify.isChecked();
}
return false;
}

@Override
public void toggle() {
if (checkNotify != null) {
checkNotify.toggle();
}
}

public void setCheckNotify(CheckNotify checkNotify) {
this.checkNotify = checkNotify;
}

CheckNotify checkNotify;

interface CheckNotify {
void setChecked(boolean checked);

boolean isChecked();

void toggle();
}
}

@Override
public boolean hasStableIds() {
return true;
}

@Override
public long getItemId(int position) {
return position;
}

public static class Bean {
public int color;
public String title;

@Override
public String toString() {
return title;
}
}
}


对话框的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
int currentMode = NightModeUtils.Companion.getSpfThemeMode(AppContext.getInstance());
ThemeMode[] values = ThemeMode.values();
ColorSelectAdapter.Bean[] items=new ColorSelectAdapter.Bean[values.length];
for (int i = 0; i < values.length; i++) {
String title = AppContext.getInstance().getString(values[i].getStringValueId());
ColorSelectAdapter.Bean bean=new ColorSelectAdapter.Bean();
bean.title=title;
bean.color=values[i].getColor();
items[i]=bean;
}
ColorSelectAdapter arrayAdapter = new ColorSelectAdapter(
getActivity(), R.layout.view_color_check_item, items);
builder.setSingleChoiceItems(arrayAdapter, currentMode, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which != currentMode) {
dialog.dismiss();
ThemeMode value = values[which];
NightModeUtils.getInstance(AppContext.getInstance()).setThemeMode(value);
EventBus.getDefault().post(new ThemeChangeEvent().themeChange());

}

}

});
builder.setTitle(AppContext.getStr(R.string.deep_color_theme_setting));
builder.show();

view_color_check_item.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<View
android:layout_margin="10dp"
android:layout_marginRight="0dp"
android:id="@+id/view_color"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical" />
<CheckedTextView
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
android:drawableLeft="?android:attr/listChoiceIndicatorSingle"
android:drawablePadding="20dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:minHeight="?attr/listPreferredItemHeightSmall"
android:paddingStart="@dimen/abc_select_dialog_padding_start_material"
android:paddingLeft="@dimen/abc_select_dialog_padding_start_material"
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingRight="?attr/dialogPreferredPadding"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?attr/textColorAlertDialogListItem" />

</LinearLayout>