自定义可显示多行的 Spinner
自定义可显示多行的 Spinner
人生如歌 发表于3年前
自定义可显示多行的 Spinner
  • 发表于 3年前
  • 阅读 398
  • 收藏 11
  • 点赞 0
  • 评论 0
摘要: Android 的控件 Spinner 有一个很大的bug,就是假如数据超过一行不能显示完整,在网上搜索了很多种方法都不能解决这个问题,无奈之下只能自己写一个可以显示多行的 Spinner。查看 Spinner 的源码,发现它用了下拉与对话框两种模式,所以这里也用这两种模式实现。

效果图如下:

    为了增加按钮点击时的效果,此控件继承自 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

最近在运营一个有关反脆弱成长的个人公众号,欢迎关注

共有 人打赏支持
粉丝 8
博文 15
码字总数 7993
×
人生如歌
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: