Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 177|回复: 0

[默认分类] android中自定义下拉框

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-5-26 13:47:55 | 显示全部楼层 |阅读模式

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



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








    要实现它,也就是一个PopupWindow时主要的界面,下面来看看代码:
    创建一个DefineSpinnerView.java文件,继承至View,然后给出如下属性:
      
    1.     /**
    2.      * 用于弹出的下拉框
    3.      */
    4.     private PopupWindow pWindow = null;
    5.     // **************************************************************************
    6.     // 这些是用来当点击一个时,根据他们之间的关系来显示下拉框中的内容
    7.     // **************************************************************************
    8.     /**
    9.      * 祖父
    10.      */
    11.     private DefineSpinnerView gradeParent = null;
    12.     /**
    13.      * 父控件
    14.      */
    15.     private DefineSpinnerView parents = null;
    16.     /**
    17.      * 子控件
    18.      */
    19.     private DefineSpinnerView child1 = null;
    20.     /**
    21.      * 孙子控件
    22.      */
    23.     private DefineSpinnerView child2 = null;
    24.     private Context context = null;
    25.     private OptionsAdapter adapter = null; // 下拉框适配器
    26.     private List<String> datas = null; // 下拉框数据
    27.     private RelativeLayout layout = null; // 父控件
    28.     private TextView text = null; // 文本显示
    29.     private ImageView image = null; // 下拉箭头
    30.     private int p_width = -1; // 下拉框宽度
    31.     private ListView list = null; // 下拉表
    复制代码

      
    在构造函数中,构造出一个TextView和一个ImageView控件,并将它们都添加到layout中,代码如下:
      
    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.         image = new ImageView(context);
    11.         image.setBackgroundResource(R.drawable.gerendang_jiantou);
    12.         image.setOnClickListener(lis);
    13.         if (LoginAct.MACHINE_PIXELS == IFinalConstant.XHDPI_RESOLUTION) {
    14.             text.setTextSize(20.0f);
    15.             LayoutParams params2 = new LayoutParams(19, 17);
    16.             params2.topMargin = top + 15;
    17.             params2.leftMargin = left + width - 28;
    18.             map.put(image, params2);
    19.         } else {
    20.             text.setTextSize(15.0f);
    21.             LayoutParams params2 = new LayoutParams(8, 8);
    22.             params2.topMargin = top + 13;
    23.             params2.leftMargin = left + width - 16;
    24.             map.put(image, params2);
    25.         }
    26.         map.put(text, params1);
    复制代码

      
    里面涉及到一个TextListener内部类,是我们自己定义的一个类,它继承至OnClickListener接口
      
    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.         }
    19.    
    复制代码

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



    然后是一些细节了,提供一个TextView设置上面文字和得到上面文字的方法,设置下拉框数据的方法setDatas,如下:
      
    1. public void setText(String str) {
    2.         if (text != null) {
    3.             text.setText(str);
    4.         }
    5.     }
    6.     public void setDatas(List<String> datas) {
    7.         this.datas = datas;
    8.         if (adapter != null) {
    9.             adapter.setDatas(datas);
    10.             adapter.notifyDataSetInvalidated();
    11.         }
    12.     }
    13.     public String getText() {
    14.         if (text != null) {
    15.             return text.getText().toString();
    16.         }
    17.         LoginAct.LogW("spinner"s textView is null");
    18.         return "";
    19.     }
    20.     private void cleanText() {
    21.         if (child1 != null) {
    22.             child1.text.setText("");
    23.         }
    24.         if (child2 != null) {
    25.             child2.text.setText("");
    26.         }
    27.     }
    复制代码

      
    然后添加几个关联控件的get方法:
      
    1. public void setChild1(DefineSpinnerView child1) {
    2.         this.child1 = child1;
    3.     }
    4.     public void setChild2(DefineSpinnerView child2) {
    5.         this.child2 = child2;
    6.     }
    7.     public void setGradeParent(DefineSpinnerView gradeParent) {
    8.         this.gradeParent = gradeParent;
    9.     }
    10.     public void setParents(DefineSpinnerView parents) {
    11.         this.parents = parents;
    12.     }
    13.     public void setP_width(int p_width) {
    14.         this.p_width = p_width;
    15.     }
    复制代码

      
    接下来提供一个设置子控件和算子控件数据的方法:
      
    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.      * @param s 字符串
    23.      * @return
    24.      * @author ZYJ
    25.      * @功能 设置父亲辈的下拉框中的内容
    26.      */
    27.     private List<String> getGuxiang2(String s) {
    28.         List<String> dd = new ArrayList<String>();
    29.         dd.add(context.getString(R.string.butian));
    30.         Map<String, ArrayList<String>> mapTmp = MaterialView.cityMap.get(s);
    31.         if (mapTmp != null) {
    32.             for (String str : mapTmp.keySet()) {
    33.                 dd.add(str);
    34.             }
    35.         }
    36.         return dd;
    37.     }
    复制代码

      
    最后提供一个隐藏软键盘的方法:
      
    1.     private void hideSoft() {
    2.                 InputMethodManager imm = (InputMethodManager) context
    3.                                 .getSystemService(Context.INPUT_METHOD_SERVICE);
    4.                 imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT,
    5.                                 InputMethodManager.HIDE_NOT_ALWAYS);
    6.         }
    复制代码

      
    到这里,自定义控件的代码基本上写完了;我们还要来看看下拉框中的xml布局和适配器的写法:
    xml文件:
    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.     <TextView
    7.             android:id="@+id/info"
    8.             android:layout_width="wrap_content"
    9.             android:layout_height="30dp"
    10.             android:textSize="15sp"
    11.             android:textColor="@color/spinner_text"
    12.             android:layout_gravity="center"
    13.             android:gravity="center"/>
    14. </LinearLayout>
    复制代码

      


    然后是适配器类(OptionsAdapter),看全部代码吧:
      
    1. public class OptionsAdapter extends BaseAdapter {
    2.     private Context context = null;
    3.     private List<String> datas = null;
    4.     public OptionsAdapter(Context context, List<String> d) {
    5.         this.context = context;
    6.         this.datas = d;
    7.     }
    8.     public int getCount() {
    9.         return datas.size();
    10.     }
    11.     public Object getItem(int arg0) {
    12.         return datas.get(arg0);
    13.     }
    14.     public long getItemId(int arg0) {
    15.         return arg0;
    16.     }
    17.     /**
    18.      * @author ZYJ
    19.      * @功能 一个简单TextView显示
    20.      */
    21.     public View getView(int arg0, View arg1, ViewGroup arg2) {
    22.         View view = LayoutInflater.from(context).inflate(R.layout.childlist,
    23.                 null);
    24.         TextView textStr = (TextView) view.findViewById(R.id.info);
    25.         textStr.setText("\t" + getItem(arg0).toString());
    26.         return view;
    27.     }
    28.     public void setDatas(List<String> datas) {
    29.         this.datas = datas;
    30.     }
    31. }
    复制代码

      


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












      





    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-3-29 06:16 , Processed in 0.297326 second(s), 38 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表