4/15/2015

[Android] 做自己的Spinner (1)

Spinner簡單來說是Android提供的下拉式選單元件
因為drop-down的功能基本上提供於 Android 3.0以上的平台
因此Spinner也必須是在3.0以上的平台才能直接使用
                                              
這篇之所以會產生是因為當初開發的平台不到 3.0
又需要下拉式選單的功能, 也不考慮使用一些知名library如 ActionBarSherlock
因此只好自行觀察原理, 然後刻一個

依照本篇的作法, 可以做出像是Android Spinner的元件跟擴充型Spinner
製作spinner首先需要三個檔案

Spinner.java //Spinner object 本身
spinner_title_layout.xml
spinner_item_layout.xml

Spinner.java 本身控制 Spinner 的主體
也就是上圖裡藍藍的 top object, 對應到的 layout 就是 spinner_title_layout.xml
碰觸主體後可以展開/收起下拉式選單, 選單的 layout 是 sppiner_item_layout.xml
再透過ListView實作
從這裡可以看出, 將主體跟選單的畫面分開做就是為什麼可以做擴充型 Spinner 的原因, 丙且, 選擇的結果可以在主體作相對應的變化
因此主體本身也是一個View, View本身包含需要的Listener還有一些基本功能
基於個人喜好, 我使用RelativeLayout去做設置
簡單來說長成這樣

public class ListSpinner extends RelativeLayout
{
  public enum SpinnerType
  {
    STRING_SPINNER,
    RADIO_TOGGLE_SPINNER //with toggle button + single selection
  }


  private class ListAdapter extends ArrayAdapter
  {
    String[] list;
    int mHolderViewId;
    int mLayoutResource;
    
    SpinnerType mSpinnerType;
    
    @SuppressWarnings("unchecked")
    public ListAdapter(Context context, int resource, String[] list, SpinnerType type)
    {
      super(context, resource, list);
      this.list = list;
      this.mLayoutResource = resource;
      this.mSpinnerType = type;
      this.mHolderViewId = getResourceIDByName(mActivity, ResourceType.Id,"dropdownTxt");
      getListButtonByType(type);
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
      View row = convertView;
      
      if (row == null)
      {
        LayoutInflater inflater = mActivity.getLayoutInflater();
        row = inflater.inflate(mLayoutResource, parent, false);
      }
      String desList = list[position];
      updateListBackground(row, position);
      
      RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(400, LayoutParams.MATCH_PARENT);
      rlp.setMargins(10, 0, 0, 0);
      
      TextView name = (TextView) row.findViewById(mHolderViewId);
      name.setLayoutParams(rlp);
      name.setText(desList);
      name.setTag(desList);
      
      updateListTriggerByType(row, this.mSpinnerType, desList);      
      
      return row;
    }    
  }

  public ListSpinner(Context context, AttributeSet attrs)
  {
    super(context, attrs);
    mActivity = null;
    mContext = context;    
    
    mSpinnerTitle = DynamicViewUtil.getViewById(this, "spinnerTitle");    
    
    mIsExpanding = false;
  }
}

首先定義之後可以使用的Type
並且完成下拉式選單用的Adapter
為了讓使用這個元件可以更快速地加入每個選項的文字, 我選擇ArrayAdapter
然後做出簡單的建構子

考慮到在實用上, 不同的spinner會需要有不同的 top column 和 item
因此需要再加入兩個函數:setTitlesetItems

public void setTitle(final Activity activity, String titleLayout, String title)
{
  mActivity = activity;
  
  int id = getResourceIDByName(mActivity, ResourceType.Layout, titleLayout);
  View view = inflate(mContext, id, null);
  addView(view);
  
  ListSpinner.LayoutParams llp = new ListSpinner.LayoutParams(400, LayoutParams.MATCH_PARENT);
  llp.setMargins(10, 0, 0, 0);
  
  mSpinnerTitle = getViewById(this, "spinnerTitle");
  mSpinnerTitle.setLayoutParams(llp);
  mSpinnerTitle.setText(title);
  
  mSpinnerList = new ListView(mContext);    
}

/**
 *  set up your spinner row content with provided listItems, layout, and pointed spinner type.
 * @param listItem The String list for spinner row item.
 * @param layoutResource Layout for spinner itself.
 * @param type Spinner presenting style.
 * */
public void setItems(String[] listItems, int layoutResource, SpinnerType type)
{
  mListAdapter = new ListAdapter(mContext, layoutResource, listItems, type);
  mSpinnerList.setAdapter(mListAdapter);        
}

可以看到我在 setTitle 的地方才去實作下拉式選單 mSpinnerList
在 setItem 的時候, 就能產生不同類型的 spinner

基本上Spinner的主體大約就是長這樣
當然我刪掉了很多不需要講解的source 因此看起來有些缺東缺西
接下來會繼續補上 Spinner其他的函式成員, 作為Listener的Interface, 兩個Spinner Layout簡單Demo最後的使用方法

沒有留言:

張貼留言