本文出自:http://blog.csdn.net/billpig/article/details/6664053
由于项目的需要,需要用到选择对话框,虽然可以使用系统自带到控件就可以实现,但是从长远的角度上去看,还是不利于本项目的发展,于是自己做了一个自定义的控件,使用到了组合控件,顺便也学习了下组合控件的创建。
自定义控件有多种方式,具体就不提及了,本次俺只使用组合控件,先上个图,让大家对本次所实现的效果有个直观的认识:
如上图所示,我希望能在点击“浏览模式”的时候弹出选择对话框(注意:这个按钮有标题和当前选择项,右边还有一个图标以提示用户),而且这个对话框是可以使用自定义的对话框。针对这种实现,我想到的可能的几种方法:
- 使用ListPreference
- 难点1:使用PreferenceActivity的背景颜色不知道可以选择不? 个人觉得应该可以更改掉
- 难点2:Preference不是要保存数据么?如果不保存数据要如何去做? 经过查证,可以设置它的persistence属性,使其不保存数据
- 难点3:能够更改对话框的布局?应该可以,俺不确定,有待求证
- 使用Spinner
- 难点1:主页面(标题、当前选项、右边加一个图标)显示使用组合对话框应该可以解决,不过好像也蛮麻烦的
- 难点2:能够更改对话框的布局?应该可以,俺不确定,有待求证
- 完全自定义
- 难点1:控件的美观程度?应该可以用图片解决
- 难点2:弹出对话框后选择选项后改变相应的内容
- 难点3:自定义对话框布局
起初做的时候,可能查证的信息不够多,因此,头两种方式没有求尝试实现,当时就选择了最后的一种方式。
我们选择了自定义控件的方式,于是定义了一个类ListSelectView extends LinearLayout,有如下变量
- privateTextViewtvHeader;
- privateTextViewtvContent;
- privateCharSequence[]mEntries;
- privateCharSequence[]mEntryValues;
- privateintmClickedDialogEntryIndex;
1、item项目实现
首先是主页的item项:
定义了如下布局:
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"android:paddingLeft="10dp"android:paddingRight="10dp"android:paddingTop="10dp"android:paddingBottom="4dp">
- <LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:layout_weight="1">
- <TextViewandroid:id="@+id/tvListSelectLayoutTitle"android:layout_width="fill_parent"android:layout_height="wrap_content"android:paddingBottom="0dp"/>
- <TextViewandroid:id="@+id/tvListSelectLayoutContent"android:layout_width="fill_parent"android:layout_height="wrap_content"android:textSize="10dp"android:paddingTop="0dp"/>
- </LinearLayout>
- <ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:scaleType="fitCenter"android:background="@drawable/ic_btn_round_more_normal"/>
- </LinearLayout>
就大致了实现了这样的布局,然后在attrs.xml中定义了两个属性(可根据情况添加)
- <declare-styleablename="ListSelectView">
- <attrname="entries"format="reference"/>
- <attrname="entryValues"format="reference"/>
- </declare-styleable>
之后在在ListSelectView构造函数中初始化控件及状态
- publicListSelectView(Contextcontext,AttributeSetattrs){
- super(context,attrs);
- LayoutInflater.from(context).inflate(R.layout.list_select_layout,this,true);
- TypedArraya=context.obtainStyledAttributes(attrs,org.lansir.R.styleable.ListSelectView,0,0);
- mEntries=a.getTextArray(org.lansir.R.styleable.ListSelectView_entries);
- mEntryValues=a.getTextArray(org.lansir.R.styleable.ListSelectView_entryValues);
- a.recycle();
- tvHeader=(TextView)findViewById(R.id.tvListSelectLayoutTitle);
- tvContent=(TextView)findViewById(R.id.tvListSelectLayoutContent);
- tvHeader.setTextColor(Color.BLACK);
- tvContent.setGravity(Gravity.TOP);
- this.setOnClickListener(this);
- }
得到的效果如上,具体的美工在后期可通过贴图实现
这样,Item项就初始化完毕了
2、对话框实现
接下来是对话框的视图:
上节中,我们设置了点击事件,事件的内容如下:
- @Override
- publicfinalvoidonClick(Viewv){
- SingleSelectionDialogdialog=newSingleSelectionDialog.Builder(this.getContext()).setTitle(tvHeader.getText()).setSingleChoiceItems(mEntries,
- mClickedDialogEntryIndex,newDialogInterface.OnClickListener(){
- @Override
- publicvoidonClick(DialogInterfacedialog,intwhich){
- mClickedDialogEntryIndex=which;
- tvContent.setText(mEntryValues[mClickedDialogEntryIndex]);
- dialog.dismiss();
- }
- }).create();
- dialog.show();
- }
在这里自定义了一个对话框,SingleSelectionDialog是一个继承自Dialog的一个类,之所以不继承自AlertDialog,是因为AlertDialog要去自定义内容及Style比Dialog类还麻烦,要通过比较复杂的方式去实现。同时,这里setSingleChoiceItems是SingleSelectionDialog类自定义的一个封装方法,这里设置了对话框List选项的值及事件,在这个事件里,设置选项的Index,以便下次再次点击对话框时设置成已设置的值,同时,这里改变主页Item选项值t的内容及关闭对话框。
SingleSelectionDialog的代码实现如下:
- publicclassSingleSelectionDialogextendsDialog{
- publicSingleSelectionDialog(Contextcontext,booleancancelable,
- OnCancelListenercancelListener){
- super(context,cancelable,cancelListener);
- }
- publicSingleSelectionDialog(Contextcontext,inttheme){
- super(context,theme);
- }
- publicSingleSelectionDialog(Contextcontext){
- super(context);
- }
- publicstaticclassBuilder{
- privateContextcontext;
- privateCharSequencetitle;
- privateCharSequence[]mListItem;
- privateintmClickedDialogEntryIndex;
- privateDialogInterface.OnClickListenermOnClickListener;
- publicBuilder(Contextcontext){
- this.context=context;
- }
- publicBuildersetTitle(inttitle){
- this.title=(String)context.getText(title);
- returnthis;
- }
- publicBuildersetTitle(CharSequencetitle){
- this.title=title;
- returnthis;
- }
- publicCharSequence[]getItems(){
- returnmListItem;
- }
- publicBuildersetItems(CharSequence[]mListItem){
- this.mListItem=mListItem;
- returnthis;
- }
- publicBuildersetSingleChoiceItems(CharSequence[]items,intcheckedItem,finalOnClickListenerlistener){
- this.mListItem=items;
- this.mOnClickListener=listener;
- this.mClickedDialogEntryIndex=checkedItem;
- returnthis;
- }
- publicSingleSelectionDialogcreate(){
- LayoutInflaterinflater=(LayoutInflater)context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- finalSingleSelectionDialogdialog=newSingleSelectionDialog(
- context,R.style.Theme_Dialog_ListSelect);
- Viewlayout=inflater.inflate(R.layout.single_selection_dialog,
- null);
- dialog.addContentView(layout,newLayoutParams(
- LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
- if(mListItem==null){
- thrownewRuntimeException("Entriesshouldnotbeempty");
- }
- ListViewlvListItem=(ListView)layout.findViewById(R.id.lvListItem);
- lvListItem.setAdapter(newArrayAdapter(context,R.layout.single_selection_list_item,R.id.ctvListItem,mListItem));
- lvListItem.setOnItemClickListener(newOnItemClickListener(){
- @Override
- publicvoidonItemClick(AdapterView<?>parent,Viewview,
- intposition,longid){
- mOnClickListener.onClick(dialog,position);
- }
- });
- lvListItem.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- lvListItem.setItemChecked(mClickedDialogEntryIndex,true);
- lvListItem.setSelection(mClickedDialogEntryIndex);
- TextViewtvHeader=(TextView)layout.findViewById(R.id.title);
- tvHeader.setText(title);
- returndialog;
- }
- }
- }
setSingleSelectItems设置了单选列表的Item以及事件,这些属性在create中用到。
最关键的就是create()方法,在这里初始化dialog的主题:
style样式如下:
- <stylename="Theme.Dialog.ListSelect"parent="android:style/Theme.Dialog">
- <itemname="android:windowIsFloating">true</item>
- <itemname="android:windowIsTranslucent">false</item><!--半透明-->
- <itemname="android:backgroundDimEnabled">false</item><!--模糊-->
- <itemname="android:windowContentOverlay">@null</item>
- <itemname="android:windowNoTitle">true</item>
- <itemname="android:windowFrame">@null</item><!--边框-->
- </style>
之后是使用setContent初始化内容,这里,使用自定义布局的方式去创建,xml布局文件如下:
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:minWidth="280dip"android:layout_height="wrap_content">
- <LinearLayoutandroid:orientation="vertical"
- android:background="@drawable/header"android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <TextViewstyle="@style/DialogText.Title"android:id="@+id/title"
- android:paddingRight="8dip"android:paddingLeft="8dip"
- android:background="@drawable/title"android:layout_width="wrap_content"
- android:layout_height="wrap_content"android:textColor="@color/black"/>
- </LinearLayout>
- <LinearLayoutandroid:id="@+id/content"
- android:orientation="vertical"android:background="@drawable/center"
- android:layout_width="fill_parent"android:layout_height="wrap_content">
- <ListViewandroid:layout_width="match_parent"
- android:layout_height="match_parent"android:layout_marginTop="5px"
- android:cacheColorHint="@null"android:divider="@android:drawable/divider_horizontal_bright"
- android:scrollbars="vertical"android:id="@+id/lvListItem"/>
- </LinearLayout>
- <LinearLayoutandroid:orientation="horizontal"
- android:background="@drawable/footer"android:layout_width="fill_parent"
- android:layout_height="wrap_content"/>
- </LinearLayout>
整个布局分为:头部、内容、底部。头部用于显示标题, 内容用于显示单选List, 底部用于美化对话框用。
然后设置Adapter,使得adapter的layout使用我们自定义的layout,这个layout设置list选项的样式:
- <CheckedTextViewxmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/ctvListItem"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:gravity="center_vertical"
- android:checkMark="@drawable/radio_button_selector"
- android:paddingLeft="6dip"
- android:paddingRight="6dip"
- android:textColor="@color/black"
- />
在做这个layout的时候,当初确实不知道如何去做,自己本想定义一个TextView 以及一个RadioButton解决,后来发现这种解决方式一直不理想,主要问题在如何设置单选按钮,实现它的单选功能?用我们自定义的Adapter必须检测是哪个item被选中,但由于ListView的缓存机制增加了这种做法的复杂程度,我们还得为之做个缓冲,保存单选的状态才能实现。而且查看了系统Dialog的源码,发现其本就使用了缓存选项状态的方式去实现,那我们干嘛要自己定义,自己实现,还那么复杂,为何不去使用它呢?于是便查看参考了android.R.layout.simple_list_item_single_choice布局文件的内容,发现它用到了CheckedTextView的控件,但是我们并不想要系统默认的单选样式。于是,自己自定义了一个CheckedTextView,改掉它的单选样式(即android:checkMark)。
于是创建布局完毕,开始最后一步整合,即设置单选列表,容易出问题的地方来了:
- ListViewlvListItem=(ListView)layout.findViewById(R.id.lvListItem);
- lvListItem.setAdapter(newArrayAdapter(context,R.layout.single_selection_list_item,R.id.ctvListItem,mListItem));
- lvListItem.setOnItemClickListener(newOnItemClickListener(){
- @Override
- publicvoidonItemClick(AdapterView<?>parent,Viewview,
- intposition,longid){
- mOnClickListener.onClick(dialog,position);
- }
- });
- lvListItem.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- lvListItem.setItemChecked(mClickedDialogEntryIndex,true);
- lvListItem.setSelection(mClickedDialogEntryIndex);
我们使用系统自定义的Adapter,发现它能为我们解决很多问题,如上述的缓存选项状态的问题。这里表明看起来没什么讲究,其实大有讲究:setChoiceMode必须在setItemChecked前调用,否则setChoiceMode会失效,这个也是我查看了Android的ListView的源码实现后才发现的。
这样,选择对话框:自定义组合控件+自定义对话框 完成,使用起来超级简单,完全不需要自己去做很多的设置,我的整个Activity如:
- publicclassSharePrefersActivityextendsActivity{
- privateListSelectViewmListSelectView;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mListSelectView=(ListSelectView)findViewById(R.id.lsvTest);
- mListSelectView.setHeader("Hello");
- mListSelectView.setContent("world");
- }
便能实现如下的效果,来个截图纪念下:
这样,就大功告成了。
3、注意选项
在做这个DEMO的时候,我想设置主页Item的select,于是便在构造函数里使用this.setBackground()去设置,发现这样设置后,在xml里对ListSelectView设置paddingLeft, layout_margin等属性时都会便无效,这里记住这个错误的方式,以提醒后来人!
源代码下载
分享到:
相关推荐
初始化颜色对话框自定义颜色集,显示颜色对话框的自定义颜色控件C#源代码 //初始化颜色对话框自定义颜色集 ColorDialog MyDlg = new ColorDialog(); MyDlg.CustomColors = new int[]{6916092, 15195440, 16107657,...
自定义组合控件之选择对话框 自定义组合控件之选择对话框
custom工程演示了App开发的自定义控件相关知识,包括:自定义视图的步骤(声明属性、构造对象、测量尺寸、绘制视图)、自定义简单动画(任务片段、下拉刷新动画、圆弧进度动画)、自定义对话框的操作(对话框、改进...
vb.net 自定义控件 自定义属性 UITypeEditor UI 类型编辑器 实例 提供一个示例 UITypeEditor,它使用 IWindowsFormsEditorService 显示用于用户输入的 Form。 IWindowsFormsEditorService 只能通过 PropertyGrid ...
自定义对话框图标(源码+示例)
里面含有6个工程,分别实现各种类型的对话框程序,模态对话框:包括基本对话框,含复杂控件的对话框,自定义按钮...非模态对话框包括:含有父窗口的模态对话框,利用脚本加载的自定义对话框,不含父窗口的对话框。
android漂亮的自定义对话框控件,完全可执行代码,里面附效果图,无论自己使用还是代码参考都比较有意义。
自定义控件有段时间没更新了,今天给大家带来一个新的对话框样式,本着用更少的代码实现更丰富的功能。 由于对话框对用户的操作有影响,所以目前app上的对话框用的已经比较少了,但还是有一些比较重要的信息提示需要...
“自定义对话框基础类”,继承自该基类的对话框的控件位置大小按需求随父窗口大小变化,大家感兴趣可以使用下这个类,不足和需要改进的地方请大家多多指教。 压缩包中是一个完整的示例工程,其中ExtDialogST.cpp、...
“自定义对话框基础类”,继承自该基类的对话框的控件位置大小按需求随父窗口大小变化,大家感兴趣可以使用下这个类,不足和需要改进的地方请大家多多指教。 压缩包中是一个完整的示例工程,其中ExtDialogST.cpp、...
史上最强的自定义单选多选对话框 可作为UI模板应用于项目中 少量改动即可实现定制 史上最强的自定义单选多选对话框 可作为UI模板应用于项目中 少量改动即可实现定制
开发过程中经常遇到选择文件路径然后对文件进行处理,普通的处理方式代码粘贴来粘贴去,很麻烦,因此对openFileDialog做了封装,可以直接选取文件,并支持拖拽
自定义对话框源码分别演示了系统对话框和自定义的对话框,可以学习一下自定义控件,有需要的朋友可以自己下载研究一下,编码GBK编译版本2.3.3。
功能效果: 1、控件大小随窗体自由缩放;2、按钮控制侧边栏的显示隐藏;...4、实现自定义气泡提示框,提示框形状依据需求自绘;5、鼠标悬停到按钮控件时候可以弹出自定义气泡提示框,移开时提示框消失。
VB之精彩编程参阅资料-显示文件属性对话框
InstallShield 打包时 使用IP控件
Jokul制作学习制作Web自定义控件的很好的几个例子 控件1:ConfirmButton 点击弹出确认对话框。 控件2:Horologe 显示为钟表日历的控件,拥有DateTime的属性特征。 控件3:LoginCtrl 登录框控件,基本的TextBox...
WPF下自定义MessageBox消息提示框,采用MVVM模式实现前后台分离,包含所使用控件的样式,已测试可编译通过 原文链接:https://blog.csdn.net/wsadcg/article/details/107157853
若要使用当前自定义对话框,只需把单元文件加入工程. 调用ShowMsg函数,定义如下: function ShowMsg(Text:String;Caption:String= 软件名称 ;OptionText:string= 详细的信息 ;ShowType:Integer=SB_OK;ShowIcon:...
提供一个自定义dialog控件,可以自定义设置样式,标题,控制功能