Android开发笔记(六十六)自定义对话框

AlertDialog

Android中最常用的对话框是AlertDialog,它可以完成常见的交互操作,如提示、确认、选择等等,然后就是进度对话框ProgressDialog(参见《Android开发笔记(四十九)异步任务处理AsyncTask》)。 AlertDialog没有公开的构造函数,必须借助于AlertDialog.Builder才能完成参数设置。Builder的常用方法如下: setIcon : 设置标题的图标。 setTitle : 设置标题的文本。 setCustomTitle : 设置自定义的标题视图。 --以上方法用于设置标题部分。注意setTitle和setCustomTitle只能设置其一,不能重复设置。 setMessage : 设置内容的文本。 setView : 设置自定义的内容视图。 setAdapter : 设置List方式的内容视图。使用较麻烦,一般不用。 setItems : 设置Spinner方式的内容视图。窗口显示与对话框模式的Spinner极为相似,没有底部的按钮,一旦选中某项就立即关闭对话框。 setSingleChoiceItems : 设置单选列表的内容视图。与setItems的区别在于有显示底部的交互按钮,并且每项右边有单选按钮。 setMultiChoiceItems : 设置多选列表的内容视图。底部有交互按钮,并且每项右边有复选按钮。 --以上方法用于设置内容部分。注意这些方法互相冲突,同时只能设置其一。 setPositiveButton : 设置肯定按钮的信息,如文本、点击监听器。 setNegativeButton : 设置否定按钮的信息,如文本、点击监听器。 setNeutralButton : 设置中性按钮的信息,如文本、点击监听器。 --以上方法用于设置交互按钮。 通过Builder设置完参数,还需调用create方法才能生成AlertDialog对象。不过要想在页面上显示AlertDialog,还得调用该对象的show方法。

Dialog

实际开发中,AlertDialog往往还是无法满足个性化的要求,比如布局不够灵活、按钮的样式无法定制等等,所以常常得自己自定义对话框。查看AlertDialog源码,发现它继承自Dialog,所以自定义对话框的思路就是基于Dialog进行拓展。下面是Dialog的常用方法: Dialog构造函数 : 可定义对话框的主题样式(样式在styles.xml中定义)。如是否有标题、是否为半透明、对话框的背景等等。 isShowing : 判断对话框是否显示。 show : 显示对话框。 hide : 隐藏对话框。 dismiss : 关闭对话框。 setCancelable : 设置对话框是否可取消。 setCanceledOnTouchOutside : 点击对话框外部区域,是否自动关闭对话框。默认会自动关闭 getWindow : 获取对话框的界面对象。 其中getWindow方法是自定义对话框的关键,首先获取到对话框所在的界面对象,才能往这个界面上添加定制视图。废话少说,直接上个自定义对话框的代码例子作为说明:

import com.example.exmdialog.R;

import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.TextView;

public class CustomDialog implements OnClickListener {
	private final static String TAG = "CustomDialog";
	
	private Dialog dialog;
	private View view;
	private TextView tv_title;
	private TextView tv_message;
	private Button btn_ok;
	private OnCustomListener mOnCustomListener;

	public CustomDialog(Context context) {
		view = LayoutInflater.from(context).inflate(R.layout.dialog_custom, null);
		dialog = new Dialog(context, R.style.CustomDialog);
		tv_title = (TextView) view.findViewById(R.id.tv_title);
		tv_message = (TextView) view.findViewById(R.id.tv_message);
		btn_ok = (Button) view.findViewById(R.id.btn_ok);
		btn_ok.setOnClickListener(this);
	}
	
	public void setTitle(String title) {
		tv_title.setText(title);
	}

	public void setMessage(String message) {
		tv_message.setText(message);
	}

	public void setOnCustomListener(OnCustomListener listener) {
		mOnCustomListener = listener;
	}
	
	public interface OnCustomListener {
		public void onClick();
	}

	public void show() {
		dialog.getWindow().setContentView(view);
		dialog.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		dialog.show();
	}

	public void dismiss() {
		if (dialog != null && dialog.isShowing()) {
			dialog.dismiss();
		}
	}

