27. 【Android教程】下拉选择框 Spinner

本节我们将学习 Android 提供的下拉选择框——Spinner,它也是 Adapter 的常客。不仅仅是在 Android 端,在 Windows 上我们也经常会看到 Spinner 类型的样式。通常它是以下拉的形式存在,Spinner 在下拉列表中包含很多可供用户选择的选项,用户可以通过点击 Spinner 完成选择。

1. Spinner 的特性

Spinner 的功能是提供一个选择框,默认情况下 Spinner 展示的是当前的选项,点击 Spinner 控件将会展示所有可选项供用户点击选择。Spinner 在很多情况下并不是独立存在的,很有可能当前的 Spinner 的选项需要依赖于前一个 Spinner 的选择结果。

比如我们常见的地址选择页面,首先一个 Spinner 展示所有的省份,在你选择省份之后,第二个 Spinner 拿到你的选项生成相应的城市选项,所以 Spinner 是一个常用并且非常灵活的控件,它的实现依然需要 Adapter。

2. Spinner 的基本用法

2.1 Spinner 的相关属性

  • android:gravity:
    设置 Spinner 内部 item 的对齐方式
  • android:dropDownHorizontalOffset:
    设置下拉选择框的水平偏移距离
  • android:dropDownVerticalOffset:
    设置下拉选择框的垂直偏移距离
  • android:dropDownWidth:
    设置下拉列表框的宽度
  • android:dropDownSelector:
    下拉选择框被选中时的背景样式
  • android:popupBackground:
    设置下拉选择框的背景样式
  • android:prompt:
    设置选择框的提示信息,此属性不能直接设置 String,而必须设置一个 string 资源
  • android:spinnerMode:
    选择框的模式,有两个可选值:
    • dialog: 对话框风格
    • dropdown: 下拉列表风格
  • android:entries:
    通过 string 资源的方式设置下拉选择项

2.2 Spinner 选择事件监听器

  • setOnItemSelectedListener:
    为 Spinner 设置选中事件回调,该接口中包含两个回调方法:

    • onItemSelected:
      当 Spinner 中某个选项被选中时回调该方法,在用户选择了 Spinner 中不同于当前已选中的选项或者当前没有任何选项选中时,系统会回调该方法。此时可以通过getItemAtPosition(position)来获取当前被选中的 item 对象,比如文章开头提到的选城市的功能就需要通过此接口实时获取用户的选择。
    • onNothingSelected:
      这个回调方法用的不较少,它是在选项消失的时候被系统回调的,选项消失通常发生在数据清空的时候

    特别说明: 虽然 Spinner 和 ListView、GridView 一样都是 AdapterView,但是在 Spinner 中不能使用setOnItemClickListener,如果使用系统会抛出以下异常:

setOnItemClickListener cannot be used with a spinner

所以在 Spinner 中我们要用setOnItemSelectedListener来监听选择事件。

3. Spinner 使用示例

本节仍然采用“水果列表”的示例,之前是通过 ListView、GridView 将水果类型和图片直接罗列在屏幕上。而本节只会在屏幕上暴露出一个选项,在点击水果的时候弹出所有的选择项等待用户选择,由于 Adapter 完善的 MVC 模式,可以继续在之前的代码上简单修改即可。

3.1 定义 Spinner 布局

布局文件很简单,直接在根布局中放置一个 Spinner 即可

Spinner 的属性都比较好理解,大家可以在阅读的同时自行添加尝试。

3.2 编写 Adapter

和上一节的 GridView 一样,我们通过修改 MyAdapter 的getCountgetView两个回调方法来实现水果列表的扩展,代码如下:

