效果圖以下: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接口
最近在運營一個有關反脆弱成長的我的公衆號,歡迎關注