三级联动的spinner选择列表及其颜色设置

  • 要实现的目标:如下图,乡镇根据区改变,村根据乡镇改变.选中为红色,默认黑色
    在这里插入图片描述
    三级联动的spinner选择列表及其颜色设置_第1张图片

大致步骤

一. 首先需要三个spinner控件

  • 属性:
  1. spinnerMode 表示下拉列表样式,一种弹窗式,一种下拉式.
  2. 有textColor属性,但是不起作用,颜色的设置要在适配器写,下面再说
 <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="20dp"
            android:paddingTop="15dp"
            android:paddingBottom="10dp">
            <Spinner
                android:id="@+id/area"
                android:theme="@style/TabLayoutTabStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:spinnerMode="dropdown">Spinner>
            <Spinner

                android:id="@+id/town"
                style="?android:spinnerItemStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:spinnerMode="dropdown">Spinner>
            <Spinner
                android:id="@+id/village"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:spinnerMode="dropdown">Spinner>
        LinearLayout>

二. 为spinner添加文本

做完第一步显示效果仅仅是三个箭头而已,内容是空,需要为它设置包含内容的TextView.写在spinner_item.xml内


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/text_view"
        android:text="test"
        android:textSize="13sp"
        android:textColor="@color/spinnerText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
LinearLayout>

三. 为spinner添加适配器

  • 适配器的作用:
  1. 为spinner设计样式,如文字颜色,大小等.这里为选中和未选中设置不同颜色
  2. 为spinner设置内容,绑定数据.这里绑定区/镇/村的内容,并设计关联方法
关于联动的实现分析:
  • 思路: 原始列表中,所有地区的乡镇和村都是混在一起的. 当选中区之后,乡镇只有本区的那几个才显示,这就要求不同区的选中会提供不同的参数来决定乡镇,同理乡镇也会提供参数决定村.反过来,每个村也只对应着一个乡镇,每个乡镇对应一个区. 也就是说他们的关系类似祖孙三辈
  • 所以可以这样设计数据结构:把地区都封装成一个对象,这个对象有两个属性,一个是自己的id,一个是父级的id,这样当区固定后,只需显示父级id为该区id的乡镇即可,完美解决
  • 具体实现就是预先把所有的地区列表传入,然后当上一级选中后,把选中对象的id作为参数传入Adapter中,来筛选这一级有哪些符合条件的地区该显示.
设计封装类:

基于前面的分析,适配器的绑定数据肯定要用到封装类,所以先把这事办了:

package com.sdxzt.xueliangapp_v2.video_monitor_page;

/**
 * 封装区域对象,三种属性,名字/自身id/父级区域id
 */
public class SpinnerBean {
    private String name;
    private int id;
    private int parentId;

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

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

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

    public int getParentId() {
        return parentId;
    }

    public void setParentId(int parentId) {
        this.parentId = parentId;
    }
}

BaseAdapter的常用需重写方法:

在进入正题前,先列举一下这个类的方法,这些方法大多是回调函数,因为会用到,而又不熟悉.总结一下

  • int getCount() 返回列表的数量,这里就是根据地区列表的size来决定
  • Object getItem(int i) 根据指定的位置返回索引位的数据对象
  • long getItemId():根据指定的索引位返回指定条目对应的行号;
  • View getView(int i, View view, ViewGroup viewGroup):
    • 在一般列表中,当绘制列表中的每一个条目时自动调用的方法,绘制多少个条目就会调用多少次;
    • 在spinner中,这个方法是绘制列表合起来的时候显示列表,只有一行.另一个方法是下面这个
  • View getDropDownView(int position, View convertView, ViewGroup parent)
    这个方法是绘制列表打开时,打开的那个表中的每一个条目,绘制多少个就调用多少次.与上面这个方法是分开的
  • class ViewHolder 这是个内部类,用来封装当前列表一个条目所有的的布局子控件,一般用来绑定在view中,以便只赋值一次,多次使用,提高效率

不同颜色的设置

看了上面的方法作用自然就明白了,getView和getDropDownView是分别针对打开和未打开的列表,对样式的设置,自然在这两个方法里.

  • 首行显示红色,只需在getView里为TextView控件设置颜色即可

  • 打开后,已选择的条目显示红色,这里就需要在绘制每个条目时判断这个position是否被选中,那么就要定义一个变量,判断它和当前position是否相等.这个变量的值可以spinner的OnItemSelected监听器触发时传进来.

  • SpinnerAdapter.java

package com.sdxzt.xueliangapp_v2.video_monitor_page;

import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.sdxzt.xueliangapp_v2.R;

import java.util.ArrayList;

/**
 * 地区选择下拉列表的适配器,主要是apapter使数据绑定到控件变得更加简单和灵活...用途为容器提供子视图,利用视图的数据和元数据来构建每个子视图。
 */
public class SpinnerAdapter extends BaseAdapter {
    private Context context;
    private ArrayList<SpinnerBean> list;
    int selectedPosition;

