首页 > 代码库 > android中自定义下拉框(转)

android中自定义下拉框(转)

android自带的下拉框好用不?我觉得有时候好用,有时候难有,项目规定这样的效果,自带的控件实现不了,那么只有我们自己来老老实实滴写一个新的了,其实最基本的下拉框就像一些资料填写时,点击的时候出现在编辑框的下面,然后又很多选项的下拉框,可是我在网上找了一下,没有这种下拉框额,就自己写了一个,看效果图先:

,这个是资料填写的一部分界面,三个下拉框,选择故乡所在地;

 

点击之后弹出下拉框,选择下面的选项;

三个下拉框时关联的,第一个决定了第二数据内容,第二个决定了第三个数据内容,如果三个全部选好之后,再次点击第一个,那么第二个、第三个都会清空,点击第二个则第三个会清空。

 

 

 

 

要实现它,也就是一个PopupWindow时主要的界面,下面来看看代码:

创建一个DefineSpinnerView.java文件,继承至View,然后给出如下属性:

 

[java] view plaincopyprint?
  1. /** 
  2.  * 用于弹出的下拉框 
  3.  */  
  4. private PopupWindow pWindow = null;  
  5.   
  6. // **************************************************************************  
  7. // 这些是用来当点击一个时,根据他们之间的关系来显示下拉框中的内容  
  8. // **************************************************************************  
  9. /** 
  10.  * 祖父 
  11.  */  
  12. private DefineSpinnerView gradeParent = null;  
  13. /** 
  14.  * 父控件 
  15.  */  
  16. private DefineSpinnerView parents = null;  
  17. /** 
  18.  * 子控件 
  19.  */  
  20. private DefineSpinnerView child1 = null;  
  21. /** 
  22.  * 孙子控件 
  23.  */  
  24. private DefineSpinnerView child2 = null;  
  25.   
  26. private Context context = null;  
  27. private OptionsAdapter adapter = null; // 下拉框适配器  
  28. private List<String> datas = null; // 下拉框数据  
  29. private RelativeLayout layout = null; // 父控件  
  30. private TextView text = null; // 文本显示  
  31. private ImageView image = null; // 下拉箭头  
  32. private int p_width = -1; // 下拉框宽度  
  33. private ListView list = null; // 下拉表  

 

在构造函数中,构造出一个TextView和一个ImageView控件,并将它们都添加到layout中,代码如下:

 

[java] view plaincopyprint?
  1. TextListener lis = new TextListener();  
  2.         text = new TextView(context);  
  3.         text.setBackgroundResource(R.drawable.edit_normal);  
  4.         text.setTextColor(getResources().getColor(R.color.spinner_text));  
  5.         text.setGravity(Gravity.CENTER);  
  6.         text.setOnClickListener(lis);  
  7.         LayoutParams params1 = new LayoutParams(width, hight);  
  8.         params1.leftMargin = left;  
  9.         params1.topMargin = top;  
  10.   
  11.         image = new ImageView(context);  
  12.         image.setBackgroundResource(R.drawable.gerendang_jiantou);  
  13.         image.setOnClickListener(lis);  
  14.         if (LoginAct.MACHINE_PIXELS == IFinalConstant.XHDPI_RESOLUTION) {  
  15.             text.setTextSize(20.0f);  
  16.             LayoutParams params2 = new LayoutParams(19, 17);  
  17.             params2.topMargin = top + 15;  
  18.             params2.leftMargin = left + width - 28;  
  19.             map.put(image, params2);  
  20.         } else {  
  21.             text.setTextSize(15.0f);  
  22.             LayoutParams params2 = new LayoutParams(8, 8);  
  23.             params2.topMargin = top + 13;  
  24.             params2.leftMargin = left + width - 16;  
  25.             map.put(image, params2);  
  26.         }  
  27.   
  28.         map.put(text, params1);  

 

里面涉及到一个TextListener内部类,是我们自己定义的一个类,它继承至OnClickListener接口

 

