android.support.v7.app.AlertDial
一:基本使用
1、显示消息
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
.setMessage("message")
.setIcon(R.drawable.ic_info_black_24dp)
.setPositiveButton(android.R.string.ok, null)
.setNegativeButton(android.R.string.cancel, null)
.show();
效果:
dialog.png
2、显示列表
CharSequence[] charSequence = new CharSequence[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
.setItems(charSequence, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//TODO
}
})
.setPositiveButton(android.R.string.ok, null)
.show();
list_dialog.png
此时如果数据有更新怎么办,我们就需要找到ListAlertDialog里面的ListView的Adapter,然后通知更新就可以了。
代码可以像下面这么写:
final CharSequence[] charSequence = new CharSequence[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final AlertDialog dialog = builder.setTitle("Title")
.setItems(charSequence, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//TODO
}
})
.setPositiveButton(android.R.string.ok, null)
.show();
AsyncTask.execute(new Runnable() {
@Override
public void run() {
SystemClock.sleep(1500);
charSequence[1] = "BBBBB";
charSequence[2] = "ZZZZZ";
if (dialog.isShowing()) {
ListView listView = dialog.getListView();
final BaseAdapter adapter = (BaseAdapter) listView.getAdapter();
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
}
});
}
}
});
这里起一个线程模拟耗时任务,listView.getAdapter()获得的对象为ListAdapter,但是ListAdapter没有notifyDataSetChanged()方法,查看源码发现他使用的就是CheckedItemAdapter,而CheckedItemAdapter的父类就继承自BaseAdapter,这里就强转成BaseAdapter就可以了。
3、显示单选和多选列表
显示单选列表,类似RadioGroup。
CharSequence[] charSequence = new CharSequence[]{"A", "B", "C", "D", "E", "F", "G"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
.setSingleChoiceItems(charSequence, 1,new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//TODO
}
})
.setPositiveButton(android.R.string.ok, null)
.show();
显示多选列表。
CharSequence[] charSequence = new CharSequence[]{"A", "B", "C", "D", "E", "F", "G"};
boolean[] booleans = new boolean[]{false, true, false, false, false, true, false};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
.setMultiChoiceItems(charSequence, booleans, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
}
})
.setPositiveButton(android.R.string.ok, null)
.show();
4、Cursor+列表
String[] projection = new String[]{
MediaStore.MediaColumns.TITLE,
MediaStore.MediaColumns._ID
};
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, null, null, null);
new AlertDialog.Builder(this)
.setTitle("Image Name")
.setMultiChoiceItems(cursor,
MediaStore.MediaColumns._ID,
MediaStore.MediaColumns.TITLE,
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
}
})
.setPositiveButton(android.R.string.ok, null)
.show();
multi_chioce.png
5、自定义
1:setView设置内容区域,不包括Title和底部按钮
View mContentView = LayoutInflater.from(this).inflate(R.layout.alert_dialog_editext, null);
new AlertDialog.Builder(this)
.setTitle("Input Name")
.setView(mContentView)
.setPositiveButton(android.R.string.ok, null)
.show();
custom_view.png
2:setCustomTitle自定义标题,替换原有的Title和Icon所在的布局,所以此时setTitle和setIcon两个方法的设置是无效的
View mTitleView = LayoutInflater.from(this).inflate(R.layout.title_view, null);
new AlertDialog.Builder(this)
.setMessage("This is Message")
.setCustomTitle(mTitleView)
.setPositiveButton(android.R.string.ok, null)
.show();
custom_view.png
二:主题样式
1、构造器
Builder有两个构造器:
public Builder(Context context) {
this(context, resolveDialogTheme(context, ResourceId.ID_NULL));
}
public Builder(Context context, int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
只有一个参数的会生成一个默认的样式给AlertDialog,这个样式会跟随Activity的主题;
第二个构造器需要自己传入一个样式。
2、修改样式
1:Style控制样式
<style name="DialogTheme" parent="ThemeOverlay.AppCompat.Dialog.Alert">
<item name="android:textColorPrimary">#FF00FF</item>
<item name="colorAccent">#00FFFF</item>
<item name="android:textSize">20sp</item>
</style>
textColorPrimary:设置Title和Message的颜色;
colorAccent:设置Button文字的颜色;
android:textSize:控制Button文字的大小。
new AlertDialog.Builder(this, R.style.DialogTheme)
.setMessage("This is Message")
.setTitle("Title")
.setPositiveButton(android.R.string.ok, null)
.show();
style.png
2:Message和Button的颜色动态修改
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setMessage("This is Message")
.setTitle("Title")
.setPositiveButton(android.R.string.ok, null)
.setNegativeButton(android.R.string.cancel, null)
.show();
TextView msg = alertDialog.findViewById(android.R.id.message);
msg.setTextColor(0x80000000);
Button pBtn = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
if (pBtn != null) {
pBtn.setTextColor(getResources().getColor(R.color.colorAccent));
}
Button nBtn = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
if (nBtn != null) {
nBtn.setTextColor(getResources().getColor(R.color.colorAccent));
}
android.R.id.message:Message所在TextView的ID;
getButton(DialogInterface.BUTTON_POSITIVE):PositiveButton;
getButton(DialogInterface.BUTTON_NEGATIVE):NegativeButton。
其中Title所在View的ID是android:id="@+id/alertTitle",但是通过findViewById是找不到的。
3、Material Design规范颜色和字号
Title text:颜色87%透明度的黑,字体android:fontFamily="sans-serif-medium",文字大小20sp;
Message text:颜色54%透明度的黑,字体android:fontFamily="sans-serif",文字大小16sp;
Button:颜色跟随主题色,字体android:fontFamily="sans-serif-medium",文字大小14sp;
三:问题Bug
1、华为android6.0/7.0/8.0等系统的手机开启单手模式,Dialog展示的位置有问题,左右距离不等(貌似华为在android9.0修复了此问题)。
正常手机截图: 单手模式.png
2、条件:①、小米android9.0以上系统
②、开启全屏模式
③、Dialog里面的内容的列表可以滚动
结果:Dialog展示时会跳动一下。
跳动.gif
正常.gif
3、条件:①、Activity的主题里面包含<item name="android:windowTranslucentStatus">true</item>
②、Dialog里面的内容列表可以滚动
结果:Dialog展示时会跳动一下(不是所有手机都存在这个问题,而且如果使用的是Android API下的AlertDialog是不会出问题的)。
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
String[] strings = new String[50];
for (int i = 0; i < strings.length; i++) {
strings[i] = i + "";
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
.setSingleChoiceItems(strings, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton(android.R.string.ok, null)
.show();
跳动.gif
四:进阶
1、dialog.dismiss();可以在子线程调用而不会崩溃。
源码:
@Override
public void dismiss() {
if (Looper.myLooper() == mHandler.getLooper()) {
dismissDialog();
} else {
mHandler.post(mDismissAction);
}
}
2、在dialog的cancel()方法里面会调用dismiss()方法,所以当调用cancel()方法时onCancel和onDismiss都接收到回调,而且顺序是先回调给onCancel然后回调给onDismiss。
源码:
@Override
public void cancel() {
if (!mCanceled && mCancelMessage != null) {
mCanceled = true;
// Obtain a new message so this dialog can be re-used
Message.obtain(mCancelMessage).sendToTarget();
}
dismiss();
}
3、可以通过给Dialog设置setOnKeyListener监听返回键的点击。