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

来源:互联网 发布:优麒麟下安装windows 编辑:程序博客网 时间:2024/06/05 19:56

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;}}@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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};@Overrideprotected 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {showToast("是呀,我们去吃顿大餐吧");}});builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {showToast("真不巧,我已经约了别人啦");}});builder.setNeutralButton("中立", new DialogInterface.OnClickListener() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {showToast("您最后预订的是"+mEatArray[mSingleChoice]);}});builder.setSingleChoiceItems(mEatArray, mSingleChoice, new DialogInterface.OnClickListener() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog, int which, boolean isChecked) {mCheckedArray[which] = isChecked;showToast("您已"+(isChecked?"预订":"取消")+mEatArray[which]);}});builder.create().show();}@Overridepublic 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() {@Overridepublic 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开发笔记的完整目录
1 0
原创粉丝点击