实现简单的多选下拉"spinner"
来源:互联网 发布:大数据时代的阅读答案 编辑:程序博客网 时间:2024/05/20 04:29
在这里之所以是带引号的Spinner是因为他并不是使用的系统的spinner,而是利用popupwindow来实现的一个spinner.
效果图如下:(比较粗糙,可以仿照原理美化下)
_________________________________________________________________________
下面正式介绍
首先第一步:上边的两个类似spinner的东西,
事先准备好9.png图片
写一个style作为我们spinner实现的样式
style.xml
<style name="spinner_style"> <item name="android:background">@drawable/spinner</item> <item name="android:padding">4dp</item> </style>接着构造我们两个spinner的布局在其中引用我们的style.
layout_month_selector.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:background="#ffffff" android:gravity="center"> <ImageView android:layout_width="20dp" android:layout_height="20dp" android:src="@drawable/date"/> </LinearLayout> <TextView android:id="@+id/year" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="5" android:textColor="#000000" android:gravity="center" style="@style/spinner_style"> </TextView> <TextView android:id="@+id/month" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="5" android:textColor="#000000" android:gravity="center" style="@style/spinner_style"> </TextView></LinearLayout>
开始定义我们的控件:
import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.widget.LinearLayout;import android.widget.TextView;/** * Created by lenovo on 2016/11/2. */public class MonthSelector extends LinearLayout{ private View root; private TextView yearText; private TextView monthText; private MonthSelectorDorp drop;//后面定义的下拉window public MonthSelector(Context context) { super(context); initView(context); } public MonthSelector(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MonthSelector(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context){ LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); root = inflater.inflate(R.layout.layout_month_selector,this);//加载我们上面定义的布局,放到this中 yearText = (TextView)root.findViewById(R.id.year); drop = new MonthSelectorDorp(context,this.getMeasuredWidth(),this.getMeasuredHeight()*4); drop.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onYearSelected(String year, int id) { yearText.setText(year); //年份选择时修改yearText中的文字 } @Override public void onMonthSelected(String month, int id) { monthText.setText(month); //月份修改时同上 } }); yearText.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { drop.press(MonthSelectorDorp.YEAR_BUTTON); //告诉drop是选的谁,以便初始布局 drop.showAsDropDown(MonthSelector.this); } }); monthText = (TextView)root.findViewById(R.id.month); monthText.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { drop.press(MonthSelectorDorp.MONTH_BUTTON); drop.showAsDropDown(MonthSelector.this);//drop要显示在这个控件之下 } }); } public String getMonth(){ String result = ""; result = result+yearText.getText().toString(); result = result+"-"+monthText.getText().toString().replace("月",""); return result; } public void setMonth(int year,int month){ this.yearText.setText(""+year); this.monthText.setText(month + "月"); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); drop.setWidth(widthMeasureSpec); //设置drop的宽度和高度,在这才会有效 drop.setHeight(heightMeasureSpec*4); }}
这样,我们上边两个spinner大概就实现了,接下来就是我们下拉框了
根据效果,我这次的布局大概是这样实现(最后再讨论更通用的布局)。
popupwindow_month_selector.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="1dp" android:background="@drawable/popupwindow_bg"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:orientation="vertical"> <TextView android:id="@+id/year_select" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:clickable="true" android:text="@string/by_year" android:gravity="center" android:focusable="true" /> <TextView android:id="@+id/month_select" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="@string/by_month" android:gravity="center" android:focusable="true" /> </LinearLayout> <ListView android:id="@+id/year_list" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="5" android:background="#ffffff"> </ListView> <ListView android:id="@+id/month_list" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="5" android:background="#ffffff"> </ListView></LinearLayout>在这里我们要让popupwindow有个边界,或者可以设置背景色与popupwindow背景色有差异,我采取前者
定义drawable,使他有左右下三条描边
popupwindow_bg.xml
<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item> <shape> <solid android:color="#ffffff"/> <stroke android:color="#c0c0c0" android:width="1dp"/> </shape></item><item android:left="1dp" android:right="1dp" android:bottom="1dp"> <shape> <solid android:color="#ffffff"/> </shape></item></layer-list>以上是多层drawable来实现描三条边。
再往下我们开始写MonthSelectorDrop了
import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.widget.*;/** * Created by lenovo on 2016/11/4. */public class MonthSelectorDorp extends PopupWindow { public final static int YEAR_BUTTON = 1; public final static int MONTH_BUTTON = 2; private TextView yearbtn; private TextView monthbtn; private ListView years; private ListView months; private View contentView; private String yearss[]; private String monthss[]; private OnItemSelectedListener listener; private int flag; public MonthSelectorDorp(Context context,int width, int height) { super(width,height); initView(context); } private void initView(final Context context){ LayoutInflater inflater = LayoutInflater.from(context); contentView = inflater.inflate(R.layout.popwindow_month_selector,null); this.setContentView(contentView); this.setFocusable(true); this.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.popupwindow_bg)); yearbtn = (TextView)contentView.findViewById(R.id.year_select); monthbtn = (TextView)contentView.findViewById(R.id.month_select); years = (ListView)contentView.findViewById(R.id.year_list); months = (ListView)contentView.findViewById(R.id.month_list); years.setDivider(null); months.setDivider(null); years.setVerticalScrollBarEnabled(false); months.setVerticalScrollBarEnabled(false);//不显示滑动条 yearss = context.getResources().getStringArray(R.array.years); //加载预定义的数组 final ListAdapter yearadapter = new ListAdapter(context,R.layout.listview_item_textview,yearss); years.setAdapter(yearadapter);//适配器,自定义的 monthss = context.getResources().getStringArray(R.array.months); final ListAdapter monthadapter = new ListAdapter(context,R.layout.listview_item_textview,monthss); months.setAdapter(monthadapter); years.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { listener.onYearSelected(yearadapter.getItem(position),position); //点击year时执行listener中year函数 dismiss();//popupwindow消失 } }); months.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { listener.onMonthSelected(monthadapter.getItem(position),position);<span style="font-family: Arial, Helvetica, sans-serif;">//因为这里可以获得item所以我listener中增加了参数</span> dismiss(); } }); yearbtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { flag = YEAR_BUTTON; monthbtn.setBackgroundResource(R.drawable.text_normal);//根据选择切换背景 yearbtn.setBackgroundResource(R.drawable.text_focused); months.setVisibility(View.INVISIBLE); years.setVisibility(View.VISIBLE); } }); monthbtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { flag = MONTH_BUTTON; yearbtn.setBackgroundResource(R.drawable.text_normal); monthbtn.setBackgroundResource(R.drawable.text_focused); years.setVisibility(View.INVISIBLE); months.setVisibility(View.VISIBLE); } }); } public void setOnItemSelectedListener(OnItemSelectedListener listener){ this.listener = listener; } public void press(int bId){//用来预先设置好背景,判断点哪个出现的popupwindow switch (bId){ case YEAR_BUTTON: flag = YEAR_BUTTON; monthbtn.setBackgroundResource(R.drawable.text_normal); yearbtn.setBackgroundResource(R.drawable.text_focused); months.setVisibility(View.INVISIBLE); years.setVisibility(View.VISIBLE); break; case MONTH_BUTTON: flag = MONTH_BUTTON; yearbtn.setBackgroundResource(R.drawable.text_normal); monthbtn.setBackgroundResource(R.drawable.text_focused); years.setVisibility(View.INVISIBLE); months.setVisibility(View.VISIBLE); break; default: throw new IllegalArgumentException("don't have this argument"); //抛出非法参数异常 } }}两个点和没点的drawabel
text_focused.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#ffffff"/></shape>text_normal.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#c0c0c0"/></shape>为年份和月份选择准备的OnItemSelectedListener
/** * Created by lenovo on 2016/11/4. */public interface OnItemSelectedListener { public void onYearSelected(String year,int id); public void onMonthSelected(String month,int id);}自定义的ListView的Item
listview_item_textview.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/list_item" android:layout_width="match_parent" android:layout_height="30dp" android:gravity="center" android:textColor="#000000"/></LinearLayout>自己的ListAdapter
import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.TextView;import csu.scrovor.cn.inote.R;/** * Created by lenovo on 2016/11/4. */public class ListAdapter extends ArrayAdapter<String> { private TextView textView; private int resource; private String[] objects; public ListAdapter(Context context, int resource, String[] objects) {//resource 为自定义Item layout的resId super(context, resource, objects); this.resource = resource; this.objects = objects; } @Override public View getView(int position, View convertView, ViewGroup parent) { String str = objects[position]; View v = LayoutInflater.from(getContext()).inflate(R.layout.listview_item_textview,null); textView = (TextView)v.findViewById(R.id.list_item); textView.setText(str); return v; }}
如果你有耐心看完以上的内容说明你真的是一个准备研究ui的人,虽然我的代码有很多冗余在以上。。
———————————————————————————————————————————————————
下面我们讨论下更通用的下拉布局实现。
在这里我只是有年份和月份,故直接写死,定格成这样,如果我们不止有2个呢?可能今天是3个明天4个呢?每次都重新写一个吗?
答案是否定的。
我们可以这样设计(预想中这样,没去实现呢):
drop 分为左右
左部:
LinearLayout(vertical).需要新的时,我动态往里面增加View,width match parent,height我们设置统一规格。
右部:
ListView就可以解决。根据左边不同的clicklistener,为listview适配不同的数据。这时我们在drop中添加一个flag来标记左边的哪个类别,并将此flag作为自定义Listener函数的参数回掉验证是哪个,再把相应的item设置到对应的下拉spinner中就可以解决了。
ps: 做过几次UI设计,发现listener真的是一个很奇妙的东西,感觉它像是一个“管道”一般,在另一端发生的事情,让你在这一端触手可及。又像是是一个函数作为参数传递一般,但函数能操作不同空间中的事务,有时间再专门说一下这个listener的理解吧。
- 实现简单的多选下拉"spinner"
- androin 中spinner下拉控件的简单实现
- 下拉控件Spinner的简单用法
- android实现多列显示的下拉列表框-Spinner
- android实现多列显示的下拉列表框-Spinner
- 安卓下拉菜单(Spinner)的实现
- 使用PopupWindow实现Spinner的下拉列表
- android实践项目一实现简单的验证码和spinner下拉选项效果
- Spinner(实现下拉列表)
- Spinner实现下拉框
- spinner实现下拉列表
- 简单的下拉多选angularjs 实现
- Spinner下拉菜单简单使用
- Android 之 下拉框(Spinner)的简单使用
- Android 之 下拉框(Spinner)的简单使用
- Android 之 下拉框(Spinner)的简单使用
- Android 之 下拉框(Spinner)的简单使用
- Spinner的简单功能和用法(下拉选项框)
- 【C语言】编译链接的详细过程
- Oracle速查语法:DDL(数据定义语言)
- 前端
- 栈的原理和缓冲区溢出原理
- 实用!开发者的 Vim 插件(二)
- 实现简单的多选下拉"spinner"
- sqlite3_column_blob()自己理解
- VBS深入CreateObject函数
- proc(1)
- windows的php环境下使用sendmai的smtp功能l的简单配置
- C语言数组作为函数参数
- 约瑟夫问题
- Hibernate延迟加载详解
- Ubuntu可以随便升级内核了