一直想着多写几篇博客,一个为了提升自己,也是给需要的人提供帮助。可惜,项目太近,琐事太多,实在闲不下来,唉。不管怎样,还是想抽点时间出来完成这篇博客!
android 是自带有下拉框spinner控件的,但是android原生的Spinner控件是不支持用户输入的(据我所知),仅仅支持在数据列表确定的情况下进行选择。所以要实现一个手动输入的下拉框,我们需要自己手动实现。
在这里要感谢该博客给的灵感:https://blog.csdn.net/u013700040/article/details/52914070
大致思想是这样:通过一个EditText和一个ImageView的组合来实现控件,然后采用popupWindow进行界面弹出。
PopupWindow不了解的可以先去了解一下,这里不做深究,PopupWindow和AlertDialog相似,都是android用于与用户交互的对话框界面。
/*
* @ Description:
* @ Time: 2019/5/18 18:40:24
* @ Author: lgy
*/
public class SpinnerPopupWindow<T> extends PopupWindow {
private List<T> datas;//listview数据
private NormalAdapter adapter;
private LayoutInflater inflater;
private ListView mListView;
private Context mContext; // 上下文参参数
public SpinnerPopupWindow(Context context, List<T> datas, AdapterView.OnItemClickListener clickListener){
super(context);
mContext=context;
inflater = LayoutInflater.from(context);
this.datas = datas;
init(clickListener);
}
private void init(AdapterView.OnItemClickListener clickListener){
View view = inflater.inflate(R.layout.spinner_window_layout, null);
setContentView(view);
setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
setFocusable(true);
ColorDrawable dw = new ColorDrawable(0x00);
setBackgroundDrawable(dw);
mListView = (ListView) view.findViewById(R.id.popup_listview);
mListView.setAdapter(adapter = new NormalAdapter(mContext,datas,R.layout.spinner_popup_item));
mListView.setOnItemClickListener(clickListener);
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/popup_listview"
android:scrollbars="none"
android:background="@drawable/round_edge_radius_tv_bl"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
LinearLayout>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffff" />
<stroke
android:width="1dp"
android:color="#30000000" />
<corners android:radius="5dp" />
shape>
/*
* @ Description:
* @ Time: 2019/5/21 17:00:22
* @ Author: lgy
*/
public class NormalAdapter<T> extends BaseAdapter {
protected Context context;
private List<T> datas;
protected LayoutInflater inflater;
protected int layoutId;
public NormalAdapter(Context context, List<T> datas, int layoutId) {
this.context = context;
this.datas = datas;
inflater = LayoutInflater.from(context);//关联布局
this.layoutId = layoutId;
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.spinner_popup_item,null);
viewHolder.textTv = (TextView) convertView.findViewById(R.id.tv_item);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.textTv.setText(getItem(position).toString());
return convertView;
}
private class ViewHolder{
private TextView textTv;
}
}
到这里,PopupWindow的实现大致就结束了。popupWindow主要是定义了一个弹出界面,也就是一个ListView。
/*
* @ Description:通用下拉框工具类
* @ Time: 2019/5/19 13:36:43
* @ Author: lgy
*/
public class CommonSpinner<T> extends RelativeLayout {
private Context context;//上下文
private List<T> datas;//下拉菜单数据集
private View Spinner;
private SpinnerPopupWindow<T> popupWindow;
private RelativeLayout rl_text;
private EditText et_text;
private ImageView iv_text;
private String showTitle;
private String showText;
//接口,消息响应
private Spinner_ClickListener spinner_ClickListener;
//用于显示popupWindow
private View.OnClickListener clickListener= new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.common_iv:
popupWindow.setWidth(rl_text.getWidth());
popupWindow.showAsDropDown(rl_text);
// setTextImage(R.mipmap.arrow_down_bl);
break;
}
}
};
//用于popupWindow中ListView的子项点击事件
private AdapterView.OnItemClickListener itemClickListener=new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
popupWindow.dismiss();
et_text.setText(datas.get(position).toString());
showText = datas.get(position).toString();
//这个接口是用来在其他界面做点击操作的时候负责调用的
if(spinner_ClickListener != null){
spinner_ClickListener.ClickListener(datas.get(position).toString());
}
}
};
public CommonSpinner(Context context, String showTitle, List<T> datas) {
super(context);
this.context=context;
this.showTitle = showTitle;
this.datas=datas;
init();
}
//设置接口
public void setSpinner_ClickListener(Spinner_ClickListener spinner_ClickListener){
this.spinner_ClickListener = spinner_ClickListener;
}
private void init() {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Spinner = inflater.inflate(R.layout.common_spinner_layout, this);
rl_text=(RelativeLayout)Spinner.findViewById(R.id.common_rl);
et_text = (EditText) Spinner.findViewById(R.id.common_et);
iv_text=(ImageView) Spinner.findViewById(R.id.common_iv);
et_text.setText(showTitle);
//设置TextView点击事件
iv_text.setOnClickListener(clickListener);
//初始化popupWindow
popupWindow = new SpinnerPopupWindow<>(getContext(), datas, itemClickListener);
popupWindow.setOnDismissListener(dismissListener);
}
/**
* 监听popupwindow取消
*/
private PopupWindow.OnDismissListener dismissListener = new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
// setTextImage(R.mipmap.spinner_up);
}
};
/**
* 给TextView右边设置图片
* @param resId
*/
private void setTextImage(int resId) {
Drawable drawable = getResources().getDrawable(resId);
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());// 必须设置图片大小,否则不显示
et_text.setCompoundDrawables(null, null, drawable, null);
}
//用于外部获取TextView中的值
public String getText(){
return et_text.getText().toString().trim();
}
/**
* @Description: 在外部获取Spinner界面上的EditText
* @Author:lgy
* @Date:2019/5/20 15:22
*/
public EditText getEditView(){
return et_text;
}
}
说明:定义一个Spinner工具类,继承自RelativeLayout,加载一个布局xml文件即可,文件命名为:common_spinner_layout(仅包含一个EditText和ImageView)。在下拉框工具类中,构造函数传入一个
①View.OnClickListener:控件的点击响应,用在ImageView上弹出PopupWindow。
②AdapterView.OnItemClickListener:ListView的子项点击响应函数,当点击ListView上的子项时,将数据显示到EditText上。
请重点考虑一下这行代码:
Spinner = inflater.inflate(R.layout.common_spinner_layout, this);
这句话的作用是将定义的界面布局加载到定义了工具类(RelativeLayout)上。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/common_rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/round_edge_radius_tv_bl">
<EditText
android:id="@+id/common_et"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/dp_2"
android:background="@color/purewhite"
android:text="下拉框"
android:textSize="12sp"/>
<ImageView
android:id="@+id/common_iv"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:paddingTop="@dimen/dp_10"
android:paddingBottom="@dimen/dp_10"
android:paddingLeft="@dimen/dp_10"
android:paddingRight="@dimen/dp_5"
android:src="@mipmap/arrow_down_bl"/>
RelativeLayout>
界面只包含一个EditText和右边的一个ImageView,ImageView加载图片为下箭头,代表下拉框标志。
图片资源:arrow_down_bl(可以自己去Iconfont上找矢量图,然后引用即可)
到这里,Spinner工具类也封装完成,那么下面该到Activity里面来引用这个工具类了。
在activity里定义一个布局,这里我采用的是LinearLayout线性布局,代码如下:
这里只定义一个线性布局,通过这个布局来加载我们写好的工具类CommonSpinner。
<LinearLayout
android:id="@+id/geology_age"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:layout_marginLeft="@dimen/dp_5"
android:layout_marginRight="@dimen/dp_20"
android:layout_gravity="center_vertical"
android:gravity="center"
android:textSize="12sp"
android:background="@drawable/round_edge_radius_tv_bl"
android:orientation="horizontal">
LinearLayout>
活动代码:
List<String> data_list;
String[] strings=getResources().getStringArray(R.array.geology_factor);
data_list= Arrays.asList(strings);
spinner_factor=new CommonSpinner<>(GeotechnicalDescription.this,"请选择",data_list);
spinner_factor.setSpinner_ClickListener(new Spinner_ClickListener() {
@Override
public void ClickListener(String data) {
if(data.equals(getResources().getString(R.string.DIY))){
spinner_factor.getEditView().setText("");
EditText et=spinner_factor.getEditView();
et.setFocusable(true);
et.setFocusableInTouchMode(true);
InputMethodManager inputManager =(InputMethodManager)et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if(inputManager!=null) {
et.requestFocus();
inputManager.showSoftInput(et, 0);
}
}
}
});
下拉框中的数据是已经在string.xml文件中定义好的:如
<string name="DIY">"自定义"string>
<string-array name="geology_factor">
<item>alitem>
<item>al+plitem>
<item>hitem>
<item>自定义item>
string-array>
这里根据自己的需要定义即可。
到这里整个下拉框工具类的封装就完成了,一个很简单的demo。相信android初学者都能看懂,毕竟笔者也才是android入门级的。
好吧,到这里这篇博客的内容大致就写完了。我一直觉得写博客的目的一个是为了分享知识,给需要的人提供帮助,但是最主要的应该还是自己对知识的巩固吧。网上这方面的知识太多,因为笔者也是参照了先者的成果,然后根据自己的需求进行改造。希望对看到这篇博客的你能提供你所需要的帮助,那也达到了我写博客的目的。如果有什么错误或者纰漏,或者不懂的地方,欢迎留言交流。
一起学习,一起成长。
---------------------------------------------------------------------分割线------------------------------------------------------------------------------------------忘记说了,在CommonSpinner类中用到了一个接口 【 private Spinner_ClickListener spinner_ClickListener;】,这个接口用来将用户在下拉框中选中的数据显示在输入框中。
新定义一个接口
public interface Spinner_ClickListener {
public void ClickListener(String data);
其中ClickListener为接口函数,负责将下拉框的数据显示在输入框中。
然后在CommonSpinner类中引入该接口即可。