	public boolean isShowing() {
		if (dialog != null) {
			return dialog.isShowing();
		} else {
			return false;
		}
	}

	@Override
	public void onClick(View v) {
		dismiss();
		if (mOnCustomListener != null) {
			mOnCustomListener.onClick();
		}
	}

}

Window

前面自定义对话框提到getWindow可以获取界面对象Window,正好就再深入探讨一下Window类的相关用法。其实不光Dialog,连Activity都是以Window为基础,如果没有Window,Activity根本没法把视图展示在手机上。 下面是Window的几个常用方法: setContentView : 设置内容视图。这个方法是不是很熟悉?我们每天打交道的Activity,第一句就是setContentView,内部原来调用Window的同名方法:getWindow().setContentView setLayout : 设置内容视图的尺寸。 setBackgroundDrawable : 设置内容视图的背景。 getDecorView : 获取当前窗口的顶层视图,可以理解为根部视图。一个运用例子参见《Android开发笔记(十九)底部标签栏TabBar》。 getCurrentFocus : 获取当前焦点所在的视图。 findViewById : 根据资源ID获取该视图的对象。这个方法更熟悉了,Activity每个都要用上许多遍,查看Activity源码,原来该方法也是调用Window的同名方法:getWindow().findViewById requestFeature : 设置窗口的特征。这个似乎也在哪里见过,看看这里有没有《Android开发笔记(二十)顶部导航栏ActionBar》,原来Activity的requestWindowFeature方法也用了Window:getWindow().requestFeature setType : 设置窗口类型。如果要让Service弹出对话框,则必须设置为WindowManager.LayoutParams.TYPE_SYSTEM_ALERT。因为Service没有窗口,只能借用系统警告来弹窗,同时TYPE_SYSTEM_ALERT类型还得加上如下权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

仿ios的滚轮对话框

自定义对话框费了许多口舌,现在说点正经的应用。玩过ios的都知道,苹果手机上有个滚轮控件很酷,比Android呆板的Spinner或AlertDialog要炫很多。不过这个滚轮控件不是本文的重点,可以利用开源代码实现滚轮,这里要做的是从页面底部弹出一个对话框,中间嵌入一个滚轮,通过滚轮来选择具体项,从而完成类似Spinner选择的功能。 滚轮的开源代码从github上找来,包名是“kankan.wheel.widget”,使用方法类似Spinner,也要设置供选择的字符串数组,以及选中的监听器。接着定义一个dialog布局文件,左上角放一个取消按钮,右上角放一个确定按钮,中间放滚轮控件。然后注册相关的事件监听器,如两个按钮的点击事件,滚轮的选中事件。最后是一些参数设置,包括标题、当前位置、文字大小、文字颜色等等。 下面记录滚轮控件的几个默认值,方便以后定制修改: 1、滚轮的默认背景,代码在WheelView.java的SHADOWS_COLORS 2、文字的默认大小和颜色,代码在AbstractWheelTextAdapter.java的DEFAULT_TEXT_SIZE和DEFAULT_TEXT_COLOR 下面是滚轮对话框的代码示例:

import com.example.exmdialog.R;

import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.widget.TextView;
import kankan.wheel.widget.OnWheelChangedListener;
import kankan.wheel.widget.WheelView;
import kankan.wheel.widget.adapters.ArrayWheelAdapter;

/**
 * 关系滚轮对话框
 */
public class WheelDialog implements OnWheelChangedListener, OnClickListener {

	private Dialog dialog;
	private View view;
	private Context mContext;
	private WheelView id_relation;
	private ArrayWheelAdapter<String> arrayWheelAdapter;
	private String[] relation;
	private String[] value;

	private TextView tv_cancel;
	private TextView tv_sure;
	private TextView wheelTitle;
	private int pCurrent = 0;

