参考:
Android API 指南:Dialog: https://developer.android.google.cn/guide/topics/ui/dialogs.html#ShowingADialog
Dialog :Builder模式创建
dialog的监听可以为null,按“确定”、“取消”仍然有效。
对话框分类 | 含义 |
---|---|
Dialog | 基类:非抽象 |
AlertDialog | 提醒对话框 |
ProgressDialog | 进度条对话框 |
Dialog背景色是黑色,这是因为style的原因:
<style name="AppBaseTheme"parent="android:Theme.Holo.Light.DarkActionBar">
这些对话框都继承自Dialog,API18:
见图:
Dialog常用的方法
方法 | 含义 |
---|---|
setContentView(View or resId) | 填充布局 |
findViewById(resId) | 找到布局中的控件,可以用dialog调用 |
setTitle(character char) | 设置比提提 |
setIcon(resId) | 设置图标 |
show() | 显示 |
dismiss() | 消失:从屏幕中移除 |
hide() | 隐藏 |
isShow() | dialog是否正在显示 |
getWindow() | 得到当前dialog所在的activity的窗体 |
类Dialog是没有方法:setMessage(charseQuence char),但是子类AlertDialog + ProgressDialog有此方法。
setButton(…)
dialog.setButton(…)
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", dialog);
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, "中立", dialog);
dialog.setButton("自定义Button:确定", dialog);
dialog.setButton2("自定义Button:取消", dialog);
builder.setPositiveButton(…)
builder.setTitle("选择时间")
.setCancelable(false)
.setIcon(android.R.drawable.ic_dialog_info)
.setSingleChoiceItems(times, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//
}
})
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//
}
})
.setNegativeButton("选择日期", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//
}
});
dialog消失的2种方法的区别!
setCancelable(boolean flag) :点击back键dialog是否消失
setCanceledOnTouchOutside(boolean cancel) : 点击dialog意外的区域dialog是否消失
见developer
Dialog效果图
AlertDialog:基本对话框
继承自Dialog,默认显示在屏幕中间,左右两边距离屏幕有间隔。
效果图:
相关的类
类 | 含义 |
---|---|
AlertDialog | 提醒对话框 |
AlertDialog.Builder | 对话框构造器 |
Builder的相关的方法
方法 | 含义 |
---|---|
setPositiviButton(String ,DialogInterface.onClickListener(..)) | 设置确定按钮 |
setNogetiveButton(String ,DialogInterface.onClickListener(..)) | 设置取消按钮 |
setMessage(charseQuence char) | 设置dialog内容 |
crete() | 创建dialog对象 |
代码:
// 普通对话框
private void initAlertDialog() {
Builder builder = new AlertDialog.Builder(context);
builder.setTitle("更新提示");
builder.setMessage("这是知乎最新版本,请更新!");
builder.setIcon(R.drawable.ic_launcher);
builder.setPositiveButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastUtil.showShortToast(context, "确定" + which);
// dialog.dismiss();//可以不调用dismiss(),dialog会自动消失
}
});
builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastUtil.showShortToast(context, "取消" + which);
// dialog.dismiss();可以不调用dismiss(),dialog会自动消失
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
注意:
AlertDialog的方法setNegativeButton(CharSequence text, OnClickListener listener) + setPositiveButton(CharSequence text, OnClickListener listener) + setPositiveButton(CharSequence text, OnClickListener listener) 会自动调用dialog的dismiss(),除此之外均如果需要让dialog消失,都必须调用dismiss().
设置单选对话框和多选对话框时,不能调用方法setMessage(charseQuence char),否则选择列表不会显示。
Dialog添加列表
可通过 AlertDialog API 提供三种列表:
- 传统单选列表
- 永久性单选列表(单选按钮)
- 永久性多选列表(复选框)
checkedItem:默认选中的position。-1表示默认不选中任何一个。
.setSingleChoiceItems(provinces, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//which表示选中的item在items中的角标
}
})
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Title")
.setIcon(R.mipmap.ic_launcher_round)
.setSingleChoiceItems(provinces, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "singleChoice,which=" + which);
}
})
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "Positive,which=" + which);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "Negative,which=" + which);
}
})
.create();
dialog.show();
AlertDialog:单选对话框
效果图:
相关的方法
类 | 含义 |
---|---|
setSingleChoiceItems(CharSequence[] items, int checkedItem, OnClickListener listener) | 设置单选对话框 |
items | 所有选项 |
checkedItem | 默认选中哪一个,-1:默认都没选 |
代码:
private void initSingleChoiceDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("标题");
// builder.setMessage("message--message");//设置message就没有了单选列表
builder.setIcon(R.drawable.ic_launcher);
final String[] items = new String[] { "item1", "item2", "item3", "item4", "item5" };
final boolean[] checkedItem = new boolean[]{false,false,false,false,false};
builder.setSingleChoiceItems(items, -1,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
checkedItem[which] = true;
ToastUtil.showShortToast(context, items[which]);
dialog.dismiss();// 点击单选按钮,dialog不会自动消失
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
AlertDialog多选对话框
效果图:
Builder的相关的方法
方法 | 含义 |
---|---|
setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, OnMultiChoiceClickListener listener) | 多选方法 |
参数 | 含义 |
items | 多选列表的内容 |
checkedItems | ,默认选中的内容 |
点开dialog显示上一次退出时选中的按钮
把checkedItems 的创建放在类中,作为类变量。
代码:
private void initMultiChoiceDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Title");
// builder.setMessage("message--message");//设置message就没有了单选列表
builder.setIcon(R.drawable.ic_launcher);
items = new String[] { "item1", "item2", "item3", "item4", "item5" };
final boolean[] checkedItems = new boolean[] { false, false, false,
false, false };
builder.setMultiChoiceItems(items, checkedItems,
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which,
boolean isChecked) {
ToastUtil.showShortToast(context, items[which]);
}
});
builder.setPositiveButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastUtil.showShortToast(context, "取消");
// dialog.dismiss();//可以不调用dismiss(),dialog会自动消失
}
});
builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < checkedItems.length; i++) {
if (checkedItems[i]) {
sb.append(items[i]);
}
}
ToastUtil.showShortToast(context, "确定" + sb.toString());
// dialog.dismiss();可以不调用dismiss(),dialog会自动消失
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
如何获选中的数据?
除了遍历boolean[] checkedItems
外,还可以创建一个List,选中时添加到List,取消后从List中清除
ArrayList<String> selectedList = new ArrayList<>();
selectedList.clear();
builder.setMultiChoiceItems(provinces, null, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
Log.d(TAG, "MultiChoice,which=" + which + ",isChecked=" + isChecked);
if (isChecked) {
selectedList.add(provinces[which]);
} else if (selectedList.contains(provinces[which])) {
selectedList.remove(provinces[which]);
}
}
})
ProgressDialog:进度条对话框
分为线性和圆形,没有Builder.
效果图:
相关的方法
类 | 含义 |
---|---|
setProgressStyle(int style) | 设置进度条样式 |
setMax(int max) | 进度最大值 |
setProgress(int value) | 设置当前进度 |
设置进度条:
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 水平线进度条
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 圆形进度条
代码:
private void initProgressDialog() {
final ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle("Title");//设置标题
dialog.setMessage("message----message");//设置dialog内容
dialog.setIcon(R.drawable.ic_launcher);//设置图标,与为Title左侧
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 水平线进度条
// dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//圆形进度条
dialog.setMax(100);//最大值
new Thread() {
public void run() {
for (int i = 0; i <= 100; i++) {
SystemClock.sleep(50);
dialog.setProgress(i);//每隔50毫秒设置当前进度
}
dialog.dismiss();// for执行完成后dialog默认不消失
};
}.start();
dialog.show();
}
自定义Dialog
需要自己设置布局
效果图:
相关
类 | 含义 |
---|---|
window | 窗体 |
方法 | 含义 |
setGravity(int gravity) | 设置窗体位置 |
类 | 含义 |
Dialog | |
方法 | 含义 |
requestWindowFeature(int featureId) | 窗体的title是否显示 |
代码:
private void initCustomDialog() {
final Dialog dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉dialog的title,放在设置布局前
dialog.setContentView(R.layout.custom_dialog);
dialog.getWindow().setGravity(Gravity.BOTTOM);
Button btn_ok = (Button) dialog.findViewById(R.id.btn_ok);
Button btn_cancle = (Button) dialog.findViewById(R.id.btn_cancle);
btn_ok.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
btn_cancle.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
自定义Dialog:加 动画 + 设置宽高 + style
效果图:
相关
类:Window
方法 | 含义 |
---|---|
方法 | 含义 |
setGravity(int gravity) | 设置窗体位置 |
getAttributes() | 获取当前窗体的参数 |
setAttributes(LayoutParams a) | 设置窗体宽高 |
setWindowAnimations(int resId) | 给窗体添加动画 |
类:Dialog
方法 | 含义 |
---|---|
requestWindowFeature(int featureId) | 窗体的title是否显示 |
setCanceledOnTouchOutside(boolean cancel) | 点击dialog意外的区域,dialog是否消失 |
设置宽 + 高
//设置 宽 + 高
LayoutParams params = window.getAttributes();//获取当前窗体的参数
view.measure(0, 0);
params.width = getResources().getDisplayMetrics().widthPixels;
params.height = view.getMeasuredHeight();//不设置高的话,dialog会充满屏幕,下方是白色,即使在布局中设置了高的具体值
window.setAttributes(params);
添加动画
window.setWindowAnimations(R.style.DialogAnimationStyle);
DialogAnimationStyle:
<style name="DialogAnimationStyle" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/dialog_enter</item>
<item name="android:windowExitAnimation">@anim/dialog_exit</item>
</style>
dialog_enter.xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromYDelta="100%" >
</translate>
dialog_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:toYDelta="100%" >
</translate>
MyStyle.xml
<style name="MyStyle">
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
代码:
private void initCustomDialog2() {
final Dialog dialog = new Dialog(context , R.style.MyStyle);//去掉dialog的title,dialog区域外是灰色
// dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉dialog的title,放在设置布局前
View view = View.inflate(context, R.layout.custom_dialog2, null);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(true);//点击dialog意外的区域,dialog是否消失
Window window = dialog.getWindow();//创建当前窗体
window.setGravity(Gravity.BOTTOM);//当前床底位于底部
//添加动画
window.setWindowAnimations(R.style.DialogAnimationStyle);
//设置 宽 + 高
LayoutParams params = window.getAttributes();//获取当前窗体的参数
view.measure(0, 0);
params.width = getResources().getDisplayMetrics().widthPixels;
params.height = view.getMeasuredHeight();//不设置高的话,dialog会充满屏幕,下方是白色,即使在布局中设置了高的具体值
window.setAttributes(params);
Button btn_camera = (Button) dialog.findViewById(R.id.btn_camera);
Button btn_gallery = (Button) dialog.findViewById(R.id.btn_gallery);
Button btn6_cancle = (Button) dialog.findViewById(R.id.btn6_cancle);
btn_camera.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ToastUtil.showShortToast(context, "btn_camera");
dialog.dismiss();
}
});
btn_gallery.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ToastUtil.showShortToast(context, "btn_gallery");
dialog.dismiss();
}
});
btn6_cancle.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ToastUtil.showShortToast(context, "btn6_cancle");
dialog.dismiss();
}
});
dialog.show();//显示dialog
}
再魅族手机中,虚拟按键会遮挡bottomDialog的下方,解决的方法是在设置window的高度是加上虚拟键的高度
public class VirtualHeightUtil {
public static int getDpi(Activity activity) {
Display display = activity.getWindowManager().getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
int height = 0;
@SuppressWarnings("rawtypes")
Class c;
try {
c = Class.forName("android.view.Display");
@SuppressWarnings("unchecked")
Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
method.invoke(display, dm);
height = dm.heightPixels;
} catch (Exception e) {
e.printStackTrace();
}
return height;
}
public static int[] getScreenWH(Context poCotext) {
WindowManager wm = (WindowManager) poCotext.getSystemService(Context.WINDOW_SERVICE);
if (wm == null) {
return new int[]{0, 0};
} else {
int width = wm.getDefaultDisplay().getWidth();
int height = wm.getDefaultDisplay().getHeight();
return new int[]{width, height};
}
}
/**
* 获取魅族手机的虚拟键高度
* @param poCotext
* @return
*/
public static int getVirtualBtnHeight(Context poCotext) {
int location[] = getScreenWH(poCotext);
int realHeiht = getDpi((Activity) poCotext);
int virtualHeight = realHeiht - location[1];
return virtualHeight;
}
}
Dialog:构造方法创建
我们知道设置模式有构建者模式,也就是Builder模式,上面我们创建Dialog就是这么做的。其实采用构造方法也可以创建Dialog。
比如:Dialog
、ProgressDialog
、DatePickerDialog
、TimePickerDialog
都可以采用构造方法创建dialog,但是AlertDialog
不可以。
其中:DatePickerDialog
、TimePickerDialog
也可以使用fragment来显示,见:Android_UI:Date & Time组件(下)
ProgressDialog
见上面
DatePickerDialog
**注意:**DatePickerDialog和TimePickerDialog 都有方法
setButton(...)
,当我们重写该方法后,那么监听OnDateSetListener
、OnTimeSetListener
就无效了,不会走这2个监听,下面在重写setButton()
中会有说明
DatePickerDialog 不重写setButton()
效果图
代码
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(context, onDateSetListener, year, month, dayOfMonth);
datePickerDialog.setCanceledOnTouchOutside(false);
datePickerDialog.setCancelable(false);
datePickerDialog.show();
DatePickerDialog 重写setButton()
重写
setButton()
, 通过getDatePicker()
获取到DatePicker
对象,进而获取到year+month+day,所以不需要OnDateSetListener
注意:TimePickDialog
确没有相似的方法getTimePicker()
,所以需要OnTimeSetListener
重写
setButton(...)
后,监听OnDateSetListener
、OnTimeSetListener
就无效了。所以如果重写刚方法,那么不需要写listener,直接传null。dialog默认有2个Button,如果我们只重写了一个
setButton(...)
,那么另一个“确定”/“取消”也会显示出来,那么怎么不让它显示出来呢,还是不设置为 “”,会显示默认文字
dialog.setButton2("", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//不写
}
});
但是不能是:
dialog.setButton2("",null);
效果图
代码
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
MyOnDateSetListener onDateSetListener = new MyOnDateSetListener();
//可以不传参数OnDateSetListener, 第2个参数: int themeResId, 第三个参数:OnDateSetListener
final DatePickerDialog dialog = new DatePickerDialog(context, 0, null, year, month, day);
dialog.setButton("自定义Button:确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog2, int which) {
DatePicker datePicker = dialog.getDatePicker();
int year = datePicker.getYear();
int month = datePicker.getMonth() + 1;
int dayOfMonth = datePicker.getDayOfMonth();
Log.d(TAG, "日期:" + year + "年" + month + "月" + dayOfMonth + "日");
}
});
dialog.setButton2("自定义Button:取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "取消" + ",which=" + which);
}
});
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
TimePickerDialog
TimePickDialog:不重写setButton()
效果图
代码
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
MyOnTimeSetListener timeSetListener = new MyOnTimeSetListener();
TimePickerDialog dialog = new TimePickerDialog(context, timeSetListener, hour, minute, true);
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
TimePickDialog:重写setButton()
效果图
代码
DatePickerDialog
通过方法getDatePicker()
获取DatePicker
对象,今儿获取year+month+day,但是TimePickDialog
没有方法getTimePicker()
,所以我们不能像DatePickerDialog那样获取hour+minute,那么该怎么做呢,就是修改SetButton()
的第二个参数,不传OnClickListener
,直接传入TimePickDialog
对象。
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
MyOnTimeSetListener timeSetListener = new MyOnTimeSetListener();
TimePickerDialog dialog = new TimePickerDialog(context, timeSetListener, hour, minute, true);
//有效方法,第2个参数不传OnClickListener,直接传入dialog本身
dialog.setButton("自定义Button:确定", dialog);
dialog.setButton2("自定义Button:取消", dialog);
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
MyOnTimeSetListener:
private class MyOnTimeSetListener implements TimePickerDialog.OnTimeSetListener {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
Log.d(TAG, "时间:" + hourOfDay + "时" + minute + "分");
}
}
其它
Demo: http://git.oschina.net/AndroidUI/DatePickerDialogTimePickerDialog
参考:
Android编程之TimePickerDialog设置确定键导致OnTimeSetListener不响应问题
Android:Picker(DatePicker、TimerPicker、NumberPicker)
重写DatePickerDialog 解决OnDateSetListener只有完成,没有取消回调问题
DialogFragment
自定义类继承
DialogFragment
,重写onCreateDialog()
或者onCreateView()
创建dialog
第一种:onCreateDialog()
中创建dialog
Dialog dialog = super.onCreateDialog(savedInstanceState);
第二种:onCreateDialog()
中创建dialog
AlertDialog dialog = new AlertDialog.Builder(getActivity()).create();
第三种:在onCreateView()
中自定义view
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.frag_dialog_3, container, false);
return rootView;
}
显示dialog
DialogFragment01 frag = new DialogFragment01();
frag.show(getSupportFragmentManager(), "frag");
Demo
DialogFragment01
public class DialogFragment01 extends DialogFragment implements View.OnClickListener {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.setTitle("Title");
dialog.setContentView(R.layout.frag_dialog_3);
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
TextView tv1 = dialog.findViewById(R.id.tv1);
TextView tv2 = dialog.findViewById(R.id.tv2);
tv1.setOnClickListener(this);
tv2.setOnClickListener(this);
return dialog;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv1:
Toast.makeText(getActivity(), "tv1", Toast.LENGTH_SHORT).show();
break;
case R.id.tv2:
Toast.makeText(getActivity(), "tv2", Toast.LENGTH_SHORT).show();
break;
}
}
}
DialogFragment02
public class DialogFragment02 extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog dialog = new AlertDialog.Builder(getActivity())
.setTitle("Title")
.setMessage("message")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setCancelable(false)
.create();
dialog.setCanceledOnTouchOutside(false);
return dialog;
}
}
DialogFragment03
public class DialogFragment03 extends DialogFragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE,0);//去掉dialog的Title,也可以使用style
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.frag_dialog_3, container, false);
return rootView;
}
}
Demo:https://git.oschina.net/AndroidUI/dialogfragment01.git
使用DialogFragment怎么把value传给Activity?
采用的接口的方式,让Activity实现给接口,把DialogFragment对象返给Activity
public class NoticeDialogFragment extends DialogFragment {
private static final String TAG = "Fragment";
private String[] provinces;
public String province="京";//默认
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
provinces = ((MainActivity) getActivity()).provinces;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setTitle(R.string.app_name)
.setSingleChoiceItems(provinces, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
province = provinces[which];
}
})
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mListener.onDialogPositiveClick(NoticeDialogFragment.this);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mListener.onDialogNegativeClick(NoticeDialogFragment.this);
}
});
return builder.create();
}
interface DialogListener {
void onDialogPositiveClick(DialogFragment dialog);
void onDialogNegativeClick(DialogFragment dialog);
}
DialogListener mListener;
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Verify that the host activity implements the callback interface
try {
// Instantiate the NoticeDialogListener so we can send events to the host
mListener = (DialogListener) context;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(context.toString()
+ " must implement NoticeDialogListener");
}
}
}
public class MainActivity extends AppCompatActivity implements NoticeDialogFragment.DialogListener
@Override
public void onDialogPositiveClick(DialogFragment dialog) {
Log.d(TAG, ((NoticeDialogFragment)dialog).province);
}
@Override
public void onDialogNegativeClick(DialogFragment dialog) {
}
仿ios透明加载框
一
效果图
工具类
为了方便以后使用,写成工具类。
public class ProgressDialogUtil {
private static Dialog mDialog;
private static ProgressDialogUtil dialogUtil;
private ProgressDialogUtil() {
super();
}
public static ProgressDialogUtil getInstance(Context context) {
if (mDialog == null) {
dialogUtil = new ProgressDialogUtil();
AlertDialog.Builder mBuilder = new AlertDialog.Builder(context, R.style.full_screen_dialog);
View view = LayoutInflater.from(context).inflate(R.layout.custom_progress_dialog_2, null);
mBuilder.setView(view);
mBuilder.setCancelable(true);
mDialog = mBuilder.create();
mDialog.setCanceledOnTouchOutside(false);
Window win = mDialog.getWindow();
//显示对话框时,后面的Activity不变暗,可选操作。
win.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
//获取对话框当前的参数值,下面代码不加也可以
// WindowManager.LayoutParams params = win.getAttributes();
// params.gravity = Gravity.CENTER;
// win.setAttributes(params);
}
return dialogUtil;
}
public void showProgressDialog() {
if (!mDialog.isShowing()) {
mDialog.show();
}
}
public void dismissProgressDialog() {
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
}
**R.style.full_screen_dialog**
<style name="full_screen_dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
</style>
**R.layout.custom_dialog**
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:background="#78909C"
android:padding="5dp"
android:orientation="horizontal">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载中..."
android:layout_marginLeft="5dp"
android:textSize="16sp"/>
</LinearLayout>
custom_progress_dialog_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#80000000" />
<corners android:radius="8dip" />
</shape>
显示和隐藏
ProgressDialogUtil.getInstance(context).showProgressDialog();
ProgressDialogUtil.getInstance(context).dismissProgressDialog();
WindowManager.LayoutParams.FLAG_DIM_BEHIND
当使用系统的progressDialog时,当前的activity会变暗,这是因为默认的WindowManager.LayoutParams.FLAG_DIM_BEHIND
,DIM是dimmed
的缩写,是变暗的意思
二:采用了帧动画
需要复制的内容
下载Demo复制
- mipmap中的12张图片
- drawable中2个文件,
progress_drawable_list.xml
、custom_progress_dialog_bg.xml
- dialog的自定义布局
- color
- style
- ProgressDialogUtil2
progress_drawable_list.xml 帧动画
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@mipmap/app_loading_001"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_002"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_003"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_004"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_005"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_006"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_007"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_008"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_009"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_0010"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_0011"
android:duration="100"/>
<item
android:drawable="@mipmap/app_loading_0012"
android:duration="100"/>
</animation-list>
ProgressDialogUtil2
public class ProgressDialogUtil2 {
private static ProgressDialogUtil2 instance = null;
private static Dialog dialog;
private static View view;
private TextView tv;
public synchronized static ProgressDialogUtil2 getInstance(Context context) {
if (instance == null) {
instance = new ProgressDialogUtil2();
dialog = new Dialog(context, R.style.CustomDialogStyle);
view = LayoutInflater.from(context).inflate(R.layout.custom_progress_dialog_1, null);
dialog.setContentView(view);
ImageView progressImageView = (ImageView) view.findViewById(R.id.iv_loading);
AnimationDrawable animationDrawable = (AnimationDrawable) progressImageView.getDrawable();
animationDrawable.start();
//要放在动画后面,否则无效
dialog.setCanceledOnTouchOutside(false);
}
return instance;
}
public void show() {
dialog.show();
}
public void showstr(String str) {
if (tv == null) {
tv = (TextView) view.findViewById(R.id.tv_loading);
tv.setText(str);
} else {
tv.setText(str);
}
dialog.show();
}
public void cancle() {
if (dialog == null) {
return;
} else {
dialog.cancel();
}
}
}
显示和隐藏
ProgressDialogUtil2.getInstance(context).show();
ProgressDialogUtil2.getInstance(context).cancle();
Demo: http://git.oschina.net/AndroidUI/customdialog01
系统级的Dialog
我们都知道dialog是依赖activity而存在的,但是系统级的Dialog不依赖Activity,所以当按下Button的同时,我们弹出此Dialog,同时进入MainActivity2页面,这是会发现,在activity的切换过程中,Dialog一直都存在。
效果图
权限+Type
需要权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
需要设置TYPE_SYSTEM_ALERT
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
设置完type后,在360、小米、魅族手机上dialog
仍然不显示,这是因为厂家对系统走了修改,解决方方法是在设置TYPE_TOAST
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
下面来自android不用context弹dialog
无意中用了一个4.0系统(<19)的手机测试了一下,dialog能弹出来,但是界面里面的button根本不能点击!这就尴尬了!经过一番资料的查找问题终于找到了:
1.WindowManager.LayoutParams.TYPE_TOAST仅在 API level >= 19 时可以正常显示,API level 19 以下因无法接收无法接收触摸(点击)和按键事件!
2.API level 19 后做了调整,当我们使用 TYPE_TOAST, Android 会偷偷给我们加上 FLAG_NOT_FOCUSABLE 和 FLAG_NOT_TOUCHABLE , 4.0.1 开始, 会额外再去掉FLAG_WATCH_OUTSIDE_TOUCH。 这样真的是什么事件都没了。
3.对于 API level < 19 的机器(MIUI除外),想要达到目的,需要:
a.要有 android.permission.SYSTEM_ALERT_WINDOW 权限
b.将 type 设置为 WindowManager.LayoutParams.TYPE_PHONE 或者 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//解决Android 7.1.1起不能再用Toast的问题(先解决crash)
if(Build.VERSION.SDK_INT > 24){
md.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
}else{
md.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
}
} else {
md.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
}
其它
参考:android不用context弹dialog
Demo:https://git.oschina.net/AndroidUI/buglyupdate01
注意
dialog的Context不能使用getApplicationContext()
dialog
中不能使用getApplicationContext()
,会报错。因为dialog
是依附于activity
而存在的。
dialog.setCanceledOnTouchOutside(false)无效
原因:
1. 在dialog.show()之前调用无效
2. 自定义的dialog有动画animation-list
也会导致其无效
解决方法:
在show()后面
dialog.show();
dialog.setCanceledOnTouchOutside(false);
在动画后面
AnimationDrawable animationDrawable = (AnimationDrawable) progressImageView.getDrawable();
animationDrawable.start();
dialog.setCanceledOnTouchOutside(false);