效果图如下:
为了增加按钮点击时的效果,此控件继承自 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;
}
}
}
两种模式统一实现同一个接口:
/**
* 两种 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:
/**
* 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:
/**
* 下拉 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,设置适配器方法如下:
public void setAdapter(ListAdapter adapter) {
this.mAdapter = adapter;
if (mPopup != null) {
mPopup.setAdapter(adapter);
}
setSelection(0);//默认选中第一个
}
根据位置选中数据,可作定位用:
/**
* 根据位置选中数据
*
* @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();
}
自定义属性定义了:1、两种模式的选择;2、选择文本显示的字体颜色
<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
最近在运营一个有关反脆弱成长的个人公众号,欢迎关注