美文网首页
自定义控件 - Spinner

自定义控件 - Spinner

作者: 沐左 | 来源:发表于2018-07-24 10:48 被阅读0次

blog 中会记录一些自定义控件的实现过程,完整的使用和其他的自定义控件可以参考,常用控件库WidgetProductor整理

效果图

Spinner.gif

默认item 布局文件item_choose_time

默认的item布局只有一个TextView,不过用户可以通过实现实现BaseSpinnerAdapter 传入自定义的布局。

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/choose_item"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:padding="10dp"
    android:textColor="@color/colorBlack"
    android:textSize="14sp" />

Spinner工具类

Spinner工具类接收上下文、一个TextView,一个BaseSpinnerAdapter的实现类;
如果不想使用系统的箭头图标,可以使用方法setArrows()设置。

/**
 * Spinner工具类
 * <p>
 * author: zuo
 * date: 2017/11/29 15:05
 */

public class SpinnerUtils {
    private Context mContext;
    private TextView mTextView;
    private BaseSpinnerAdapter mAdapter;
    private PopupWindow popupWindow;
    private boolean noData;
    @DrawableRes
    private int mArrowDown = R.drawable.arrow_down;
    @DrawableRes
    private int mArrowUp = R.drawable.arrow_top;

    public SpinnerUtils(Context context, TextView textView, @NonNull BaseSpinnerAdapter adapter) {
        this.mContext = context;
        this.mTextView = textView;
        this.mAdapter = adapter;
    }

    /**
     * 设置箭头,如果不想使用系统的箭头图标,可以在这个方法中设置
     * 需要注意的时,这个方法需要在初始化方法init()之前调用
     * @param arrowDown
     * @param arrowUp
     */
    public void setArrows(@DrawableRes int arrowDown, @DrawableRes int arrowUp) {
        this.mArrowDown = arrowDown;
        this.mArrowUp = arrowUp;
    }

    public void init() {
        if (mAdapter != null && mAdapter.getData() != null && mAdapter.getData().size() > 0) {
            mTextView.setText("----请选择---");
            tvSetImg(mTextView, mArrowDown);
            noData = false;
        } else {
            mTextView.setText("----无数据---");
            noData = true;
        }
        mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (noData) {
                    Toast.makeText(mContext, "无数据!", Toast.LENGTH_SHORT).show();
                    return;
                }
                showPopupWindow();
            }
        });
    }

    private void showPopupWindow() {
        tvSetImg(mTextView, mArrowUp);
        View view = LayoutInflater.from(mContext).inflate(R.layout.choose_pop_rv, null);
        popupWindow = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        popupWindow.setTouchable(true);
        popupWindow.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.shape_popup_view));
        popupWindow.showAsDropDown(mTextView);
        popupWindow.setOnDismissListener(new PopupDismissListener());
        RecyclerView recyclerView = view.findViewById(R.id.rv_choose_pop);
        recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
        recyclerView.setAdapter(mAdapter);
        recyclerView.addItemDecoration(new DividerItemDecoration(mContext, DividerItemDecoration.VERTICAL));
    }

    /**
     * 关闭popupWindow
     */
    public void closeSpinner() {
        if (popupWindow != null) {
            popupWindow.dismiss();
        }
    }

    /**
     * 弹窗消失的时候让箭头换回来
     */
    class PopupDismissListener implements PopupWindow.OnDismissListener {
        @Override
        public void onDismiss() {
            tvSetImg(mTextView, mArrowDown);
        }

    }

    /**
     * 设置textView右侧的图像
     *
     * @param textView
     * @param img
     */
    private void tvSetImg(TextView textView, int img) {
        Drawable nav_up = mContext.getResources().getDrawable(img);
        nav_up.setBounds(0, 0, nav_up.getMinimumWidth(), nav_up.getMinimumHeight());
        textView.setCompoundDrawables(null, null, nav_up, null);
    }

}

Spinner基础AdapterBaseSpinnerAdapter

BaseSpinnerAdapter基础的SpinnerAdapte,用户使用Spinner想自定义Adapter时需要继承这个类。

/**
 * 封装一个基础的SpinnerAdapter,便于外界调用时进行扩展
 *
 * @author zuo
 * @date 2018/7/23 15:24
 */
