效果图以下: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接口
最近在运营一个有关反脆弱成长的我的公众号,欢迎关注