重拾Android之路之Spinner

作者: OzanShareing | 来源:发表于2018-04-14 15:58 被阅读245次

    引言

    最近做的项目想仿做滴滴出行首页的悬浮框。

    正文

    效果参考滴滴出行;

    工欲善其事,必先利其器!来......

    Spinner详解

    Spinner控件初始化时,会调用它的选择监听事件,默认选择第一个

    一、Spinner比较好用的属性
    1. Spinnerentries属性,就可以不用设置SpinnerAdapter,也可以填充数据
    <Spinner
       android:id="@+id/spCity"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:prompt="请选择城市"
       android:entries="@array/cities"/>
    
    1. SpinnerspinnerMode属性,Spinner显示为对话框或者是下拉框形式;
    android:spinnerMode=["dialog"|"dropdown"]
    prompt属性表示spinner列表上方的提示
    

    spinnerMode="dialog"效果图,可以看到我们设置的提示符"请选择城市"

    spinnerMode="dropdown"效果图

    spinner_drop_item
    二、设置spinner显示数据

    使用Spinner布局文件使用的是系统默认的;使用创建ArrayAdapter两种方式,传入不同的数据源;

    • 使用xml文件作为数据源
    private void initView(){
        city= (Spinner) findViewById(R.id.spCity);
        SpinnerAdapter  adapter=null;
        adapter=ArrayAdapter.createFromResource(this,R.array.cities,android.R.layout.simple_spinner_dropdown_item);
        city.setAdapter(adapter);
    }
    
    • 使用数组或者是List作为数据数据源
    ArrayList<String> list=new ArrayList<String>();
    SpinnerAdapter adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,list);
    
    三、spinner点击事件处理
    city.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
          @Override
          public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                //这个方法里可以对点击事件进行处理
                //i指的是点击的位置,通过i可以取到相应的数据源
          }
          @Override
          public void onNothingSelected(AdapterView<?> adapterView) {
          }
    })
    
    四、用代码来点击spinner
    //选择Spinner里的第二个数据;
    city.setSelection(1,true);
    
    自定义Spinner
    • 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函数中,mResourcemDropDownResource赋值相同。但是ArrayAdapter还有一个setDropDownViewResource函数。

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

    spinner_layout.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的两个函数setPopupBackgroundResourcesetDropDownVerticalOffset

    但是注意这两个函数都需要在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)); 
    }
    

    另外有一种方式同样也可以达到效果,在这里记录一下:
    (但是很粗糙,没能满足紧靠正下方的需求)

    解决方案:这是因为spinner有一个属性:android:overlapAnchor=”false”
    这个属性默认是true。改为false即可。但是不知道为什么这个属性在代码提示中是没有的。所以记录下来。

    (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){
        }
    });
    
    

    相关文章

      网友评论

        本文标题:重拾Android之路之Spinner

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