选择对话框:自定义组合控件+自定义对话框 实现

本文出自:http://blog.csdn.net/billpig/article/details/6664053

由于项目的需要,需要用到选择对话框,虽然可以使用系统自带到控件就可以实现,但是从长远的角度上去看,还是不利于本项目的发展,于是自己做了一个自定义的控件,使用到了组合控件,顺便也学习了下组合控件的创建。

自定义控件有多种方式,具体就不提及了,本次俺只使用组合控件,先上个图,让大家对本次所实现的效果有个直观的认识:


如上图所示,我希望能在点击“浏览模式”的时候弹出选择对话框(注意:这个按钮有标题和当前选择项,右边还有一个图标以提示用户),而且这个对话框是可以使用自定义的对话框。针对这种实现,我想到的可能的几种方法:

  1. 使用ListPreference
    • 难点1:使用PreferenceActivity的背景颜色不知道可以选择不? 个人觉得应该可以更改掉
    • 难点2:Preference不是要保存数据么?如果不保存数据要如何去做?  经过查证,可以设置它的persistence属性,使其不保存数据
    • 难点3:能够更改对话框的布局?应该可以,俺不确定,有待求证
  2. 使用Spinner
    • 难点1:主页面(标题、当前选项、右边加一个图标)显示使用组合对话框应该可以解决,不过好像也蛮麻烦的
    • 难点2:能够更改对话框的布局?应该可以,俺不确定,有待求证
  3. 完全自定义
    • 难点1:控件的美观程度?应该可以用图片解决
    • 难点2:弹出对话框后选择选项后改变相应的内容
    • 难点3:自定义对话框布局

起初做的时候,可能查证的信息不够多,因此,头两种方式没有求尝试实现,当时就选择了最后的一种方式。


我们选择了自定义控件的方式,于是定义了一个类ListSelectView extends LinearLayout,有如下变量

  1. private TextView tvHeader;    //Item 的标题  
  2. private TextView tvContent;   //Item的选项  
  3.   
  4. private CharSequence[] mEntries;   //对话框的选项  
  5.        private CharSequence[] mEntryValues;  //选择对话框后的值  
  6. private int mClickedDialogEntryIndex; //对话框选项的index  


1、item项目实现

首先是主页的item项:



定义了如下布局:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout  
  3.   xmlns:android="http://schemas.android.com/apk/res/android"  
  4.   android:orientation="horizontal"  
  5.   android:layout_width="fill_parent"  
  6.   android:layout_height="fill_parent"  android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="10dp" android:paddingBottom="4dp">  
  7.       
  8.     <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_weight="1">  
  9.         <TextView android:id="@+id/tvListSelectLayoutTitle" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingBottom="0dp" />  
  10.         <TextView android:id="@+id/tvListSelectLayoutContent" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="10dp" android:paddingTop="0dp" />  
  11.     </LinearLayout>  
  12.     <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="fitCenter" android:background="@drawable/ic_btn_round_more_normal"/>  
  13. </LinearLayout>  


就大致了实现了这样的布局,然后在attrs.xml中定义了两个属性(可根据情况添加)
  1. <declare-styleable name="ListSelectView">  
  2.     <attr name="entries" format="reference"/>  
  3.     <attr name="entryValues" format="reference" />  
  4. </declare-styleable>  

之后在在ListSelectView构造函数中初始化控件及状态
  1. public ListSelectView(Context context, AttributeSet attrs) {  
  2.     super(context, attrs);  
  3.     LayoutInflater.from(context).inflate(R.layout.list_select_layout, thistrue);  
  4.     TypedArray a = context.obtainStyledAttributes(attrs, org.lansir.R.styleable.ListSelectView, 00);  
  5.     mEntries = a.getTextArray(org.lansir.R.styleable.ListSelectView_entries);  //从属性处初始化值  
  6.     mEntryValues = a.getTextArray(org.lansir.R.styleable.ListSelectView_entryValues);  
  7.     a.recycle();  
  8.   
  9.     tvHeader = (TextView) findViewById(R.id.tvListSelectLayoutTitle);  //初始化控件  
  10.     tvContent = (TextView) findViewById(R.id.tvListSelectLayoutContent);  
  11.     tvHeader.setTextColor(Color.BLACK);  //设置标题颜色  
  12.     tvContent.setGravity(Gravity.TOP);  
  13.     this.setOnClickListener(this); //设置点击事件  
  14. }  



得到的效果如上,具体的美工在后期可通过贴图实现

这样,Item项就初始化完毕了

2、对话框实现

接下来是对话框的视图:

上节中,我们设置了点击事件,事件的内容如下:

  1. @Override  
  2. public final void onClick(View v) {  
  3.   
  4.     SingleSelectionDialog dialog = new SingleSelectionDialog.Builder(this.getContext()).setTitle(tvHeader.getText()).setSingleChoiceItems(mEntries,  
  5.             mClickedDialogEntryIndex, new DialogInterface.OnClickListener() {  
  6.   
  7.                 @Override  
  8.                 public void onClick(DialogInterface dialog, int which) {  
  9.                     mClickedDialogEntryIndex = which;  
  10.                     tvContent.setText(mEntryValues[mClickedDialogEntryIndex]);  
  11.                     dialog.dismiss();  
  12.                 }  
  13.   
  14.             }).create();  
  15.   
  16.     dialog.show();  
  17.   
  18.   
  19. }  

在这里自定义了一个对话框,SingleSelectionDialog是一个继承自Dialog的一个类,之所以不继承自AlertDialog,是因为AlertDialog要去自定义内容及Style比Dialog类还麻烦,要通过比较复杂的方式去实现。同时,这里setSingleChoiceItems是SingleSelectionDialog类自定义的一个封装方法,这里设置了对话框List选项的值及事件,在这个事件里,设置选项的Index,以便下次再次点击对话框时设置成已设置的值,同时,这里改变主页Item选项值t的内容及关闭对话框。


SingleSelectionDialog的代码实现如下:

  1. public class SingleSelectionDialog extends Dialog {  
  2.   
  3.     public SingleSelectionDialog(Context context, boolean cancelable,  
  4.             OnCancelListener cancelListener) {  
  5.         super(context, cancelable, cancelListener);  
  6.   
  7.     }  
  8.   
  9.     public SingleSelectionDialog(Context context, int theme) {  
  10.         super(context, theme);  
  11.     }  
  12.   
  13.     public SingleSelectionDialog(Context context) {  
  14.         super(context);  
  15.     }  
  16.   
  17.     public static class Builder {  
  18.   
  19.         private Context context;  
  20.         private CharSequence title;  //对话框标题  
  21.         private CharSequence[] mListItem; //对话框选项值  
  22.         private int mClickedDialogEntryIndex;  //对话框选项Index  
  23.         private DialogInterface.OnClickListener mOnClickListener;  //对话框点击事件  
  24.   
  25.         public Builder(Context context) {  
  26.             this.context = context;  
  27.         }  
  28.   
  29.         public Builder setTitle(int title) {  
  30.             this.title = (String) context.getText(title);  
  31.             return this;  
  32.         }  
  33.   
  34.         public Builder setTitle(CharSequence title) {  
  35.             this.title = title;  
  36.             return this;  
  37.         }  
  38.   
  39.         public CharSequence[] getItems() {  
  40.             return mListItem;  
  41.         }  
  42.   
  43.         public Builder setItems(CharSequence[] mListItem) {  
  44.             this.mListItem = mListItem;  
  45.             return this;  
  46.         }  
  47.           
  48.         //设置单选List选项及事件,这些属性在之后的create中用到,这里使用Android系统创建dialog的风格  
  49.         public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) {  
  50.             this.mListItem = items;  
  51.                         this.mOnClickListener = listener;  
  52.                         this.mClickedDialogEntryIndex = checkedItem;  
  53.                         return this;  
  54.                 }   
  55.   
  56.       
  57.         public SingleSelectionDialog create() {  
  58.             LayoutInflater inflater = (LayoutInflater) context  
  59.                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  60.             final SingleSelectionDialog dialog = new SingleSelectionDialog(  
  61.                     context, R.style.Theme_Dialog_ListSelect);  
  62.             View layout = inflater.inflate(R.layout.single_selection_dialog,  
  63.                     null);  
  64.             dialog.addContentView(layout, new LayoutParams(  
  65.                     LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));  
  66.               
  67.             if(mListItem == null){  
  68.                 throw new RuntimeException("Entries should not be empty");  
  69.             }  
  70.             ListView lvListItem = (ListView) layout.findViewById(R.id.lvListItem);  
  71. //          android.R.layout.simple_list_item_single_choice  
  72.             //lvListItem.setAdapter(new ArrayAdapter(context, android.R.layout.simple_list_item_single_choice, android.R.id.text1, mListItem));  
  73. //          SingleSelectionAdapter mSingleSelectionAdapter = new SingleSelectionAdapter(context, R.layout.single_list_item, R.id.ctvListItem, mListItem);  
  74. //          lvListItem.setAdapter(mSingleSelectionAdapter);  
  75.             lvListItem.setAdapter(new ArrayAdapter(context,  R.layout.single_selection_list_item, R.id.ctvListItem, mListItem));  
  76.             lvListItem.setOnItemClickListener(new OnItemClickListener(){  
  77.   
  78.                 @Override  
  79.                 public void onItemClick(AdapterView<?> parent, View view,  
  80.                         int position, long id) {  
  81.                     mOnClickListener.onClick(dialog, position);  
  82.   
  83.                 }  
  84.                   
  85.             });  
  86.             lvListItem.setChoiceMode(ListView.CHOICE_MODE_SINGLE);  
  87.             lvListItem.setItemChecked(mClickedDialogEntryIndex, true);  
  88.             lvListItem.setSelection(mClickedDialogEntryIndex);  
  89.           
  90.   
  91.             TextView tvHeader = (TextView)layout.findViewById(R.id.title);  
  92.             tvHeader.setText(title);  
  93.                       
  94.               
  95.             return dialog;  
  96.         }         
  97.           
  98.     }  
  99.   
  100. }  


