安卓开发中如果想提示用户某些信息,一般都是Toast、dialog或者SnackBar。
toast用作说明;SnackBar则相对“正式”一些,可以显示一些文字信息,并且可以与用户进行简单交互;dialog一般来说用于显示“重量”级信息,例如警示框,进度条等需要用于确切关注的内容。
1、Dialog初级入门 —— 使用系统Dialog
SDK中封装好的Dialog主要包括以下四种:
- AlertDialog——提示对话框框
- ProgressDialog——进程对话框
- DatePickerDialog——日期选择对话框
- TimePickerDialog——时间选择对话框
1、基本提示框:AlertDialog
AlertDialog继承自Dialog,构造方法访问属性为protected,一般需要借助AlertDialog的内部类Builder来生成具体对象(类似情况可以推及Notification);
//参数是一个上下文对象Context
AlertDialog.Builder builder=new AlertDialog.Builder(context);
通过Builder类可以设定显示内容以及按钮的点击事件等
setTitle(String title): 为对话框设置标题 ;
setIcon (int iconId): 为对话框设置图标;
setMessage(String message): 为对话框设置内容;
setView(View view): 给对话框设置自定义样式 ;
setSingleChoiceItems(CharSequence[] items, int checkedItem,DialogInterface.OnClickListener listener):用来设置对话框显示一系列的单选框;
setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems,DialogInterface.OnMultiChoiceClickListener listener):用来设置对话框显示一系列的复选框;
setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) : 响应中立行为的点击;
setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) : 响应Yes/Ok的点击 ;
setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) :响应No/Cancel的点击 ;
create() : 创建对话框 ;
show() : 显示对话框;
一般情况下,使用系统已有的方法就足够了,这能够胜任大部分的需求,效果图如下:
当我们需要显示单选框或者复选框时,可以通过setView将内容部分更换为需要的View:
//layoutId是布局文件的id号。
View view=LayoutInflater.from(context).inflate(layoutId,ViewGroup);
builder.setView(view);
builder.show();
2、等待框&进度框:ProgressDialog
ProgressDialog是通过把ProgeressBar引入dialog封装成的对话框,它可以直接new出新的对象,需要传入一个context参数。ProgressDialog还有一个构造方法
public ProgressDialog(Context context,int theme);
第二个参数表示ProgressDialog的样式,一般默认为圆形,效果如图:
还可以设置为水平样式
public static final int STYLE_HORIZONTAL;
如下图:
进度显示可以通过设置当前值和最大值来确定:
setMax() 设置进度条最大的值;
getMax()
setProgress() 设置当前进度条的值。
getProgress()
3、时间、日期选择框——TimePickerDialog、DatePickerDialog
日期和时间Dialog类似,以TimePickerDialog为例。
(DatePickerDialog中月份是从0开始计算,即month为0表示1月份)
TimePickerDialog一般用来设置定时提醒:
//将hour和minutes设为类的成员
private int hour,minutes;
...
new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute){
//获取设置的时间
this.hour=hourOfDay;
this.minutes=minute;
}
},0,0,true).show();
2、Dialog进阶——自定义AlertDialog
AlertDialog对象的 setView方法将自定义布局view加载到dialog内容显示区域,但标题等部分还是会显示出来;因此若想要完全自定义Dialog显示效果,需要使用setContentView;两者区别如下:
- setview 是将 message 处的布局替换为 view
- setContentView 是将整个对话框替换为 view
自定义AlertDialog显示效果,需要先设计界面布局
XML布局:dialog.xml
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:rowCount="2"
android:columnCount="4"
android:background="#00ff00"
android:layout_gravity="center"
android:alpha="100"
android:padding="0dp"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/sizeSmall"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:gravity="center"
android:text="字体-"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/sizeLarge"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:text="字体+"
android:gravity="center"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/lightDecrease"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:gravity="center"
android:text="亮度-"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/lightIncrease"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:text="亮度+"
android:gravity="center"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/edit"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:text="编辑"
android:gravity="center"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/toPdf"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:text="pdf"
android:gravity="center"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/exit"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:text="退出"
android:gravity="center"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical">
<ImageView
android:clickable="true"
android:id="@+id/save"
android:layout_width="62dp"
android:layout_height="42dp"/>
<TextView
android:text="保存"
android:gravity="center"
android:layout_width="62dp"
android:layout_height="20dp"/>
/>
</LinearLayout>
</GridLayout>
现有一需求,需要让弹出的菜单栏在屏幕中间,大小为wrap_content,现在就自定义dialog来满足需求:
AlertDialog.Builder builder=new AlertDialog.Builder(this);
//设置提示框可取消
builder.setCancelable(true);
//加载需要显示的布局文件
View view=getLayoutInflater().inflate(R.layout.menu_dialog,null);
AlertDialog dialog=builder.create();
//这里要确保show方法调用在setContentView方法之前
dialog.show();
Window window=dialog.getWindow();
WindowManager.LayoutParams lp=window.getAttributes();
// 设置不透明度,取值0-1,1表示不透明
lp.alpha = 0.8f;
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
window.setGravity(Gravity.CENTER);
window.setAttributes(lp);
//自定义Dialog时不能使用已有的setTitle等方法;否则会空指针异常
dialog.setContentView(view);
自定义dialog显示效果:
3、Dialog定制全屏显示——顶部进度框,底部菜单栏
Dialog类与AlertDialog相比,没有多余需要显示的部分,因此实现全屏效果时,应直接继承Dialog 类。
一般系统会强行为Dialog添加某些约束,例如无法完全占满屏幕Width等,因此需要自定义Theme布局,来确保Dialog拥有与Activity相同的整个屏幕:
在/res/values/styles.xml中添加如下样式
<style name="ActivityBottomView">
<item name="android:windowFullscreen">true</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.6</item>
</style>
<style name="ActivityBottomViewAnimation">
<item name="android:windowEnterAnimation">@anim/dialog_activity_menu_enter</item>
<item name="android:windowExitAnimation">@anim/dialog_activity_menu_exit</item>
</style>
<style name="ActivityTopViewAnimation">
<item name="android:windowEnterAnimation">@anim/dialog_activity_top_enter</item>
<item name="android:windowExitAnimation">@anim/dialog_activity_top_exit</item>
</style>
backgroundDimEnabled为true表示开启遮罩窗体,在Dialog弹出后,没有被Dialog遮挡的部分会有半透明效果,backgroundDimAmount用于设置半透明度
新建如下动画效果,保证顶部进度框与底部菜单栏可以平滑的进入和退出:
/res/dialog_activity_menu_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="100%"
android:toYDelta="0"/>
</set>
/res/dialog_activity_menu_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="0"
android:toYDelta="100%"/>
</set>
/res/dialog_activity_top_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="-100%"
android:toYDelta="0"/>
</set>
/res/dialog_activity_top_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="0"
android:toYDelta="-100%"/>
</set>
1、底部菜单栏:ActivityBottomView
public class ActivityBottomView extends Dialog {
private static final String TAG = "ActivityBottomView";
private Context context;
private View dialogView;
/**
* @param context 上下文
* @param View 需要在底部显示的视图
*/
public ActivityBottomView(Context context,View dialogView) {
super(context, R.style.ActivityBottomView);
//调用该方法,保证菜单栏Width可以充满整个屏幕
setOwnerActivity((Activity)context);
this.context = context;
this.dialogView=dialogView;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void show() {
super.show();
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.alpha = 1F;
//这标志表示含义为:所有在该弹出框后的内容都将模糊不清,即显示遮罩窗体
params.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
window.setAttributes(params);
window.setGravity(Gravity.BOTTOM);
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.WRAP_CONTENT);
window.setDimAmount(0.35F);
window.setWindowAnimations(R.style.ActivityBottomViewAnimation);
setContentView(dialogView);
}
}
2、顶部进度框:ActivityTopProgress
public class ActivityTopProgress extends Dialog {
private static final String TAG = "ActivityTopProgress";
private Context context;
private View dialogView;
private ImageView iv_animator;
private TextView tv_message;
private ImageView iv_divider;
private RotateAnimation animator;
/**
* @param context 上下文
*/
public ActivityTopProgress(Context context) {
super(context, R.style.ActivityBottomView);
setOwnerActivity((Activity) context);
this.context = context;
this.dialogView = LayoutInflater.from(context).inflate(R.layout.layout_top_progress, null);
this.iv_animator = (ImageView) this.dialogView.findViewById(R.id.iv_animator);
this.tv_message = (TextView) this.dialogView.findViewById(R.id.tv_message);
this.iv_divider = (ImageView) this.dialogView.findViewById(R.id.iv_divider);
//针对ImageView开启一个自定义的旋转效果
this.animator = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5F, Animation
.RELATIVE_TO_SELF, 0.5F);
this.animator.setDuration(1 * 1000);
this.animator.setRepeatCount(Animation.INFINITE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void show() {
super.show();
//获取顶部statusBar的高度
int paddingTop = ActivityUtil.getStatusBarHeightPixels(context);
//设置iv_divider高度等于状态栏statusBar高度
iv_divider.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
paddingTop));
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.alpha = 1F;
params.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
window.setAttributes(params);
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
window.setGravity(Gravity.TOP);
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.WRAP_CONTENT);
window.setDimAmount(0.35F);
window.setWindowAnimations(R.style.ActivityTopViewAnimation);
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(dialogView);
iv_animator.startAnimation(animator);
}
public void setMessage(CharSequence message) {
tv_message.setText(message);
}
@Override
public void dismiss() {
super.dismiss();
iv_animator.clearAnimation();
}
}
进度框对应的/res/layout/layout_top_progres.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<ImageView
android:background="@color/white"
android:id="@+id/iv_divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_animator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_volume_bluetooth_in_call"/>
<TextView
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:id="@+id/tv_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"/>
</LinearLayout>
</LinearLayout>