Android自定義Spinner彈出選擇器

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容