安卓中有Spinner这样一种控件,可以实现点击旁边的一个选择型的 > 来进行用户选择自己需要的属性,然后展示保存等等操作,在各种APP中都是非常常见的,但安卓自带的Spinner控件太过于死板,又难看。我们需要改风格,弹出动画,以及样式大小用安卓原生的Spinner是无法实现的。所以我简单介绍一下如何自定义Spinner,把它变成自己想要的样子。下面是一个简单的效果图,其中布局界面等等都可随意更改。
实现原理
根据自己实际需求,写出Spinner在界面展示的布局,一般情况下都有一个TextView的文字展示选择后的元素,旁边有个可点击的按钮,点击后利用PopupWindow弹窗,弹出一条ListView的列表,以供用户选择,点击Item后再返回给TextView显示。我这里演示最简单的一种布局实现原理。
1.定义好所需要的布局##
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:id="@+id/spinnerid"
android:orientation="horizontal">
<TextView
android:id="@+id/text_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2016年6月" />
<ImageView
android:id="@+id/image_spinner"
android:src="@mipmap/spinner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
上面是自定义Spinner的Xml布局代码,就两个基本的TextView和ImageView,可以根据需要添加更多随意选择样式图片,用于界面展示效果。
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<ListView
android:background="@color/material_white"
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="@null"
android:dividerHeight="1px">
</ListView>
</LinearLayout>
这里设置PopupWindow弹窗的布局,我采用的是ListView,用于演示简单的Item选择,下面是List里面的Item,也是非常简单的布局。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/material_white"
android:orientation="vertical">
<TextView
android:id="@+id/date_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
</LinearLayout>
2.配置ListView的Adapter##
public class MySpinnerAdapter extends BaseAdapter {
LayoutInflater inflater;
Context context;
ArrayList<String> list;
public MySpinnerAdapter(Context context, ArrayList<String> list) {
super();
this.context = context;
this.list = list;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position); }
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position; }
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_daka_spinner, null);
viewHolder = new ViewHolder();
viewHolder.textView = (TextView) convertView.findViewById(R.id.date_text);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.textView.setText(list.get(position));
return convertView;
}
public class ViewHolder {
TextView textView;
}
public void refresh(List<String> l) {
this.list.clear();
list.addAll(l);
notifyDataSetChanged();
}
public void add(String str) {
list.add(str);
notifyDataSetChanged();
}
public void add(ArrayList<String> str) {
list.addAll(str);
notifyDataSetChanged();
}
}
简单的使用BaseAdapter ,然后设置了构造函数,用于传入数据,并展示在View中。
3.自定义Spinner类##
直接继承LinearLayout,定义好构造函数,找到之前为Spinner定义好的布局以及子View。
public class SpinnerView extends LinearLayout{
private Context context;
private LinearLayout layout;
private ListView listView;
private MySpinnerAdapter adapter;
private PopupWindow popupWindow;
private TextView mSpinnerText;
private ImageView mSpinnerImag;
private ArrayList<String> listData = new ArrayList<>();
public SpinnerView(Context context) {
super(context);
this.context = context;
}
public SpinnerView(final Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.include_my_spinnerview,this);
mSpinnerText = (TextView)findViewById(R.id.text_spinner);
mSpinnerImag = (ImageView)findViewById(R.id.image_spinner);
}
public SpinnerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
}
然后对外开放一个方法,用于传入数据给Adapter ,初始化适配器数据,构造方法根据自己需求定义,我这里用的最简单的List容器。当数据接收到后,初始化控件属性,设置监听。
public void setMyData(ArrayList<String> data){
this.listData = data;
adapter = new MySpinnerAdapter(context, listData); // 默认设置下拉框的标题为数据的第一个
mSpinnerText.setText((CharSequence) adapter.getItem(0)); // 点击右侧按钮,弹出下拉框
mSpinnerImag.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showWindow(v);
}
});
}
然后设置PopupWindow的弹框:
public void showWindow(View v) {
// 找到布局文件
layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.mypinner_dropdown, null);
// 实例化listView
listView = (ListView) layout.findViewById(R.id.listView);
// 设置listView的适配器
listView.setAdapter(adapter);
// 实例化一个PopuWindow对象
popupWindow = new PopupWindow(v);
// 设置弹框的宽度为布局文件的宽
popupWindow.setWidth(getWidth());
// 高度设置的300
popupWindow.setHeight(300);
// 设置一个透明的背景,不然无法实现点击弹框外,弹框消失
popupWindow.setBackgroundDrawable(new BitmapDrawable());
// 设置点击弹框外部,弹框消失
popupWindow.setOutsideTouchable(true);
// 设置焦点
popupWindow.setFocusable(true);
// 设置所在布局
popupWindow.setContentView(layout);
// 设置弹框出现的位置,在v的正下方横轴偏移textview的宽度
popupWindow.showAsDropDown(v, -mSpinnerText.getWidth(), 0);
// listView的item点击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
mSpinnerText.setText(listData.get(arg2));// 设置所选的item作为下拉框的标题
// 弹框消失
popupWindow.dismiss();
popupWindow = null;
}
});
}
弹窗的样式,以及大小宽高等,直接可以设置,想要酷炫一点就加入动画,这里只列出部分属性。需要知道更多的去查popupWindow的API。
4.引入##
在XML中直接使用布局即可
<com.customview.MySpinner.SpinnerView
android:id="@+id/spinnerid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#fff"/>
在代码中,记得添加数据。自己也可以拿到选中的属性
mySpinner = (SpinnerView) findViewById(R.id.spinnerid);
persons = new ArrayList<String>();
for (int i = 16; i <= 20; i++) {
for (int r = 1; r <= 12; r++) {
persons.add("20" + i + "年" + r + "月");
}
}
mySpinner.setMyData(persons);
一个自定义的Spinner就完成了。