public abstract class BaseSpinnerAdapter<T extends RecyclerView.ViewHolder, E> extends RecyclerView.Adapter<T> {
    private static OnItemClickListener onItemClickListener;

    public static interface OnItemClickListener<E> {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        onItemClickListener = listener;
    }

    protected Context context;
    protected List<E> datas;
    protected int layoutID;

    public BaseSpinnerAdapter(Context context, List<E> datas, int layoutID) {
        this.context = context;
        this.datas = datas;
        this.layoutID = layoutID;
    }

    @NonNull
    @Override
    public T onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = View.inflate(context, layoutID, null);
        return getViewHolder(itemView);
    }

    @Override
    public int getItemCount() {
        return datas == null ? 0 : datas.size();
    }

    @Override
    public void onBindViewHolder(final T holder, final int position) {
        setValues(holder, position);
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (onItemClickListener != null) {
                    onItemClickListener.onItemClick(holder.itemView, position);
                }
            }
        });

        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (onItemClickListener != null) {
                    onItemClickListener.onItemLongClick(holder.itemView, position);
                }
                return true;
            }
        });
    }

    /**
     * 返回viewholder
     *
     * @param itemView
     * @return
     */
    protected abstract T getViewHolder(View itemView);

    /**
     * 设置控件数据
     *
     * @param holder
     * @param position
     */
    protected abstract void setValues(T holder, int position);

    /**
     * 获取Spinner展示的数据
     */
    protected abstract List<E> getData();
}

一个示例SpinnerAdapterSpinnerChooseAdapter

实现效果图的Adapter

/**
 * 展示String类型数据的SpinnerAdapter
 *
 * @author zuo
 * @date 2017/11/23 15:25
 */

public class SpinnerChooseAdapter extends BaseSpinnerAdapter<RecyclerView.ViewHolder, String> {
    private List<String> mData;

    public SpinnerChooseAdapter(Context context, List<String> list, OnItemClickListener itemClickListener) {
        super(context, list, R.layout.item_choose_time);
        this.mData = list;
        setOnItemClickListener(itemClickListener);
    }

    @Override
    protected RecyclerView.ViewHolder getViewHolder(View itemView) {
        itemView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));
        return new ItemViewHolder(itemView);
    }

    @Override
    protected void setValues(RecyclerView.ViewHolder holder, int position) {
        ((ItemViewHolder) holder).textView.setText(mData.get(position));
    }

    @Override
    protected List<String> getData() {
        return mData;
    }


    public class ItemViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public ItemViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.choose_item);
        }
    }
}

控件使用

SpinnerActivity中的使用代码

public class SpinnerActivity extends AppCompatActivity implements BaseSpinnerAdapter.OnItemClickListener {
    private List<String> list = new ArrayList<>();
    private TextView textView;
    private SpinnerUtils spinnerUtils;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_spinner);
        initData();
        initView();
    }

    private void initView() {
        textView = findViewById(R.id.show_spinner);
        SpinnerChooseAdapter chooseAdapter = new SpinnerChooseAdapter(this, list, this);
        spinnerUtils = new SpinnerUtils(this, textView, chooseAdapter);
        spinnerUtils.init();
    }

    private void initData() {
        list.add("战争女神");
        list.add("蒙多");
        list.add("德玛西亚皇子");
        list.add("殇之木乃伊");
        list.add("狂战士");
        list.add("布里茨克拉克");
        list.add("冰晶凤凰 艾尼维亚");
        list.add("德邦总管");
        list.add("野兽之灵 乌迪尔 (德鲁伊)");
        list.add("赛恩");
        list.add("诡术妖姬");
        list.add("永恒梦魇");
    }

    @Override
    public void onItemClick(View view, int position) {
        Toast.makeText(this, "点击" + list.get(position), Toast.LENGTH_SHORT).show();
        textView.setText(list.get(position));
        if (spinnerUtils != null) {
            spinnerUtils.closeSpinner();
        }
    }

    @Override
    public void onItemLongClick(View view, int position) {
        Toast.makeText(this, "长按" + list.get(position), Toast.LENGTH_SHORT).show();
        textView.setText(list.get(position));
        if (spinnerUtils != null) {
            spinnerUtils.closeSpinner();
        }
    }

}