setSingleSelectItems设置了单选列表的Item以及事件,这些属性在create中用到。

最关键的就是create()方法,在这里初始化dialog的主题:

  • 取消标题
  • 取消边框
  • 使用透明
style样式如下:
  1. <style name="Theme.Dialog.ListSelect" parent="android:style/Theme.Dialog">  
  2.     <item name="android:windowIsFloating">true</item>  
  3.     <item name="android:windowIsTranslucent">false</item><!--半透明-->  
  4.     <item name="android:backgroundDimEnabled">false</item><!--模糊-->  
  5.     <item name="android:windowContentOverlay">@null</item>  
  6.     <item name="android:windowNoTitle">true</item>   
  7.     <item name="android:windowFrame">@null</item><!--边框-->  
  8. </style>  


之后是使用setContent初始化内容,这里,使用自定义布局的方式去创建,xml布局文件如下:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:minWidth="280dip" android:layout_height="wrap_content">  
  5.          //标题  
  6.     <LinearLayout android:orientation="vertical"  
  7.         android:background="@drawable/header" android:layout_width="fill_parent"  
  8.         android:layout_height="wrap_content">  
  9.   
  10.         <TextView style="@style/DialogText.Title" android:id="@+id/title"  
  11.             android:paddingRight="8dip" android:paddingLeft="8dip"  
  12.             android:background="@drawable/title" android:layout_width="wrap_content"  
  13.             android:layout_height="wrap_content" android:textColor="@color/black" />  
  14.     </LinearLayout>  
  15.         //内容  
  16.     <LinearLayout android:id="@+id/content"  
  17.         android:orientation="vertical" android:background="@drawable/center"  
  18.         android:layout_width="fill_parent" android:layout_height="wrap_content">  
  19.         <ListView android:layout_width="match_parent"  
  20.             android:layout_height="match_parent" android:layout_marginTop="5px"  
  21.             android:cacheColorHint="@null" android:divider="@android:drawable/divider_horizontal_bright"  
  22.             android:scrollbars="vertical" android:id="@+id/lvListItem" />  
  23.   
  24.     </LinearLayout>//底部  
  25.     <LinearLayout android:orientation="horizontal"  
  26.         android:background="@drawable/footer" android:layout_width="fill_parent"  
  27.         android:layout_height="wrap_content" />  
  28.   
  29. </LinearLayout>  


整个布局分为:头部、内容、底部。头部用于显示标题, 内容用于显示单选List, 底部用于美化对话框用。

然后设置Adapter,使得adapter的layout使用我们自定义的layout,这个layout设置list选项的样式:

  1. <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:id="@+id/ctvListItem"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="?android:attr/listPreferredItemHeight"  
  5.     android:textAppearance="?android:attr/textAppearanceLarge"  
  6.     android:gravity="center_vertical"  
  7.     android:checkMark="@drawable/radio_button_selector"  
  8.     android:paddingLeft="6dip"  
  9.     android:paddingRight="6dip"  
  10.     android:textColor="@color/black"  
  11.   
  12. />  

在做这个layout的时候,当初确实不知道如何去做,自己本想定义一个TextView 以及一个RadioButton解决,后来发现这种解决方式一直不理想,主要问题在如何设置单选按钮,实现它的单选功能?用我们自定义的Adapter必须检测是哪个item被选中,但由于ListView的缓存机制增加了这种做法的复杂程度,我们还得为之做个缓冲,保存单选的状态才能实现。而且查看了系统Dialog的源码,发现其本就使用了缓存选项状态的方式去实现,那我们干嘛要自己定义,自己实现,还那么复杂,为何不去使用它呢?于是便查看参考了android.R.layout.simple_list_item_single_choice布局文件的内容,发现它用到了CheckedTextView的控件,但是我们并不想要系统默认的单选样式。于是,自己自定义了一个CheckedTextView,改掉它的单选样式(即android:checkMark)。