    public SpinnerAdapter(Context context, ArrayList<SpinnerBean> list,int parentId) {
        Log.d("SpinnerAdapter", "list初始化完成"+list.size());
        this.context = context;
        this.list = new ArrayList<>();
        //把应该显示的地区提取到新集合中
        this.list.add(new SpinnerBean("请选择", -1, -1));
        for (SpinnerBean item:list) {
            if (item.getParentId() == parentId) {
                this.list.add(item);
            }
        }
        Log.d("全部list的元素:" + list.size(), "当前list的元素:" + this.list.size());
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    /**
     * 这个是下拉前的布局
     * @param i 位置
     * @param view 列表单项的视图
     * @param viewGroup
     * @return
     */
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder = null;
        if (view == null) {
            view = LayoutInflater.from(context).inflate(R.layout.spinner_item,viewGroup,false);
            viewHolder = new ViewHolder();
            viewHolder.textView = view.findViewById(R.id.text_view);
            //用来绑定控件信息,以便复用,不需要每次查找赋值.主要场景是当控件超出屏幕范围消失,再次出现时复用
            view.setTag(viewHolder);
        }else {
            viewHolder = (ViewHolder) view.getTag();
        }
        //绑定数据
        viewHolder.textView.setText(list.get(i).getName());
        //这里的颜色仅限选择列表首行显示的内容
        viewHolder.textView.setTextColor(Color.RED);
        return view;
    }

    /**
     * 这是下拉后,下拉的布局
     * @param position
     * @param convertView
     * @param parent
     * @return
     */
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        //修改Spinner展开后的字体颜色
        ViewHolder viewHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.spinner_item,parent,false);
            viewHolder = new ViewHolder();
            viewHolder.textView = convertView.findViewById(R.id.text_view);
            //用来绑定控件信息,以便复用,不需要每次查找赋值.主要场景是当控件超出屏幕范围消失,再次出现时复用
            convertView.setTag(viewHolder);
        }else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        //默认显示文字的TextView
        TextView textView  = convertView.findViewById(R.id.text_view);
        textView.setTextColor(Color.BLACK);
        //根据点击位置改变颜色
        if (position == selectedPosition) {
            textView.setTextColor(Color.RED);
        }
        viewHolder.textView.setText(list.get(position).getName());
        return convertView;
    }

    /**
     * 当spinner的OnItemSelected监听器触发时,调用该方法,把选中的位置作为参数传进来,用于在绘制时
     * 判断当前条目是否被选中,应该是什么颜色
     * @param selectedPosition
     */
    public void setSelectedPosition(int selectedPosition) {
        this.selectedPosition = selectedPosition;
    }

    public class ViewHolder{
        TextView textView;
    }
}

四. 为spinner添加OnItemSelectedListener监听器