	public WheelDialog(Context context) {
		mContext = context;
		view = LayoutInflater.from(context).inflate(R.layout.dialog_wheel, null);
		dialog = new Dialog(context, R.style.WheelDialog);

		Window dialogWindow = dialog.getWindow();
		dialogWindow.setGravity(Gravity.BOTTOM);

		relation = context.getResources().getStringArray(R.array.relation_name);
		value = context.getResources().getStringArray(R.array.relation_value);

		tv_cancel = (TextView) view.findViewById(R.id.tv_cancel);
		tv_sure = (TextView) view.findViewById(R.id.tv_sure);
		wheelTitle = (TextView) view.findViewById(R.id.wheelTitle);
		id_relation = (WheelView) view.findViewById(R.id.id_relation);

		arrayWheelAdapter = new ArrayWheelAdapter<String>(context, relation);
		id_relation.setViewAdapter(arrayWheelAdapter);
		id_relation.addChangingListener(this);

		tv_cancel.setOnClickListener(this);
		tv_sure.setOnClickListener(this);
	}

	public void show() {
		dialog.getWindow().setContentView(view);
		dialog.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		dialog.show();
	}

	public void dismiss() {
		if (dialog != null && dialog.isShowing()) {
			dialog.dismiss();
		}
	}

	public boolean isShowing() {
		if (dialog != null)
			return dialog.isShowing();
		return false;
	}

	public void setCancelable(boolean flag) {
		dialog.setCancelable(flag);
	}

	public void setCancelableOnTouchOutside(boolean flag) {
		dialog.setCanceledOnTouchOutside(flag);
	}

	@Override
	public void onChanged(WheelView wheel, int oldValue, int newValue) {
		if (wheel == id_relation) {
			pCurrent = id_relation.getCurrentItem();
		}
	}

	private OnWheelChangeListener onWheelChangeListener;

	public void setOnWheelChangeListener(OnWheelChangeListener onWheelChangeListener) {
		this.onWheelChangeListener = onWheelChangeListener;
	}

	public interface OnWheelChangeListener {
		public void ScollChange(String nickname, String nickvalue);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.tv_cancel:
			dismiss();
			break;
		case R.id.tv_sure:
			if (onWheelChangeListener != null) {
				onWheelChangeListener.ScollChange(relation[pCurrent], value[pCurrent]);
			}
			dismiss();
			break;
		default:
			break;
		}
	}

	public void setNewWheelData(String[] relation, String[] value) {
		this.relation = relation;
		this.value = value;
		arrayWheelAdapter = new ArrayWheelAdapter<String>(mContext, relation);
		id_relation.setViewAdapter(arrayWheelAdapter);
	}

	public void setWheelTitle(String title) {
		wheelTitle.setText(title);
	}

	public void setCurrentItem(int index) {
		id_relation.setCurrentItem(index);
	}

	public void setTextSize(int size) {
		arrayWheelAdapter.setTextSize(size);
	}

	public void setTextColor(int color) {
		arrayWheelAdapter.setTextColor(color);
	}
	
}

代码示例

下面是各类对话框的代码例子,包括:简单的AlertDialog、类似Spinner对话框、单选对话框、多选对话框、自定义对话框、滚轮对话框等等

