自定义控件 - Spinner

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

效果图

自定义控件 - Spinner_第1张图片
Spinner.gif

默认item 布局文件item_choose_time

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




Spinner工具类

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

/**
 * Spinner工具类
 * 

* 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 extends RecyclerView.Adapter {
    private static OnItemClickListener onItemClickListener;

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

        void onItemLongClick(View view, int position);
    }

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

    protected Context context;
    protected List datas;
    protected int layoutID;

    public BaseSpinnerAdapter(Context context, List 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 getData();
}

一个示例SpinnerAdapterSpinnerChooseAdapter

实现效果图的Adapter

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

public class SpinnerChooseAdapter extends BaseSpinnerAdapter {
    private List mData;

    public SpinnerChooseAdapter(Context context, List 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 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 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 {
    private List mData;

    public SpinnerUserChooseAdapter(Context context, List 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 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 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


    
    
    
    

  • popupWindow使用的Recyclerview


自定义控件 - Spinner_第2张图片
Spinner.gif

你可能感兴趣的:(自定义控件 - Spinner)