监听器要做的事:

  1. 列表开始只显示地区一栏,后面隐藏,选择地区后才显示选择乡镇,后面一样. 所以第一件事是判断选择的条目是否有效,有效让后面的显示,否则不显示
  2. 当地区和乡镇选中后,需要把选中的对象的id传入下一级的适配器中,以便下一级来筛选合适的列表数据
  3. 选中后,把选中条目的位置通过setSelectedPosition()进行设置,一遍打开的列表根据位置绘制不同的颜色
 //区spinner的监听器
    private class AreaClickListener implements AdapterView.OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            areaSpinnerAdapter.setSelectedPosition(i);
            SpinnerBean item = (SpinnerBean) adapterView.getItemAtPosition(i);
            //把该选项的id作为参数,为下一级设置适配器
            townSpinnerAdapter = new SpinnerAdapter(VideoMonitorActivity.this, townList, item.getId());
            town.setAdapter(townSpinnerAdapter);
            if ("请选择".equals(item.getName())) {
                Log.d("onItemSelected", "低级列表设置不可见");
                town.setVisibility(View.INVISIBLE);
                village.setVisibility(View.INVISIBLE);
            } else {
                town.setVisibility(View.VISIBLE);
                town.setSelection(0);
            }
            //TODO 自定义一个弹框工具类
            Toast.makeText(getApplicationContext(), item.getName(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    }

    //镇的监听器
    private class TownClickListener implements AdapterView.OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            townSpinnerAdapter.setSelectedPosition(i);
            SpinnerBean item = (SpinnerBean) adapterView.getItemAtPosition(i);
            villageSpinnerAdapter = new SpinnerAdapter(VideoMonitorActivity.this, villageList, item.getId());
            village.setAdapter(villageSpinnerAdapter);
            if ("请选择".equals(item.getName())) {
                village.setVisibility(View.INVISIBLE);
            } else {
                village.setVisibility(View.VISIBLE);
                village.setSelection(0);
            }

            Toast.makeText(getApplicationContext(), item.getName(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    }

    //村的监听器
    private class VillageClickListener implements AdapterView.OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            villageSpinnerAdapter.setSelectedPosition(i);
            SpinnerBean item = (SpinnerBean) adapterView.getItemAtPosition(i);
            Toast.makeText(getApplicationContext(), item.getName(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    }

五. 在主activity中

package com.sdxzt.xueliangapp_v2.video_monitor_page;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SnapHelper;

import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.Spinner;
import android.widget.Toast;

import com.sdxzt.xueliangapp_v2.R;
import com.sdxzt.xueliangapp_v2.base.HeadFragment;

import java.util.ArrayList;

/**
 * 视频监控页面,包括头部,区域选择列表,视频网格列表
 */
public class VideoMonitorActivity extends AppCompatActivity {
   
    private Spinner area, town, village;
    private ArrayList<SpinnerBean> areaList;
    private ArrayList<SpinnerBean> townList;
    private ArrayList<SpinnerBean> villageList;
    private SpinnerAdapter townSpinnerAdapter,areaSpinnerAdapter,villageSpinnerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_monitor);
        initView();
        //添加列表全部地区
        loadArea();
        loadTown();
        loadVillage();
        //给第一级列表添加适配器,父级元素id固定为0,所以可以这这里设置
        areaSpinnerAdapter = new SpinnerAdapter(this, areaList, 0);
        area.setAdapter(areaSpinnerAdapter);
        //设置选择监听器
        area.setOnItemSelectedListener(new AreaClickListener());
        town.setOnItemSelectedListener(new TownClickListener());
        village.setOnItemSelectedListener(new VillageClickListener());

       
    }

    private void loadArea() {
        areaList = new ArrayList<>();
        areaList.add(new SpinnerBean("请选择", -1, -1));
        areaList.add(new SpinnerBean("兖州区", 1, 0));
        areaList.add(new SpinnerBean("任城区", 2, 0));
        areaList.add(new SpinnerBean("市中区", 3, 0));
    }

    private void loadTown() {
        townList = new ArrayList<>();
        townList.add(new SpinnerBean("请选择", -1, -1));
        townList.add(new SpinnerBean("新驿镇", 101, 1));
        townList.add(new SpinnerBean("小孟镇", 102, 1));
        townList.add(new SpinnerBean("新兖镇", 103, 1));
        townList.add(new SpinnerBean("李营街道", 104, 2));
        townList.add(new SpinnerBean("仙营街道", 103, 2));
        townList.add(new SpinnerBean("市中区1号", 105, 3));
        townList.add(new SpinnerBean("市中区2号", 106, 3));
        //因为需要根据父级联动,所以要在父级选定后设置适配器
        //town.setAdapter(new SpinnerAdapter(this,townList));
    }

    private void loadVillage() {
        villageList = new ArrayList<>();
        villageList.add(new SpinnerBean("请选择", -1, -1));
        villageList.add(new SpinnerBean("一村", 200, 101));
        villageList.add(new SpinnerBean("二村", 201, 101));
        villageList.add(new SpinnerBean("三村", 202, 101));
        villageList.add(new SpinnerBean("四村", 203, 101));
        villageList.add(new SpinnerBean("五村", 204, 101));
        int id = 205;
        for (int i = 102; i < 106; i++) {
            for (int j = 0; j < 3; j++) {
                villageList.add(new SpinnerBean("村" + j, id++, i));

            }
        }
        //village.setAdapter(new SpinnerAdapter(this,villageList));
    }

    private void initView() {
        headContainer = findViewById(R.id.head_container);
        area = findViewById(R.id.area);
        town = findViewById(R.id.town);
        village = findViewById(R.id.village);
        videoContainer = findViewById(R.id.video_container);
    }


    //区spinner的监听器
    private class AreaClickListener implements AdapterView.OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            areaSpinnerAdapter.setSelectedPosition(i);
            SpinnerBean item = (SpinnerBean) adapterView.getItemAtPosition(i);
            //把该选项的id作为参数,为下一级设置适配器
            townSpinnerAdapter = new SpinnerAdapter(VideoMonitorActivity.this, townList, item.getId());
            town.setAdapter(townSpinnerAdapter);
            if ("请选择".equals(item.getName())) {
                Log.d("onItemSelected", "低级列表设置不可见");
                town.setVisibility(View.INVISIBLE);
                village.setVisibility(View.INVISIBLE);
            } else {
                town.setVisibility(View.VISIBLE);
                town.setSelection(0);
            }
            //TODO 自定义一个弹框工具类
            Toast.makeText(getApplicationContext(), item.getName(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    }

    //镇的监听器
    private class TownClickListener implements AdapterView.OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            townSpinnerAdapter.setSelectedPosition(i);
            SpinnerBean item = (SpinnerBean) adapterView.getItemAtPosition(i);
            villageSpinnerAdapter = new SpinnerAdapter(VideoMonitorActivity.this, villageList, item.getId());
            village.setAdapter(villageSpinnerAdapter);
            if ("请选择".equals(item.getName())) {
                village.setVisibility(View.INVISIBLE);
            } else {
                village.setVisibility(View.VISIBLE);
                village.setSelection(0);
            }

            Toast.makeText(getApplicationContext(), item.getName(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    }

    //村的监听器
    private class VillageClickListener implements AdapterView.OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            villageSpinnerAdapter.setSelectedPosition(i);
            SpinnerBean item = (SpinnerBean) adapterView.getItemAtPosition(i);
            Toast.makeText(getApplicationContext(), item.getName(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    }
}

你可能感兴趣的:(学习日志)