安卓中有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就完成了。