目录
Spinner用于从一串列表中选择某项,功能类似于单选按钮的组合
有两种展示的方式:列表框形式、对话框形式

- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context=".MainActivity">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="下拉模式的列表框"
- android:textSize="17sp" />
-
- <Spinner
- android:id="@+id/sp_dropdown"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:spinnerMode="dropdown"/>
-
- </LinearLayout>
效果

声明变量

声明变量(静态数组,要展示的选项内容)

主界面完整代码
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.ArrayAdapter;
- import android.widget.Spinner;
- import android.widget.Toast;
-
- public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
- private Spinner sp_dropdown;
-
- //定义下拉列表需要显示的文本数组
- private final static String[] starArray = {"水星", "金星", "地球", "火星", "木星", "土星", "天王星", "海王星"};
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- sp_dropdown = findViewById(R.id.sp_dropdown);
- //声明一个下拉列表的数组适配器// 第一个参数:上下文,第二个参数:条目布局,第三个参数:要显示的数据
- ArrayAdapter<String> startAdapter = new ArrayAdapter<>(this, R.layout.item_select, starArray);
-
- //将适配器给Spinner
- sp_dropdown.setAdapter(startAdapter);
-
- //设置下拉框默认显示第一项
- sp_dropdown.setSelection(0);
-
- //给下拉框设置选择监听器,一旦用户选中某一项,就触发监听器的onItemSelected方法
- sp_dropdown.setOnItemSelectedListener(this);
- }
-
- @Override
- public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
- Toast.makeText(MainActivity.this, "你选择的是" + starArray[position], Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> adapterView) {
-
- }
- }
新建条目布局(我这里根节点直接用的TestView)


- <?xml version="1.0" encoding="utf-8"?>
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:gravity="center"
- android:textColor="#0000ff"
- android:textSize="17sp"
- tools:text="火星" />

添加适配器(Adapter)
适配器作用:负责从数据集合中取出对应的数据显示到条目布局上
数组适配器(ArrayAdapter):最简单的适配器,只展示一行文字
实现步骤:
(1)编写列表项的XML文件,内部布局只要一个TextView标签
(2)调用ArrayAdapter的构造方法,填入待展现的字符串数组,以及列表项的XML文件(R。layout.item_select)
(3)调用下拉控件的setAdapter方法,传入第二步得到的适配器实例
声明数组适配器

效果

设置监听,一单选中弹出吐司

效果


- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context=".MainActivity">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="下拉模式的列表框"
- android:textSize="17sp" />
-
- <Spinner
- android:id="@+id/sp_dialog"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:spinnerMode="dialog"/>
-
- </LinearLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:gravity="center"
- android:textColor="#0000ff"
- android:textSize="17sp"
- tools:text="火星" />
- package net.lzt.spinnerdialog;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.ArrayAdapter;
- import android.widget.Spinner;
- import android.widget.Toast;
-
- public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
- private Spinner sp_dialog;
-
- //定义下拉列表需要显示的文本数组
- private final static String[] starArray = {"水星", "金星", "地球", "火星", "木星", "土星", "天王星", "海王星"};
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- sp_dialog = findViewById(R.id.sp_dialog);
- //声明一个下拉列表的数组适配器// 第一个参数:上下文,第二个参数:条目布局,第三个参数:要显示的数据
- ArrayAdapter<String> startAdapter = new ArrayAdapter<>(this, R.layout.item_select, starArray);
-
- //设置下拉框的标题。对话框模式才显示标题,下拉模式不显示标题
- sp_dialog.setPrompt("请选择行星");
-
- //将适配器给Spinner
- sp_dialog.setAdapter(startAdapter);
-
- //设置下拉框默认显示第一项
- sp_dialog.setSelection(0);
-
- //给下拉框设置选择监听器,一旦用户选中某一项,就触发监听器的onItemSelected方法
- sp_dialog.setOnItemSelectedListener(this);
- }
-
- @Override
- public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
- Toast.makeText(MainActivity.this, "你选择的是" + starArray[position], Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> adapterView) {
-
- }
- }
两种方式的代码基本不变,但是对话框的可以显示一个标题
效果

简单适配器(SimpleAdapter)
简单适配器允许在列表项中同时展示文本与图片

- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <ImageView
- android:layout_width="0dp"
- android:layout_height="50dp"
- android:layout_weight="1"
- android:src="@mipmap/diqiu" />
-
- <TextView
- android:id="@+id/tv_name"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="3"
- android:gravity="center"
- android:textColor="#ff0000"
- android:textSize="17sp"
- android:text="地球"/>
- </LinearLayout>
实现效果

- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context=".MainActivity">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="简单适配器"
- android:textSize="17sp" />
-
- <Spinner
- android:id="@+id/sp_icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:spinnerMode="dialog"/>
-
- </LinearLayout>
效果

- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.SimpleAdapter;
- import android.widget.Spinner;
- import android.widget.Toast;
-
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
-
- //定义下拉列表需要显示的行星图标数组
- private static final int[] iconArray = {
- R.mipmap.shuixing, R.mipmap.jinxing, R.mipmap.diqiu, R.mipmap.huoxing,
- R.mipmap.muxing, R.mipmap.tuxing, R.mipmap.tianwangxing, R.mipmap.haiwangxing
- };
- //定义下拉列表需要显示的行星名称数组
- private static final String[] starArray = {"水星", "金星", "地球", "火星", "木星", "土星", "天王星", "海王星"};
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- //声明一个映射对象的列表,用于保存行星的图标与名称配对信息
- List<Map<String, Object>> List = new ArrayList<>();
- //iconArray是行星的图标数组,starArray是行星名称数组【这里遍历数组】
- for (int i = 0; i < iconArray.length; i++) {
- Map<String, Object> item = new HashMap<>();
- item.put("icon", iconArray[i]);
- item.put("name", starArray[i]);
- List.add(item);
- }
-
-
- //建立绑定关系,声明一个下拉列表的简单适配器,其中指定了图标与文本两组数据
- SimpleAdapter starAdapter = new SimpleAdapter(this, List,
- R.layout.item_simple, //条目布局
- new String[]{"icon", "name"}, //map中的key
- new int[]{R.id.iv_icon, R.id.tv_name}); //map中的值
-
- Spinner sp_icon = findViewById(R.id.sp_icon);
- sp_icon.setAdapter(starAdapter);
- sp_icon.setSelection(0); // 默认选中0
- sp_icon.setOnItemSelectedListener(this);
-
- }
-
- @Override
- public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
- Toast.makeText(MainActivity.this, "你选择的是" + starArray[position], Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> adapterView) {
-
- }
- }
集合当中数据与条目布局的对应关系

运行效果