自定义的Adapter

假定我们需要展示UserBean类型的数据(其他实体类亦可),我们就需要自定义一个adapter,同样需要继承BaseSpinnerAdapter。

/**
 * 展示UserBean类型数据的SpinnerAdapter
 *
 * @author zuo
 * @date 2017/11/23 15:25
 */

public class SpinnerUserChooseAdapter extends BaseSpinnerAdapter<RecyclerView.ViewHolder, SpinnerActivity.UserBean> {
    private List<SpinnerActivity.UserBean> mData;

    public SpinnerUserChooseAdapter(Context context, List<SpinnerActivity.UserBean> list, OnItemClickListener itemClickListener) {
        super(context, list, R.layout.item_choose_time);
        this.mData = list;
        setOnItemClickListener(itemClickListener);
    }

    @Override
    protected RecyclerView.ViewHolder getViewHolder(View itemView) {
        itemView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));
        return new ItemViewHolder(itemView);
    }

    @Override
    protected void setValues(RecyclerView.ViewHolder holder, int position) {
        ((ItemViewHolder) holder).textView.setText(mData.get(position).getName());
    }

    @Override
    protected List<SpinnerActivity.UserBean> getData() {
        return mData;
    }


    public class ItemViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public ItemViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.choose_item);
        }
    }
}

控件使用

public class SpinnerActivity extends AppCompatActivity implements BaseSpinnerAdapter.OnItemClickListener {
    private List<UserBean> list = new ArrayList<>();
    private TextView textView;
    private SpinnerUtils spinnerUtils;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_spinner);
        initData();
        initView();
    }

    private void initView() {
        textView = findViewById(R.id.show_spinner);
        SpinnerUserChooseAdapter chooseAdapter = new SpinnerUserChooseAdapter(this, list, this);
        spinnerUtils = new SpinnerUtils(this, textView, chooseAdapter);
        spinnerUtils.setArrows(R.drawable.arrow_down_app,R.drawable.arrow_up_app);
        spinnerUtils.init();
    }

    private void initData() {
        list.add(new UserBean(1,"战争女神"));
        list.add(new UserBean(2,"蒙多"));
        list.add(new UserBean(3,"德玛西亚皇子"));
        list.add(new UserBean(4,"殇之木乃伊"));
        list.add(new UserBean(5,"狂战士"));
        list.add(new UserBean(6,"布里茨克拉克"));
        list.add(new UserBean(7,"冰晶凤凰 艾尼维亚"));
        list.add(new UserBean(8,"德邦总管"));
        list.add(new UserBean(9,"野兽之灵 乌迪尔 (德鲁伊)"));
        list.add(new UserBean(10,"赛恩"));
        list.add(new UserBean(11,"诡术妖姬"));
        list.add(new UserBean(12,"永恒梦魇"));
    }

    @Override
    public void onItemClick(View view, int position) {
        Toast.makeText(this, "点击" + list.get(position).getName(), Toast.LENGTH_SHORT).show();
        textView.setText(list.get(position).getName());
        if (spinnerUtils != null) {
            spinnerUtils.closeSpinner();
        }
    }

    @Override
    public void onItemLongClick(View view, int position) {
        Toast.makeText(this, "长按" + list.get(position).getName(), Toast.LENGTH_SHORT).show();
        textView.setText(list.get(position).getName());
        if (spinnerUtils != null) {
            spinnerUtils.closeSpinner();
        }
    }

    public class UserBean{
        private int id;
        private String name;

        public UserBean(int id, String name) {
            this.id = id;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

其他代码

  • popupWindow 的背景 shape
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorWhite" />
    <corners android:radius="2dp" />
    <padding android:bottom="5dp" android:left="10dp" android:right="10dp" android:top="5dp"/>
    <stroke android:color="@color/font_common_2" android:width="1dp"/>
</shape>
  • popupWindow使用的Recyclerview
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rv_choose_pop"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorWhite"/>
Spinner.gif

相关文章

网友评论

      本文标题:自定义控件 - Spinner

      本文链接:https://www.haomeiwen.com/subject/axqjmftx.html