自定義可顯示多行的 Spinner

效果圖以下:ide

    爲了增長按鈕點擊時的效果,此控件繼承自 LinearLayout,LinearLayout 中添加一個模樣相似於 Spniner 的 Button,在點擊 Button 的時候顯示數據。自定義變量以下:字體

/**
  *  Dialog 模式
  */
 public static final int MODE_DIALOG = 0;
 /**
  * dropdown 模式
  */
 public static final int MODE_DROPDOWN = 1;
 /**
  * 默認選擇 dropdown 模式
  */
 private static final int MODE_THEME = -1;
 private SpinnerPopup mPopup;// 兩種 Popup 模式實現的同一接口
 private Button mSpinnerButton;// 默認Button
 private ListAdapter mAdapter;
 private int mTextColor;// 字體顏色
 private int mSelectedItemPosition;// 選中的位置

初始化,根據資源文件設置顯示數據的模式:動畫

 /**
  * 初始化
  * @param context
  * @param mode 顯示數據的模式:下拉或者dialog
  */
 private void init(Context context, int mode) {
  this.setBackgroundResource(R.drawable.bg_textfield_default);// 設置背景
  /** 添加 Button */
  mSpinnerButton = new Button(context);
  mSpinnerButton.setBackgroundResource(R.drawable.selector_spinner);// 設置成下拉控件背景
  /** button只用一行顯示 */
  mSpinnerButton.setEllipsize(TruncateAt.END);
  mSpinnerButton.setMaxLines(1);
  mSpinnerButton.setTextColor(mTextColor);// 字體顏色
  LinearLayout.LayoutParams params = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
  this.addView(mSpinnerButton, params);
  mSpinnerButton.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    if(mPopup != null)
     mPopup.show();// 點擊 Button 顯示 Popup
   }
  });
  switch (mode) {
  case MODE_DIALOG: {//Dialog 模式
   mPopup = new DialogPopup();
   break;
  }
  case MODE_DROPDOWN: {//下拉模式
   mPopup = new DropdownPopup(context);
   break;
  }
  }
  
 }

兩種模式統一實現同一個接口:ui

 /**
  * 兩種 Popup 模式實現同一接口
  */
 public interface SpinnerPopup {
  public void setAdapter(ListAdapter adapter);
  /**
   * 顯示 popup
   */
  public void show();
  /**
   * 隱藏  popup
   */
  public void dismiss();
  /**
   * 
   * @return 若是 popup 已顯示,返回 true, 不然返回 false
   */
  public boolean isShowing();
  
  /**
   * 設置 Popup ListView 的樣式
   */
  public void setPopupListViewStyle(ListView listView);
  
 }

Dialog 模式實現的 Popup:this

 /**
  * Dialog Popup
 *@author liuyinjun
 
 * @date 2015-2-9
  */
 private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
  private AlertDialog mPopup;
  private ListAdapter mListAdapter;
  
  public void dismiss() {
   if(mPopup == null)
    return;
   mPopup.dismiss();
   mPopup = null;
  }
  public boolean isShowing() {
   return mPopup != null ? mPopup.isShowing() : false;
  }
  public void setAdapter(ListAdapter adapter) {
   this.mListAdapter = adapter;
  }
  public void show() {
   AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
   mPopup = builder.setSingleChoiceItems(mListAdapter, getSelectedItemPosition(), this).create();
   final ListView listView = mPopup.getListView();
   setPopupListViewStyle(listView);
   if(mPopup != null)
    mPopup.show();
  }
  @Override
  public void onClick(DialogInterface dialog, int which) {
   setSelection(which);
  }

  @Override
  public void setPopupListViewStyle(ListView listView) {
   if(listView == null)
    return;
   listView.setBackgroundResource(R.drawable.bg_spinner_white_shadow);
   listView.setCacheColorHint(Color.TRANSPARENT);
   listView.setDivider(getResources().getDrawable(R.drawable.list_view_divider_line));
   listView.setDividerHeight(1);
  }

 }

下拉模式實現的 Popup:.net

 /**
  * 下拉 Popup
 *@author liuyinjun
 
 * @date 2015-2-9
  */
 private class DropdownPopup extends PopupWindow implements SpinnerPopup {
  private ListView mListView;
  public DropdownPopup(Context context) {
   LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   View contentView = inflater.inflate(R.layout.spinner_shared_list, null);
   this.setContentView(contentView);
   this.setWidth(LayoutParams.FILL_PARENT);
   this.setHeight(LayoutParams.WRAP_CONTENT);
   this.setTouchable(true);
   this.setFocusable(true);
   this.setOutsideTouchable(true);
   this.setBackgroundDrawable(new BitmapDrawable());
   this.setAnimationStyle(R.style.SpinnerAnimation);// 設置進入進出動畫
   mListView = (ListView) contentView.findViewById(R.id.spinner_shared_listview);
   setPopupListViewStyle(mListView);
   // 下拉後點擊 item 事件
   mListView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
     setSelection(position);
    }
   });
  }
  @Override
  public void setAdapter(ListAdapter adapter) {
   if (mListView != null)
    mListView.setAdapter(adapter);
  }
  @Override
  public void show() {
   showAsDropDown(CustomSpinner.this, 0, 0);//顯示在當前控件之下
  }
  @Override
  public void setPopupListViewStyle(ListView listView) {
   if(listView == null)
    return;
   listView.setBackgroundResource(R.drawable.bg_spinner_white_shadow);
   listView.setCacheColorHint(Color.TRANSPARENT);
   listView.setDivider(getResources().getDrawable(R.drawable.list_view_divider_line));
   listView.setDividerHeight(1);
  }
 }

相似於 Spinner,設置適配器方法以下:code

 public void setAdapter(ListAdapter adapter) {
  this.mAdapter = adapter;
  if (mPopup != null) {
   mPopup.setAdapter(adapter);
  }
  setSelection(0);//默認選中第一個
 }

根據位置選中數據,可做定位用:orm

 /**
  * 根據位置選中數據
  * 
  * @param position
  */
 public void setSelection(int position) {
  if(mAdapter == null)
    throw new UnsupportedOperationException("請先設置適配器");
  this.mSelectedItemPosition = position;
  mSpinnerButton.setText(mAdapter.getItem(position).toString());// 設置Button顯示選中文本
  if (mPopup != null && mPopup.isShowing())
   mPopup.dismiss();
 }

自定義屬性定義了:一、兩種模式的選擇;二、選擇文本顯示的字體顏色繼承

<declare-styleable name="CustomSpinner">
        <attr name="spinnerMode">
            <enum name="dialog" value="0" />
            <enum name="dropdown" value="1" />
        </attr>
        <attr name="textColor" format="color" />
    </declare-styleable>

至此,關鍵代碼已貼出,關鍵是 PopupWindow 與 AlertDialog 的運用。此控件的用法很是相似於 Spinner,完整代碼請看自定義可顯示多行的 Spinner接口

最近在運營一個有關反脆弱成長的我的公衆號,歡迎關注

相關文章
相關標籤/搜索