于是创建布局完毕,开始最后一步整合,即设置单选列表,容易出问题的地方来了:

  1. ListView lvListItem = (ListView) layout.findViewById(R.id.lvListItem);  
  2. lvListItem.setAdapter(new ArrayAdapter(context,  R.layout.single_selection_list_item, R.id.ctvListItem, mListItem));  
  3. lvListItem.setOnItemClickListener(new OnItemClickListener(){  
  4.   
  5.     @Override  
  6.     public void onItemClick(AdapterView<?> parent, View view,  
  7.             int position, long id) {  
  8.         mOnClickListener.onClick(dialog, position);  
  9.   
  10.     }  
  11.       
  12. });  
  13. lvListItem.setChoiceMode(ListView.CHOICE_MODE_SINGLE);  
  14. lvListItem.setItemChecked(mClickedDialogEntryIndex, true);  
  15. lvListItem.setSelection(mClickedDialogEntryIndex);  
我们使用系统自定义的Adapter,发现它能为我们解决很多问题,如上述的缓存选项状态的问题。这里表明看起来没什么讲究,其实大有讲究:setChoiceMode必须在setItemChecked前调用,否则setChoiceMode会失效,这个也是我查看了Android的ListView的源码实现后才发现的。

这样,选择对话框:自定义组合控件+自定义对话框 完成,使用起来超级简单,完全不需要自己去做很多的设置,我的整个Activity如:

  1. public class SharePrefersActivity extends Activity {  
  2.       
  3.     private ListSelectView mListSelectView;  
  4.       
  5.       
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.         mListSelectView = (ListSelectView)findViewById(R.id.lsvTest);  
  11.         mListSelectView.setHeader("Hello");  
  12.         mListSelectView.setContent("world");  
  13.   
  14.     }  

便能实现如下的效果,来个截图纪念下:



这样,就大功告成了。

3、注意选项

在做这个DEMO的时候,我想设置主页Item的select,于是便在构造函数里使用this.setBackground()去设置,发现这样设置后,在xml里对ListSelectView设置paddingLeft, layout_margin等属性时都会便无效,这里记住这个错误的方式,以提醒后来人!


源代码下载


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC自定义界面HUI,高效简单,含详细注释和示例。 HUI包括基本控件、按钮、标签、编辑框、表格、悬停提示等,可组合出更多功能。资源占用少,效率高,能在低端机上运行,流畅不闪烁,完全满足工控等各种专业软件实现个性化要求。 本资源是“http://download.csdn.net/detail/hhhh63/6961889”的正式发布版。包括3个项目,Hui、HuiDemo1和HuiDemo2。 一、Hui项目 本项目是DLL项目,包括完整的界面库,使用双缓存,局部重画等技术,性能优异。为保证在不同的MFC版本中使用,本次上传提供了这部分的源码,一般不要对其改动。 二、HuiDemo1 简单的应用示例,包括窗口分割,控制面板和主显示区等,展示控件各方向停靠、自动充满、全屏切换、记忆窗口位置和大小、选项设置和保存注册表等功能,用户可直接以此为基础开发新项目。如需扩展其它功能,可从HuiDemo2查找复制相应代码。 三、HuiDemo2 除HuiDemo1的所有功能外,还包括界面库的全部功能和其它实用扩展功能,左中右三栏式分布,左右固定宽度,中间栏大小可变。 1、左边是属性栏,固定宽度,上边是时钟,下边是鼠标信息,当鼠标移到中间的图像区时显示鼠标位置和图像值。 2、中间是图像区,演示如何动态生存索引图像,从下向上移动,自适应大小,长宽比不变,点右边的调色板按钮改变颜色,点保存按钮把当前图像保存到桌面。 3、右边上边是控制栏,在中间的图像区中画各种几何图形,并计算几何图形包围的图像数据的最大值,最小值和平均值。 4、右边下边是表格演示,显示Windows文件夹下的文件列表,自动充满窗口区,随窗口大小改变显示项数,保证界面美观,最下面是搜索和定位功能。 四、运行环境,VC2010或更高版本。 欢迎大家下载并提意见,本资源版权归作者所有,分享供大家研究学心,不得用于商业用途,如有特殊要求请与本人联系。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值