package com.emercy.myapplication;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;public class MyAdapter extends BaseAdapter {private Context mContext;private String[] mName;private int[] mResId;public MyAdapter(Context context) {mContext = context;}public void setData(String[] name, int[] resId) {mName = name;mResId = resId;}@Overridepublic int getCount() {return mName.length * 10;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// 针对convertView做一个简单的优化if (convertView == null) {convertView = LayoutInflater.from(mContext).inflate(R.layout.list_view, null);}TextView name = convertView.findViewById(R.id.textView);ImageView image = convertView.findViewById(R.id.imageView);name.setText(mName[position % mName.length]);image.setImageResource(mResId[position % mResId.length]);return convertView;}
}

细心的读者可能会注意到,相比上一节的例子,在getView当中有一个小小的改动:

 // 针对convertView做一个简单的优化if (convertView == null) {convertView = LayoutInflater.from(mContext).inflate(R.layout.list_view, null);}

这个改动是一个简单的优化,可以减少每次 inflate 造成的性能消耗,这样 Adapter 只会在第一次去做 inflate,而后续的getView()回调将直接复用之前的convertView。

3.3 定义数据源

数据源分两部分:水果名称和水果图片,分别用一个 String 数组和 int 数组存放,如下:

String[] mDataName = {"苹果", "梨", "香蕉", "桃子", "西瓜", "荔枝", "橘子"};int[] mDataImage = {R.drawable.apple, R.drawable.pear, R.drawable.banana, R.drawable.peach,R.drawable.watermelon, R.drawable.lychee, R.drawable.orange, R.drawable.orange};

然后通过 MyAdapter 提供的设置数据的接口设置给 Adapter:

        adapter.setData(mDataName, mDataImage);

3.4 完成 MainActivity

整体的 MainActivity 和之前的逻辑大体相同,但是在 2.2 中我们提到过,Spinner 不能使用setOnItemClickListener接口,所以我们将事件监听器改成setOnItemSelectedListener,最终代码如下:

package com.emercy.myapplication;import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Spinner;
import android.widget.Toast;public class MainActivity extends Activity {Spinner mSpinner;String[] mDataName = {"苹果", "梨", "香蕉", "桃子", "西瓜", "荔枝", "橘子"};int[] mDataImage = {R.drawable.apple, R.drawable.pear, R.drawable.banana, R.drawable.peach,R.drawable.watermelon, R.drawable.lychee, R.drawable.orange, R.drawable.orange};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mSpinner = findViewById(R.id.spinner);MyAdapter adapter = new MyAdapter(this);adapter.setData(mDataName, mDataImage);mSpinner.setAdapter(adapter);mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {Toast.makeText(getApplicationContext(), mDataName[position / mDataImage.length], Toast.LENGTH_LONG).show();}@Overridepublic void onNothingSelected(AdapterView<?> parent) {Toast.makeText(getApplicationContext(), "onNothingSelected", Toast.LENGTH_LONG).show();}});}
}

运行之后页面中只会有一个默认选项,点击 Spinner 会弹出一个下拉框,任意选中一个会触发onItemSelected回调方法并通过Toast打印当前选择项。选择完成之后,Spinner 会展示新选择的水果名称和图片,效果如下:

4. 小结

本节继 ListView、GridView 之后又讲解了一个采用 Adapter 实现的 UI 样式,它主要适用的是下拉选择的场景,相比 ListView、GridView 它更省空间,只会在页面上展示已选项,用户需要通过点击才能调起所有的选项。

Spinner 的属性也比较简单,需要特别注意的是它不支持设置setOnItemClickListener接口,取而代之的是setOnItemSelectedListener接口,最后我们仍然采用“水果列表”的例子演示了一个 Spinner 的用法,当然对于 Spinner 还有很多花哨的样式,大家可以在自己的例子代码中设置看看,会有惊喜哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/623949.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker+Uwsgi部署Django项目

在之前的文章中&#xff0c;已经给大家分享了在docker中使用django自带的命令部署项目&#xff0c;这篇文章主要讲解如何使用uwsgi部署。 1. 在Django项目的根目录下新建Dockerfile文件 #Dockerfile文件 # 使用 Python 3.9 作为基础镜像 FROM python:3.9# 设置工作目录 WORKDI…

Intel显卡驱动导致Qt opengl 渲染YUV时拉伸窗口内存泄漏

最近在使用QOpenGLWidget做YUV视频渲染&#xff0c;发现在拉伸窗口的时候内存暴涨&#xff0c;如果窗口不动则内存不变。 可以得出结论一定是resizeGL出了问题&#xff0c;但是其实这里代码很简单 glViewport(0, 0, w, h); 还有就是变换矩阵计算&#xff0c;根本没资源建立与释…