[java] view plaincopyprint?
  1. /** 
  2.  * @author ZYJ 
  3.  *         当点击Text时,根据上一级的内容来设置下一级的内容 
  4.  */  
  5. class TextListener implements OnClickListener {  
  6.     public void onClick(View v) {  
  7.         hideSoft ();  
  8.         if (gradeParent != null && parents != null) {  
  9.             DefineSpinnerView.this.setDatas(DefineSpinnerView.this  
  10.                     .getGuxiang3(gradeParent.getText(), parents.getText()));  
  11.         }  
  12.         if (gradeParent == null && parents != null) {  
  13.             DefineSpinnerView.this.setDatas(DefineSpinnerView.this  
  14.                     .getGuxiang2(parents.getText()));  
  15.         }  
  16.         cleanText();  
  17.         changPopState(text);  
  18.     }  

 

这个里面调用了一个方法changPopState,它的定义如下:

 

[java] view plaincopyprint?
  1. /** 
  2.  * 显示或者隐藏下拉框 
  3.  * 
  4.  * @param v 
  5.  */  
  6. private void changPopState(View v) {  
  7.     if (pWindow == null) {  
  8.         popWindow(v);  
  9.         return;  
  10.     }  
  11.     if (!pWindow.isShowing()) {  
  12.         popWindow(v);  
  13.     } else {  
  14.         if (pWindow != null) {  
  15.             pWindow.dismiss();  
  16.         }  
  17.     }  
  18. }  

 

这个里面又调用了一个popWindow方法,定义如下:

 

[java] view plaincopyprint?
  1. /** 
  2.      * 初始化下拉框 
  3.      * 
  4.      * @param par 父控件 
  5.      */  
  6.     private void popWindow(final View par) {  
  7.         if (pWindow == null) {  
  8.   
  9.             // 布局文件  
  10.             View v = LayoutInflater.from(context).inflate(R.layout.list, null);  
  11.             list = (ListView) v.findViewById(R.id.list);  
  12.             list.setOnItemClickListener(new OnItemClickListener() {  
  13.                 public void onItemClick(AdapterView<?> arg0, View arg1,  
  14.                                         int arg2, long arg3) {  
  15.                     // R.String.butian代表的是“不填”  
  16.                     if (datas.get(arg2).toString().equals(context.getString(R.string.butian))) {    
  17.                         text.setText("");  
  18.                     } else {  
  19.                         text.setText(datas.get(arg2).toString()); // 将当前点击的item中的字符串显示出来  
  20.                     }  
  21.                     if (pWindow != null) { // 关闭下拉框  
  22.                         changPopState(par);  
  23.                     }  
  24.                 }  
  25.             });  
  26.             adapter = new OptionsAdapter(context, datas); // 根据数据,设置下拉框显示  
  27.             list.setAdapter(adapter);  
  28.             list.setDivider(null); // 屏蔽下拉框每个item之间的线条  
  29.             /** 
  30.              * 两种不同长度的下拉框,主要是为了适应屏幕的大小 
  31.              */  
  32.             if (p_width > 0) {  
  33.                 pWindow = new PopupWindow(v, par.getWidth(), 150);  
  34.             } else {  
  35.                 pWindow = new PopupWindow(v, par.getWidth(), 300);  
  36.             }  
  37.             pWindow.setFocusable(true);  
  38.             pWindow.setBackgroundDrawable(new BitmapDrawable());  
  39.             pWindow.setOutsideTouchable(true);  
  40.             pWindow.update();  
  41.         }  
  42.         pWindow.showAsDropDown(text);  
  43.     }  

 

然后是一些细节了,提供一个TextView设置上面文字和得到上面文字的方法,设置下拉框数据的方法setDatas,如下:

 

[java] view plaincopyprint?
  1. public void setText(String str) {  
  2.         if (text != null) {  
  3.             text.setText(str);  
  4.         }  
  5.     }  
  6.   
  7.     public void setDatas(List<String> datas) {  
  8.         this.datas = datas;  
  9.         if (adapter != null) {  
  10.             adapter.setDatas(datas);  
  11.             adapter.notifyDataSetInvalidated();  
  12.         }  
  13.     }  
  14.   
  15.     public String getText() {  
  16.         if (text != null) {  
  17.             return text.getText().toString();  
  18.         }  
  19.         LoginAct.LogW("spinner‘s textView is null");  
  20.         return "";  
  21.     }  
  22.   
  23.     private void cleanText() {  
  24.         if (child1 != null) {  
  25.             child1.text.setText("");  
  26.         }  
  27.         if (child2 != null) {  
  28.             child2.text.setText("");  
  29.         }  
  30.     }  

 

然后添加几个关联控件的get方法:

 

[java] view plaincopyprint?
  1. public void setChild1(DefineSpinnerView child1) {  
  2.        this.child1 = child1;  
  3.    }  
  4.   
  5.    public void setChild2(DefineSpinnerView child2) {  
  6.        this.child2 = child2;  
  7.    }  
  8.   
  9.    public void setGradeParent(DefineSpinnerView gradeParent) {  
  10.        this.gradeParent = gradeParent;  
  11.    }  
  12.   
  13.    public void setParents(DefineSpinnerView parents) {  
  14.        this.parents = parents;  
  15.    }  
  16.   
  17.    public void setP_width(int p_width) {  
  18.        this.p_width = p_width;  
  19.    }  

 

接下来提供一个设置子控件和算子控件数据的方法:

 

[java] view plaincopyprint?
  1. /** 
  2.      * @param s1 父控件中的字符串 
  3.      * @param s2 子控件中的字符串 
  4.      * @return 返回一个List<String>集合 
  5.      * @功能 通过父控件的字符串来设置子控件中的内容 
  6.      */  
  7.     private List<String> getGuxiang3(String s1, String s2) {  
  8.         List<String> dd = new ArrayList<String>();  
  9.         dd.add(context.getString(R.string.butian));  
  10.         Map<String, ArrayList<String>> mapTmp1 = MaterialView.cityMap.get(s1);  
  11.         if (mapTmp1 != null) {  
  12.             List<String> list = mapTmp1.get(s2);  
  13.             if (list != null) {  
  14.                 for (String str : list) {  
  15.                     dd.add(str);  
  16.                 }  
  17.             }  
  18.         }  
  19.         return dd;  
  20.     }  
  21.   
  22.     /** 
  23.      * @param s 字符串 
  24.      * @return 
  25.      * @author ZYJ 
  26.      * @功能 设置父亲辈的下拉框中的内容 
  27.      */  
  28.     private List<String> getGuxiang2(String s) {  
  29.         List<String> dd = new ArrayList<String>();  
  30.         dd.add(context.getString(R.string.butian));  
  31.         Map<String, ArrayList<String>> mapTmp = MaterialView.cityMap.get(s);  
  32.         if (mapTmp != null) {  
  33.             for (String str : mapTmp.keySet()) {  
  34.                 dd.add(str);  
  35.             }  
  36.         }  
  37.         return dd;  
  38.     }  

 

最后提供一个隐藏软键盘的方法:

 

[java] view plaincopyprint?
  1. private void hideSoft() {  
  2. putMethodManager imm = (InputMethodManager) context  
  3. .getSystemService(Context.INPUT_METHOD_SERVICE);  
  4. m.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT,  
  5. InputMethodManager.HIDE_NOT_ALWAYS);  

 

到这里,自定义控件的代码基本上写完了;我们还要来看看下拉框中的xml布局和适配器的写法:

xml文件:

[html] view plaincopyprint?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.               xmlns:tools="http://schemas.android.com/tools"  
  3.               android:layout_width="match_parent"  
  4.               android:layout_height="match_parent"  
  5.               android:orientation="horizontal">  
  6.   
  7.     <TextView  
  8.             android:id="@+id/info"  
  9.             android:layout_width="wrap_content"  
  10.             android:layout_height="30dp"  
  11.             android:textSize="15sp"  
  12.             android:textColor="@color/spinner_text"  
  13.             android:layout_gravity="center"  
  14.             android:gravity="center"/>  
  15.   
  16. </LinearLayout>  

 

 

然后是适配器类(OptionsAdapter),看全部代码吧:

 

[java] view plaincopyprint?
  1. public class OptionsAdapter extends BaseAdapter {  
  2.   
  3.     private Context context = null;  
  4.     private List<String> datas = null;  
  5.   
  6.     public OptionsAdapter(Context context, List<String> d) {  
  7.         this.context = context;  
  8.         this.datas = d;  
  9.     }  
  10.   
  11.     public int getCount() {  
  12.         return datas.size();  
  13.     }  
  14.   
  15.     public Object getItem(int arg0) {  
  16.         return datas.get(arg0);  
  17.     }  
  18.   
  19.     public long getItemId(int arg0) {  
  20.         return arg0;  
  21.     }  
  22.   
  23.     /** 
  24.      * @author ZYJ 
  25.      * @功能 一个简单TextView显示 
  26.      */  
  27.     public View getView(int arg0, View arg1, ViewGroup arg2) {  
  28.         View view = LayoutInflater.from(context).inflate(R.layout.childlist,  
  29.                 null);  
  30.         TextView textStr = (TextView) view.findViewById(R.id.info);  
  31.         textStr.setText("\t" + getItem(arg0).toString());  
  32.         return view;  
  33.     }  
  34.   
  35.     public void setDatas(List<String> datas) {  
  36.         this.datas = datas;  
  37.     }  
  38.   
  39. }  

 

 

这样,上面的功能基本上都实现了,我的这个控件在我项目中是手动添加上去的,而不是定义在xml文件中的,所以也不知道定义在xml文件中能不能生效,各位尽管试试吧。

 

转自:http://blog.csdn.net/a497393102/article/details/9279309