ViewAndroid技术知识Android知识

Android自定义Spinner弹出选择器

2016-11-14  本文已影响3473人  番茄And鸡蛋

安卓中有Spinner这样一种控件,可以实现点击旁边的一个选择型的 > 来进行用户选择自己需要的属性,然后展示保存等等操作,在各种APP中都是非常常见的,但安卓自带的Spinner控件太过于死板,又难看。我们需要改风格,弹出动画,以及样式大小用安卓原生的Spinner是无法实现的。所以我简单介绍一下如何自定义Spinner,把它变成自己想要的样子。下面是一个简单的效果图,其中布局界面等等都可随意更改。

效果图.gif

实现原理
根据自己实际需求,写出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就完成了。

上一篇下一篇

猜你喜欢

热点阅读