【我的图片是我网上找的然后截的图,大小有点差别,如果还想好看整齐点儿可以找大小一致的照片】
基本适配器(BaseAdapter)是一种适应性更强的基本适配器
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <!--这里用于显示行星图片的视图-->
- <ImageView
- android:id="@+id/iv_icon"
- android:layout_width="0dp"
- android:layout_height="80dp"
- android:layout_weight="1"
- android:scaleType="fitCenter"
- android:src="@mipmap/diqiu" />
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_marginLeft="5dp"
- android:layout_weight="3"
- android:orientation="vertical">
-
- <!--显示行星名称的文本视图-->
- <TextView
- android:id="@+id/tv_name"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:gravity="start|center"
- android:text="地球"
- android:textColor="#000000"
- android:textSize="20sp" />
-
- <TextView
- android:id="@+id/tv_desc"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="2"
- android:gravity="start|center"
- android:text="地球是距太阳第三颗,也是太阳系第五大行星,地球是太阳系中密度最大的行星。"
- android:textColor="#000000"
- android:textSize="10sp" />
- </LinearLayout>
-
-
- </LinearLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context=".MainActivity">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="基本适配器"
- android:textSize="17sp" />
-
- <Spinner
- android:id="@+id/sp_planet"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:spinnerMode="dialog"/>
-
- </LinearLayout>
BaseAdapter是一个抽象类,无法直接使用所以需要创建一个适配器类
- import android.content.Context;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.TextView;
-
- import java.util.List;
-
- //适配器
-
- public class PlanetBaseAdapter extends BaseAdapter {
-
- //定义成员属性
- private Context mContext;
- private List<Planet> mPlaneList; //行星信息的集合
-
-
- public PlanetBaseAdapter(Context mContext, List<Planet> mPlaneList) {
- this.mContext = mContext;
- this.mPlaneList = mPlaneList;
- }
-
- @Override
- public int getCount() { //告诉适配器集合中有多少个元素
- return mPlaneList.size();
- }
-
- @Override
- public Object getItem(int position) { //条目与数据对应的索引
- return mPlaneList.get(position);
- }
-
- @Override
- public long getItemId(int position) { //Planet对应的id,但是这里没有,所以直接返回position(不会重复)
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) { // 每个条目怎么来的
- // 根据布局文件item_list.xml生成转换视图对象(导入条目布局)
- View view = LayoutInflater.from(mContext).inflate(R.layout.item_list, null);
- ImageView iv_icon = view.findViewById(R.id.iv_icon);
- TextView tv_name = view.findViewById(R.id.tv_name);
- TextView tv_desc = view.findViewById(R.id.tv_desc);
-
- // 给控件设置好数据(拿到数据)
- Planet planet = mPlaneList.get(position);
- iv_icon.setImageResource(planet.image);
- tv_name.setText(planet.name);
- tv_desc.setText(planet.desc);
-
- return view;
- }
- }
这里主要是存放行星的图片、名称以及介绍的信息,方便后续导入
这里关于各个行星的介绍网上复制即可,但是注意最好别太多
- import java.util.ArrayList;
- import java.util.List;
-
- //实体类
-
- public class Planet {
- public int image; // 行星图标
- public String name; //行星名称
- public String desc; //行星描述
-
- public Planet(int image, String name, String desc) {
- this.image = image;
- this.name = name;
- this.desc = desc;
- }
-
- //定义下拉列表需要显示的行星图标数组
- private static int[] iconArray = {R.mipmap.shuixing, R.mipmap.jinxing, R.mipmap.diqiu, R.mipmap.huoxing,
- R.mipmap.muxing, R.mipmap.tuxing, R.mipmap.tianwangxing, R.mipmap.haiwangxing};
-
- //定义下拉列表需要显示的行星名称数组
- private static final String[] nameArray = {"水星", "金星", "地球", "火星", "木星", "土星", "天王星", "海王星"};
-
- //定义下拉列表需要显示的行星描述数组
- private static final String[] descArray = {
- "水星最接近太阳 [3] ,是太阳系中体积和质量最小的行星。常和太阳同时出没,中国古代称之它为“辰星”。水星在直径上小于两个卫星——木卫三和土卫六。",
- "太阳系中第六大行星,太阳系中温度最高的行星,中国古代称之为太白或太白金星。它有时是晨星,黎明出现于东方天空,被称为“启明”;有时又是昏星,黄昏后出现西方天空,被称为“长庚”。",
- "地球是距太阳第三颗,也是太阳系第五大行星,地球是太阳系中密度最大的行星。地球,当然不需要飞行器即可被观测,然而我们直到二十世纪才有了整个行星的地图。",
- "为距太阳第四远,也是太阳系中第七大行星,在中国古代又称荧火,因为火星呈红色,荧荧像火,亮度常有变化;而且在天空中运动,有时从西向东,有时又从东向西。",
- "木星是离太阳第五颗行星,中国古代称为岁星,因为他公转一周正好是12年,也就是一地支,木星是太阳系行星中质量最大的一颗。",
- "土星是离太阳第六远的行星,也是八大行星中第二大的行星,中国古代称为“镇星”,是太阳系密度最小的行星,可以浮在水上。",
- "天王星是太阳系中离太阳第七远行星,也是太阳系中最冷的行星,从直径来看,是太阳系中第三大行星。天王星的体积比海王星大,质量却比其小。",
- "海王星是环绕太阳运行的第八颗行星,也是太阳系中第四大天体(直径上)。海王星在直径上小于天王星,但质量比它大。"
- };
-
- public static List<Planet> getDefaultList() {
- List<Planet> planetList = new ArrayList<>();
- for (int i = 0; i < iconArray.length; i++) {
- planetList.add(new Planet(iconArray[i], nameArray[i], descArray[i]));//根据上面的三个数组构建的集合
- }
- return planetList;
- }
- }
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.Spinner;
- import android.widget.Toast;
-
- import java.util.List;
-
- public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
- private List<Planet> planetList;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
-
- Spinner sp_planet = findViewById(R.id.sp_planet);
-
- //创建一个集合,获取默认的行星列表
- planetList = Planet.getDefaultList();
-
- /**
- * 指定Spinner的适配器
- * BaseAdapter是一个抽象类,无法直接使用(创建一个适配器类)
- * 构建一个行星适配器
- */
- PlanetBaseAdapter adapter = new PlanetBaseAdapter(this, planetList);
- sp_planet.setAdapter(adapter);
-
- sp_planet.setSelection(0);
- //选中的监听
- sp_planet.setOnItemSelectedListener(this);
- }
-
- @Override
- public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
-
- Toast.makeText(MainActivity.this, "你选择的是" + planetList.get(position).name, Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> adapterView) {
-
- }
- }
条目与数据集合对应关系

运行结果

当列表的item从上方滚出屏幕视角之外时:

优化后

- @Override
- public View getView(int position, View convertView, ViewGroup parent) { // 每个条目怎么来的
- ViewHolder holder;
- if (convertView == null) {
- // 根据布局文件item_list.xml生成转换视图对象(导入条目布局)
- convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, null);
- holder = new ViewHolder();
- holder.iv_icon = convertView.findViewById(R.id.iv_icon);
- holder.tv_name = convertView.findViewById(R.id.tv_name);
- holder.tv_desc = convertView.findViewById(R.id.tv_desc);
-
- //将试图持有者保存到转换视图中(将holder绑定到convertView)
- convertView.setTag(holder);
- } else {
- //重用上面的控件(将上面的控件打包好直接调用)
- holder = (ViewHolder) convertView.getTag();
- }
-
- // 给控件设置好数据(拿到数据)
- Planet planet = mPlaneList.get(position);
- holder.iv_icon.setImageResource(planet.image);
- holder.tv_name.setText(planet.name);
- holder.tv_desc.setText(planet.desc);
-
- return convertView;
- }
-
- public final class ViewHolder {
- public ImageView iv_icon;
- public TextView tv_name;
- public TextView tv_desc;
- }
这里无论是if还是else都会刷新数据
这样个写法更企业化,也更节省空间。