【android开发记录片】2.自定义/定制 Dialog组件
写在前面
好久没有更新android方面的博客,因为一直没搞,最近做一个小项目,用到了Dialog作弹出菜单 和 确认/输入框。这里跟大家分享一下我定制Dialog的方法。
下面是截图:
1.弹出菜单
2.确认框
3.输入框
4.颜色选择框
文件结构
包含dialog的封装类,layout文件,drawable文件。
实现
1.弹出菜单
首先定义对话框的事件接口:
public interface MenuListener{ /** * @方法名称 :onClick * @功能描述 : * @param position 菜单项的下标 * @return :void */ public void onMenuClick(int code, int position); } public interface ConfirmListener{ /** * @方法名称 :onConfirmClick * @功能描述 :当confirm对话框中的按钮被点击时 * @param position * @return :void */ public void onConfirmClick(int position, Object obj); }
然后定义一个layout,里面放一个GridView就好,还定义GridView 的Item的布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/RelativeLayout_Item" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingBottom="1dip"> <ImageView android:id="@+id/item_image" android:layout_centerHorizontal="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@string/nothing" /> <TextView android:layout_below="@id/item_image" android:id="@+id/item_text" android:layout_centerHorizontal="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/nothing" /> </RelativeLayout>
接着是MenuDialog.java,内部有一个Dialog实例,对外提供show()方法:
public MenuDialog(Context context, int id) { this.context = context; this.id = id; } /** * @方法名称 :creatDialog * @功能描述 :创建一个菜单Dialog,需要有数据才得,否则 menuDialog 为null * @param menuDialog * @param data * @return :void */ public void creatDialog(final MenuData data){ if(data == null) return ; if(data.icons.length > 0){ View view = View.inflate(context, getMenuLayout(), null); //优先使用图片作为背景 if(data.bgResource != -1){ view.setBackgroundDrawable( UIFactory.getRepeatBG(context,data.bgResource) ); }else if(data.bgColor != -1){ Log.i("CellNote", "set bgColor---------"); view.setBackgroundColor(data.bgColor); } GridView gView = (GridView)view.findViewById(GRID_ID); gView.setAdapter(getMenuAdapter(data)); dialog = new Dialog(context); dialog.show(); Window win = dialog.getWindow(); //将dialog的背景透明化 win.setBackgroundDrawable(new ColorDrawable(0)); win.setGravity(getGravity()); win.setContentView(view); if(data.listener != null){ //注册菜单事件 gView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { data.listener.onMenuClick(id,arg2); if(data.onlyOneTime) dialog.dismiss(); } }); } registerKey(); this.hasMenu = true; } } /** * @方法名称 :show * @功能描述 :显示对话框 * @return :void */ public void show(){ dialog.show(); }
在Activity中如此调用:
@Override public boolean onCreateOptionsMenu(Menu menu) { menu.add("danting"); return super.onCreateOptionsMenu(menu); } @Override public boolean onMenuOpened(int featureId, Menu menu) { hideKeyboard(); if (menuDialog == null) { menuDialog = new MenuDialog(this, MENU_OPTION); menuDialog.creatDialog(getMenuData()); Log.i("CellNote","menuDialog create!!"); } if(menuDialog.hasMenu) menuDialog.show(); // 返回false 阻止系统的菜单 return false; }
上面是一个父类Activity通用的产生弹出菜单的方法(在onCreateOptionsMenu()方法,menu.add("");是一定要的,不要的话不会弹出对话框,这个不解=.=),子类只需要重写 getMenuData()方法就可以产生菜单,如:
/** * 产生菜单 */ @Override public MenuData getMenuData() { MenuData data = new MenuData(); data.icons = new int[]{ R.drawable.ic_menu_color_home, R.drawable.ic_menu_color_category, R.drawable.ic_menu_color_note, R.drawable.ic_menu_color_search, R.drawable.ic_menu_color_setting, R.drawable.ic_menu_color_bag, R.drawable.ic_menu_color_help, R.drawable.ic_menu_color_about }; data.labels = new String[]{"首页","新分类","新便签","内容搜索","设置","备份/还原","帮助","关于我们"}; data.listener = this; data.bgResource = R.drawable.bg_green_32x32; return data; }
上面用到了一个MenuData类,如下:
/** * @项目名称 :CellNote * @文件名称 :MenuDialog.java * @所在包 :org.nerve.cellnote.view * @功能描述 : * 菜单数据体,其中 icons 是菜单的图像引用,labels 是菜单文字 * @创建者 :集成显卡 1053214511@qq.com * @创建日期 :2013-1-23 * @修改记录 : */ public static class MenuData{ /**背景的drawable,如果为-1,则使用默认的背景*/ public int bgResource = -1; /**背景颜色*/ public int bgColor = -1; /**菜单点击监听器*/ public MenuListener listener; /**为true时,菜单被点击后后自动消失*/ public boolean onlyOneTime; public int[] icons = new int[0]; public String[] labels; public MenuData(){ this.onlyOneTime = true; } public MenuData(int [] is,String[] ls){ this(); this.icons = is; this.labels = ls; } }
2.确认对话框
定义layout:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@drawable/shape_dialog" > <TextView android:id="@+id/dialog_title" android:layout_width="fill_parent" android:layout_height="35dp" android:textSize="18sp" android:textColor="#000000" android:gravity="center" /> <TextView android:id="@+id/dialog_message" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="20dp" android:paddingBottom="2dp" android:textColor="#000000" /> <!-- 这个可以自由添加视图 --> <LinearLayout android:id="@+id/dialog_live" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" > </LinearLayout> <LinearLayout android:id="@+id/dialog_button_group" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="20dp" android:paddingRight="20dp" android:paddingBottom="15dp"> <Button android:id="@+id/dialog_ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/dialog_ok" android:padding="3dp" android:background="@drawable/shape_dialog_button_ok" android:textColor="@color/black" android:layout_marginRight="10dp"/> <Button android:id="@+id/dialog_cannel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/dialog_cannel" android:layout_marginLeft="10dp" android:textColor="@color/black" android:background="@drawable/shape_dialog_button_cannel"/> </LinearLayout> </LinearLayout>
然后是ConfirmDialog.java:
package org.nerve.cellnote.view.dialog; import org.nerve.cellnote.R; import org.nerve.cellnote.view.dialog.DialogHelper.ConfirmListener; import android.app.Dialog; import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.WindowManager.LayoutParams; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; /** * @项目名称 :CellNote * @文件名称 :ConfirmDialog.java * @所在包 :org.nerve.cellnote.view.dialog * @功能描述 : * 确定对话框,显示标题,内容,还有确定和取消按钮 * @创建者 :集成显卡 1053214511@qq.com * @创建日期 :2013-1-28 * @修改记录 : */ public class ConfirmDialog { /**默认的对话框视图*/ public static int DIALOG_UI = R.layout.dialog_main; /**默认的对话框占主屏幕多宽度的比例*/ public static float WIDTH_SCALE = 0.8F; /**OK按钮被点击*/ public static final int OK = 0; /**取消按钮点击*/ public static final int CANNEL = 1; protected Context context; protected Dialog dialog; protected Button okBtn; protected Button cannelBtn; protected int id; protected String title; protected String message; protected ConfirmListener listener; public ConfirmDialog(Context context){ this.context = context; } public ConfirmDialog(Context context, String t, String m){ this(context); this.title = t; this.message = m; } public void setTitle(String t){ this.title = t; } public void setMessage(String m){ this.message = m; } public void setConfirmListener(ConfirmListener listener){ this.listener = listener; } protected void createDialog(){ View view = View.inflate(context, getMainXML(), null); ((TextView)view.findViewById(R.id.dialog_title)).setText(title); //如果message为null,不显示 TextView messageTV = (TextView)view.findViewById(R.id.dialog_message); if(message == null) ((LinearLayout)view).removeView(messageTV); else messageTV.setText(message); dialog = new Dialog(context); dialog.show(); Window win = dialog.getWindow(); //将dialog的背景透明化 win.setBackgroundDrawable(new ColorDrawable(0)); win.setGravity(getGravity()); LinearLayout ll = (LinearLayout)view.findViewById(R.id.dialog_live); View liveView = getLiveView(); if(liveView != null){ ll.addView(liveView); } win.setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); win.setContentView(view); initButton(view); } public void show(){ if(dialog == null) createDialog(); else dialog.show(); } /** * @方法名称 :initButton * @功能描述 :初始化按钮 * * @param view * @return :void */ protected void initButton(View view){ if(isButtonShow()){ okBtn = (Button)view.findViewById(R.id.dialog_ok); cannelBtn = (Button)view.findViewById(R.id.dialog_cannel); okBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); afterClickOK(); } }); cannelBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); }else{ View v = view.findViewById(R.id.dialog_button_group); ((LinearLayout)view).removeView(v); } } /** * @方法名称 :isButtonShow * @功能描述 :如果子类不需要显示按钮,可以重写这个方法。 * @return * @return :boolean */ protected boolean isButtonShow(){ return true; } /** * @方法名称 :getMainXML * @功能描述 :获得主视图id * @return * @return :int */ public int getMainXML(){ return DIALOG_UI; } public int getGravity(){ return Gravity.CENTER; } /** * @方法名称 :afterClickOK * @功能描述 :确认按钮点击后触发,子类可以重写这个方法达到不同的效果 * @return :void */ public void afterClickOK(){ if(listener != null) listener.onConfirmClick(OK, null); } /** * @方法名称 :getLiveView * @功能描述 :得到一个扩展的视图,可以产生不同组合的对话框,子类可以重写这个方法 * @return * @return :View */ public View getLiveView(){ return null; } }
子类可以通过重写一些方法再定义对话框。
调用方法:
ConfirmDialog cd = new ConfirmDialog(this); cd.setTitle("关于我们"); StringBuilder about = new StringBuilder(); about.append("名称:"+getString(R.string.app_name)); about.append("\n版本:" + getString(R.string.app_version)); about.append("\n作者:" + getString(R.string.app_author)); about.append("\n简介:" + getString(R.string.app_information)); about.append("\n邮箱:" + getString(R.string.app_email)); cd.setMessage(about.toString()); cd.show();
3.输入对话框
dialog_single_input.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="20dp" android:paddingRight="20dp" > <EditText android:id="@+id/dialog_single_input" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@null" /> </LinearLayout>
然后 SingleInputDialog 继承自 ConfirmDialog,重写getView() 方法,返回 上面的布局:
package org.nerve.cellnote.view.dialog; import org.nerve.cellnote.R; import android.content.Context; import android.view.View; import android.widget.EditText; /** * @项目名称 :CellNote * @文件名称 :SingleInputDialog.java * @所在包 :org.nerve.cellnote.view.dialog * @功能描述 : * 只有一个输入的对话框,在这里,message 被设置为了:请输入 * @创建者 :集成显卡 1053214511@qq.com * @创建日期 :2013-1-28 * @修改记录 : */ public class SingleInputDialog extends ConfirmDialog{ protected EditText singleInput; protected String defaultText; public SingleInputDialog(Context context) { super(context); } @Override public View getLiveView() { View lv = View.inflate(context, R.layout.dialog_single_input, null); this.singleInput = (EditText)lv.findViewById(R.id.dialog_single_input); this.singleInput.setText(defaultText); return lv; } @Override public void afterClickOK() { listener.onConfirmClick(OK, singleInput.getText().toString()); } public void setDefaultText(String t){ this.defaultText = t; } }
调用方法:
SingleInputDialog sd = new SingleInputDialog(this); String title = getString(R.string.category_input); sd.setTitle(title); sd.setMessage(title + ":"); sd.setConfirmListener(new ConfirmListener() { @Override public void onConfirmClick(int position, Object obj) { String name = (String)obj; newCategoryDo(name); } }); sd.show();
恩,帖了好多代码,这里就源文件打包给大家下载,下载导入到自己的工程里便可以看到效果:http://download.csdn.net/detail/ssrc0604hx/5062435