import com.example.exmdialog.dialog.CustomDialog;
import com.example.exmdialog.dialog.CustomDialog.OnCustomListener;
import com.example.exmdialog.dialog.WheelDialog;
import com.example.exmdialog.dialog.WheelDialog.OnWheelChangeListener;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

	private Button btn_wheel;
	private String[] mTypeArray = {"0", "1", "2", "3", "4", "5", "6", "7"}; 
	private String[] mEatArray = {"中式炒菜", "洋快餐", "港式茶点", 
			"自助餐", "羊肉火锅", "日韩料理", "沙县小吃", "兰州拉面"}; 
	private boolean[] mCheckedArray = {true, false, false, 
			false, false, false, true, false};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Button btn_alert = (Button) findViewById(R.id.btn_alert);
		Button btn_alert_spinner = (Button) findViewById(R.id.btn_alert_spinner);
		Button btn_alert_single = (Button) findViewById(R.id.btn_alert_single);
		Button btn_alert_multi = (Button) findViewById(R.id.btn_alert_multi);
		Button btn_custom = (Button) findViewById(R.id.btn_custom);
		btn_wheel = (Button) findViewById(R.id.btn_wheel);
		btn_alert.setOnClickListener(this);
		btn_alert_spinner.setOnClickListener(this);
		btn_alert_single.setOnClickListener(this);
		btn_alert_multi.setOnClickListener(this);
		btn_custom.setOnClickListener(this);
		btn_wheel.setOnClickListener(this);
		initWheelDialog();
	}

	private int mPosition = 0;
	private WheelDialog mWheelDialog;
	private void initWheelDialog() {
		mWheelDialog = new WheelDialog(this);
		mWheelDialog.setWheelTitle("你要吃什么?");
		mWheelDialog.setOnWheelChangeListener(new OnWheelChangeListener() {
			public void ScollChange(String nickname, String nickvalue) {
				mPosition = Integer.parseInt(nickvalue);
				btn_wheel.setText(mEatArray[mPosition]);
				showToast("您选择的是:"+nickname+"|"+nickvalue);
			}
		});
	}
	
	private void showToast(String hint) {
		Toast.makeText(MainActivity.this, hint, Toast.LENGTH_LONG).show();
	}
	
	private void showAlert() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("今天天气真好啊");
		builder.setMessage("我们去哪里玩玩吧");
		builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				showToast("是呀,我们去吃顿大餐吧");
			}
		});
		builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				showToast("真不巧,我已经约了别人啦");
			}
		});
		builder.setNeutralButton("中立", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				showToast("嗯,今天我有事,明天可以吗");
			}
		});
		AlertDialog alert = builder.create();
		alert.show();
	}
	
	private void showAlertSpinner() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("订餐请选择");
		builder.setItems(mEatArray, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				showToast("您选择的是"+mEatArray[which]);
			}
		});
		builder.create().show();
	}

	private int mSingleChoice = 1;
	private void showAlertSingle() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("单人订餐请选择");
		builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				showToast("您最后预订的是"+mEatArray[mSingleChoice]);
			}
		});
		builder.setSingleChoiceItems(mEatArray, mSingleChoice, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				mSingleChoice = which;
				showToast("您选择的是"+mEatArray[which]);
			}
		});
		builder.create().show();
	}

	private void showAlertMulti() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("多人订餐请选择");
		builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				String meals = "";
				String meal = "";
				for (int i=0; i<mCheckedArray.length; i++) {
					if (mCheckedArray[i] == true) {
						if (meals.length() > 0) {
							meal = "、" + mEatArray[i];
						} else {
							meal = mEatArray[i];
						}
						meals = meals + meal;
					}
				}
				showToast("您最后预订的是:"+meals);
			}
		});
		builder.setMultiChoiceItems(mEatArray, mCheckedArray, new DialogInterface.OnMultiChoiceClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which, boolean isChecked) {
				mCheckedArray[which] = isChecked;
				showToast("您已"+(isChecked?"预订":"取消")+mEatArray[which]);
			}
		});
		builder.create().show();
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_alert) {
			showAlert();
		} else if (v.getId() == R.id.btn_alert_spinner) {
			showAlertSpinner();
		} else if (v.getId() == R.id.btn_alert_single) {
			showAlertSingle();
		} else if (v.getId() == R.id.btn_alert_multi) {
			showAlertMulti();
		} else if (v.getId() == R.id.btn_custom) {
			CustomDialog custom = new CustomDialog(this);
			custom.setTitle("天气冷了");
			custom.setMessage("要多穿衣服噢");
			custom.setOnCustomListener(new OnCustomListener() {
				@Override
				public void onClick() {
					showToast("您点击了自定义对话框的确定按钮");
				}
			});
			custom.show();
		} else if (v.getId() == R.id.btn_wheel) {
			mWheelDialog.setNewWheelData(mEatArray, mTypeArray);
			mWheelDialog.setCurrentItem(mPosition);
			mWheelDialog.setTextSize(20);
			mWheelDialog.setTextColor(0xff1144aa);
			mWheelDialog.show();
		}
	}

}

点击下载本文用到的自定义对话框的工程代码 点此查看Android开发笔记的完整目录

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券