大模型微调的几种常见方法

在文章深入理解大语言模型微调技术中&#xff0c;我们详细了解大语言模型微调的概念和训练过程&#xff0c;本篇给大家介绍大模型微调常见的7种训练方法。 1、Adapter Tuning 2019年谷歌的研究人员首次在论文《Parameter-Efficient Transfer Learning for NLP》提出针对 BERT 的…

NIO学习

文章目录 前言一、主要模块二、使用步骤1.服务器端2.客户端 三、NIO零拷贝(推荐)四、NIO另一种copy总结 前言 NIO是JDK1.4版本带来的功能,区别于以往的BIO编程,同步非阻塞极大的节省资源开销&#xff0c;避免了线程切换和上下文切换带来的资源浪费。 一、主要模块 Selector&a…

ENSP-旁挂式AC

提醒&#xff1a;如果AC不能成功上线AP&#xff0c;一般问题不会出在AC上&#xff0c;优先关注AC-AP线路上的二层或三层组网的三层交换机 拓扑图 管理VLAN&#xff1a;99 | 业务VLAN&#xff1a;100 注意点&#xff1a; 1.连接AP的接口需要打上pvid为管理vlan的标签 2.AC和…

Vitis HLS 学习笔记--readVec2Stream 函数-探究

目录 1. 高效内存存取的背景 2. readVec2Stream() 参数 3. 函数实现 4. 总结 1. 高效内存存取的背景 在深入研究《Vitis HLS 学习笔记--scal 函数探究》一篇文章之后&#xff0c;我们对于scal()函数如何将Y alpha * X这种简单的乘法运算复杂化有了深刻的理解。本文将转向…

imgcat 工具

如果经常在远程服务器或嵌入式设备中操作图片&#xff0c;要查看图片效果&#xff0c;就要先把图片dump到本地&#xff0c;比较麻烦。可以使用这个工具&#xff0c;直接在终端上显示。类似于这种效果。 imgcat 是一个终端工具&#xff0c;使用 iTerm2 内置的特性&#xff0c;允…

FOR循环指令计算累加和(CODESYS ST+SMART梯形图代码)

1、SMART PLC FOR循环指令应用 SMART PLC FOR循环指令_smart plc可以调用多少次for循环-CSDN博客文章浏览阅读2.4k次&#xff0c;点赞2次&#xff0c;收藏6次。SMART PLC的FOR循环&#xff1a; PLC里写需要加上&#xff1a; NEXT指令_smart plc可以调用多少次for循环https://r…

2024 年10个最佳 Ruby 测试框架

QA一直在寻找最好的自动化测试框架&#xff0c;这些框架提供丰富的功能、简单的语法、更好的兼容性和更快的执行速度。如果您选择结合使用Ruby和Selenium进行Web测试&#xff0c;可能需要搜索基于Ruby的测试框架进行Web应用程序测试。 Ruby测试框架提供了广泛的功能&#xff0…

打一把王者的时间,学会web页面测试方法与测试用例编写

一、输入框 1、字符型输入框&#xff1a; &#xff08;1&#xff09;字符型输入框&#xff1a;英文全角、英文半角、数字、空或者空格、特殊字符“~&#xff01;#&#xffe5;%……&*&#xff1f;[]{}”特别要注意单引号和&符号。禁止直接输入特殊字符时&#xff0c;…

纯golang开发的mqtt server

Mochi-MQTT Server github地址&#xff1a;https://github.com/mochi-mqtt/server Mochi-MQTT 是一个完全兼容的、可嵌入的高性能 Go MQTT v5&#xff08;以及 v3.1.1&#xff09;中间件/服务器。 Mochi MQTT 是一个完全兼容 MQTT v5 的可嵌入的中间件/服务器&#xff0c;完…

网络编程day4

目录 使用多进程实现并发服务器 使用多线程实现并发服务器 流式域套接字服务器 流式域套接字客户端 报式域套接字服务器 报式域套接字客户端 tftp客户端 思维导图 使用多进程实现并发服务器 #include <myhead.h> void sighandler(int signum){if(signumSIGCHLD)…