一步步自定义下拉组件spinner

简介: spinner就是下拉选择组件,系统自带的spinner使用起来非常方便,首先定义一个array(strings.xml),如下:<array name="grade"> <item>一年级</item> <item>二年级</item> <item>三年级</item> <item>四年级</item> <item>五年级</item> <item>六年级</item></array>复制代码

前言


spinner就是下拉选择组件,系统自带的spinner使用起来非常方便,首先定义一个array(strings.xml),如下:


<array name="grade">
    <item>一年级</item>
    <item>二年级</item>
    <item>三年级</item>
    <item>四年级</item>
    <item>五年级</item>
    <item>六年级</item>
</array>
复制代码


代码如下:


Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.grade, android.R.layout.simple_spinner_item);
spinner.setAdapter(adapter);
复制代码


这样就实现了一个简单的spinner,显示如下:


网络异常,图片无法展示
|


但这并不是我想要的样式和效果,下面我们就一点点的来改造它。


(1)改变初始布局


即弹窗前的样式,先自定义一个布局,如下:

spinner_layout.xml


<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"
    android:textColor="#6d6d6d"
    android:textSize="15sp"
    android:drawableRight="@drawable/arrow"
    android:drawablePadding="5dp"
    tools:text="一年级">
</TextView>
复制代码


然后替换createFromResource中的即可,如下:


ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.grade, R.layout.spinner_layout);
复制代码


这样还不够,因为还有一个带箭头的背景,将背景设置为透明即可,如下:


spinner.setBackgroundColor(0x0);
复制代码


这样初始布局的展示就与spinner_layout一样了。


(2)改变列表item布局


经过上面的修改后,发现弹窗中列表item的布局也变成了spinner_layout,查看ArrayAdapter的构造函数可知有mResource和mDropDownResource两个变量,其中mResource就是初始布局,而mDropDownResource则是列表item的布局。

而createFromResource函数中,mResource和mDropDownResource赋值相同。但是ArrayAdapter还有一个setDropDownViewResource函数。

首先定义一个布局,如下:


spinner_item.xml


<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"
    android:textColor="#6d6d6d"
    android:textSize="15sp"
    android:padding="8dp"
    android:gravity="center_horizontal"
    tools:text="一年级">
</TextView>
复制代码


然后使用setDropDownViewResource函数即可,如下:


adapter.setDropDownViewResource(R.layout.spinner_item);
复制代码


(3)改变弹窗背景及位置


在开始的动画中可以看到弹窗会遮挡住,我们想让弹窗处于下方,同时弹窗是圆角带箭头的。

这就需要使用spinner的两个函数setPopupBackgroundResource和setDropDownVerticalOffset。

但是注意这两个函数都需要在android4.1版本及以上,鉴于目前4.1以下版本已经很少了,所以我们只考虑4.1以上即可,代码如下:


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    spinner.setPopupBackgroundResource(R.drawable.bg_spinner);
    spinner.setDropDownVerticalOffset(dip2px(20));
}
复制代码


(4)添加选中效果


经过上面的处理,我们已经得到想要的样式。但是还差一点,弹窗列表中缺少选中的样式。比如说我当前选择“二年级”,在弹窗中,对应的item字体应该加深加粗。在spinner源码中搜寻了一遍,发现并没有对应的函数和解决方法,那么我们自己动手吧。

其实spinner是使用adapter来加载列表的,而我们使用createFromResource函数会自动创建了adapter,我们可以自定义一个adapter,如下:


public class SpinnerAdapter<T> extends ArrayAdapter<T> {
    private int selectedPostion;
    public void setSelectedPostion(int selectedPostion) {
        this.selectedPostion = selectedPostion;
    }
    public SpinnerAdapter(@NonNull Context context, int resource, @NonNull T[] objects) {
        super(context, resource, objects);
    }
    @Override
    public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        View view = super.getDropDownView(position, convertView, parent);
        TextView textView = (TextView)view;
        if(selectedPostion == position){
            textView.setTextColor(0xff373741);
            textView.getPaint().setFakeBoldText(true);
        }
        else{
            textView.setTextColor(0xff6d6d6d);
            textView.getPaint().setFakeBoldText(false);
        }
        return view;
    }
    public static @NonNull SpinnerAdapter<CharSequence> createFromResource(@NonNull Context context,
                                                                      @ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
        final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
        return new SpinnerAdapter<>(context, textViewResId, strings);
    }
}
复制代码

注意ArrayAdapter中的getDropDownView函数是获取弹窗item使用的view的,而不是getView函数。

同时我们要重新写一个createFromResource函数。

将之前使用的adapter替换成自定义这个,同时为spinner设置监听即可,更改后的代码如下:


Spinner spinner = (Spinner) findViewById(R.id.spinner);
adapter = SpinnerAdapter.createFromResource(this, R.array.grade, R.layout.spinner_layout);
adapter.setDropDownViewResource(R.layout.spinner_item);
spinner.setBackgroundColor(0x0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    spinner.setPopupBackgroundResource(R.drawable.bg_spinner);
    spinner.setDropDownVerticalOffset(dip2px(20));
}
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        adapter.setSelectedPostion(position);
    }
    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }
});
复制代码


最终效果如下:


网络异常,图片无法展示
|


通过我们自己定义adapter可以实现更多复杂的效果和样式,有时间我们再来探讨。


目录
相关文章
|
1月前
|
XML Java Android开发
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
68 1
|
1月前
|
Java Android开发
Android Studio入门之按钮触控的解析及实战(附源码 超详细必看)(包括按钮控件、点击和长按事件、禁用与恢复按钮)
Android Studio入门之按钮触控的解析及实战(附源码 超详细必看)(包括按钮控件、点击和长按事件、禁用与恢复按钮)
362 0
|
9天前
|
API 容器
Flutter 自定义实现时间轴、侧边进度条
Flutter 自定义实现时间轴、侧边进度条
16 0
|
1月前
|
移动开发 小程序 API
uniapp组件库中Collapse 折叠面板 的使用方法
uniapp组件库中Collapse 折叠面板 的使用方法
102 1
|
1月前
uniapp 设置底部导航栏
uniapp 设置底部导航栏
|
6月前
|
Python
按钮组件的使用方法
在tkinter中,按钮组件的使用方法主要包括以下几个步骤: 1. 导入tkinter模块:
64 6
uniapp下拉弹层选择框效果demo(整理)
uniapp下拉弹层选择框效果demo(整理)
|
JSON 小程序 JavaScript
走进小程序【四】小程序自定义Component如何使用,手把手封装一个底部Tabbar栏
走进小程序【四】小程序自定义Component如何使用,手把手封装一个底部Tabbar栏
180 0
走进小程序【四】小程序自定义Component如何使用,手把手封装一个底部Tabbar栏
|
XML 存储 缓存
底部导航栏的几种实现方式
底部导航栏的几种实现方式
300 0
|
设计模式
带你造轮子,自定义一个随意拖拽可吸边的悬浮View组件
在开发中,随意拖拽可吸边的View还是比较常见的,这种功能网上也有各种各样的轮子,其实写起来并不复杂,看完本文,你也可以手写一个,不到400行代码就能实现一个通用的随意拖拽可吸边的View组件。
557 1