提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:Spinner的自定义控件
提示:以下是本篇文章正文内容,下面案例可供参考
一、Spinner是什么?
示例:Android中的Spinner
是一种下拉菜单控件,通常用于选择一组选项中的一个。由于Android屏幕有限,所以在Android中实现Spinner是通过弹出式窗口实现的。
Spinner控件的属性包括:
android:entries:直接在xml布局文件中绑定数据源(可以不设置,即可以在Activity中动态绑定)。
android:prompt:在Spinner弹出选择对话框的时候对话框的标题。
android:dropDownHorizontalOffset:设置列表框的水平偏移距离。
android:dropDownVerticalOffset:设置列表框的水平竖直距离。
android:dropDownSelector:列表框被选中时的背景。
android:dropDownWidth:设置下拉列表框的宽度。
android:gravity:设置里面组件的对其方式。
android:popupBackground:设置列表框的背景。
特别注意android:spinnerMode:属性有Spinner的显示形式,有两个可选值:dialog
和dropdown
(默认)。
dropdown模式:
dialog模式:
二、应用场景
Spinner控件在Android中常被用于以下场景:
1.用户输入:Spinner可以用于提供用户输入的选项列表,用户可以从下拉菜单中选择一个选项作为输入。
2.数据选择:Spinner可以用于从一组预定义的选项中选择数据。例如,在表单填写中,用户可以通过Spinner选择性别、省份等选项。
3.节省屏幕空间:由于Spinner控件会以弹出窗口的形式展示选项,因此可以在有限的屏幕空间内展示更多的选项,特别是在需要展示大量选项时。
4.提供快速导航:Spinner可以用于提供快速导航选项,例如在应用程序中快速切换不同的视图或页面。
三、使用步骤
1.准备资源文件
1.在 res/values/ 文件夹下新建一个 arrays.xml
文件,下面的数据是点击弹出的选项内容
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="spinner_string">
<item>C语言</item>
<item>C++</item>
<item>python</item>
<item>Java</item>
</string-array>
</resources>
2.activity_main.xml 文件的布局内容
<Spinner
android:layout_width="100dp"
android:layout_height="80dp"
android:id="@+id/spinner"
android:spinnerMode="dropdown"
android:entries="@array/spinner_string"/>
2.自定义dropdown样式
1.修改点击样式和下拉框样式
在res/drawable/ 文件夹下新建两个文件:
(1)shape_for_custom_spinner.xml 文件(用来定义下拉框的样式):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 填充颜色 -->
<solid android:color="@color/white"/>
<stroke android:width="1dp" android:color="#661886F7"/>
<!-- 矩形的圆角半径 -->
<corners android:radius="6dp" />
</shape>
参考数据:
在Android中,Shape类可以用于创建各种形状,包括矩形(rectangle)、椭圆形(oval)、线条(line)、环形(ring)等。Shape类中包含以下基本属性:
corners:用于定义形状的角,可以设置圆角半径。
solid:用于定义形状的颜色和填充方式。
gradient:用于定义形状的渐变效果,包括线性渐变(linear)、放射性渐变(radial)和扫描式渐变(sweep)。
stroke:用于定义形状的描边属性,包括描边的宽度、颜色、虚实线等。
padding:用于定义形状的内边距。
(2)selector_for_custom_spinner文件(用来定义Spinner控件本身的样式,带选择器,有点击效果):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 表示被按下(触摸)的状态。在这个状态下,会显示一个填充了#661886F7颜色的矩形,矩形的圆角半径为6dp -->
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#661886F7"/>
<!-- 矩形的圆角半径 -->
<corners android:radius="6dp" />
</shape>
</item>
<!-- 表示没有被按下(触摸)的状态。在这个状态下,会显示一个透明的矩形,并在边缘有一条宽度为1dp、颜色为#661886F7的描边。矩形的圆角半径同样为6dp -->
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="@android:color/transparent"/>
<stroke android:width="1dp" android:color="#661886F7"/>
<!-- 矩形的圆角半径 -->
<corners android:radius="6dp" />
</shape>
</item>
</selector>
3.在界面文件中的Spinner控件中引用它们:
<Spinner
...
android:popupBackground="@drawable/shape_for_custom_spinner"
android:background="@drawable/selector_for_custom_spinner"/>
4. 增加下划线
在res/values/ 文件夹下新建一个style.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<!-- 定义了一个自定义主题(customTheme)和一个对应的自定义下拉列表样式(customSpinnerStyle) -->
<resources>
<style name="customTheme">
<item name="dropDownListViewStyle">@style/customSpinnerStyle</item>
</style>
<style name="customSpinnerStyle" parent="android:Widget.ListView.DropDown">
<item name="android:textAlignment">center</item>
<item name="divider">@color/black</item>
<item name="android:dividerHeight">1dp</item>
</style>
</resources>
说明:
(1)customTheme——自定义主题样式,引用它自定义下划线才能正常显示。
(2)customSpinnerStyle——自定义的Spinner样式,和上面的主题样式一样在界面文件中引用。
(3)android:divider——分割线颜色。
(4)android:dividerHeight——分割线宽度。
在界面文件中的Spinner控件中引用它:
<Spinner
...
android:paddingTop="15dp"
android:paddingBottom="15dp"
style="@style/customSpinnerStyle"/>
3.动态配置Spinner选项
1. 删除界面文件中引入的字符串组即,删除这一行:
<Spinner
...
android:entries="@array/spinner_string"
.../>
2. 增加一个自定义的layout文件来配置列表样式
在res/layout/ 文件夹下新建一个item_for_custom_spinner.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center"
android:text="下拉列表项样式"
android:textColor="@color/purple_700"
android:textSize="18dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="15dp"
android:paddingBottom="15dp"
android:singleLine="true"
android:ellipsize="marquee"/>
当文本内容超过控件宽度时,android:ellipsize="marquee"会使文本像 marquee(跑马灯)一样滚动。Marquee 是一种在页面顶部或者底部的滚动文本效果,常用于新闻滚动条或者广告条。
3. 在Java文件中对Spinner控件进行配置
MainActivity.java
文件:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 预定义变量
Spinner spinner;
List<String> listForSpinner = new ArrayList<>();
ArrayAdapter<String> adapterForSpinner;
// 变量初始化
spinner = findViewById(R.id.spinner);// 引用Spinner控件
// 给字符串数组赋初值
listForSpinner.add("C语言");
listForSpinner.add("Python");
listForSpinner.add("Java");
listForSpinner.add("C++");
// 设置适配器
adapterForSpinner = new ArrayAdapter<>(MainActivity.this, R.layout.item_for_custom_spinner, listForSpinner);
spinner.setAdapter(adapterForSpinner);
}
}
说明: 不想自己自定义列表样式可以选择直接使用Android自带的support_simple_spinner_dropdown_item 效果:
4.Spinner选择事件
1. 增加一个简单的选择监听器
Toast toast = Toast.makeText(getApplicationContext(), "default toast", Toast.LENGTH_SHORT);
//为Spinner设置了一个监听器,当Spinner的某个选项被选中时,这个监听器会被触发
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
toast.setText(listForSpinner.get(i));
toast.show();
}
//接口的另一个方法,它会在没有任何选项被选中时被调用。这里没有实现任何功能,即当没有选项被选中时,程序什么也不做
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
可以发现有两个问题:
(1)初始化监听器的时候事件被调用了。
(2)重复点击同一选项事情不会被重复调用,即不会跳出吐司提示。
2. 不希望监听器动作初始化时就被调用
办法很简单,就是定义一个flag用来确认监听器是否是第一次被调用,是,则忽略它:
代码如下:(需要替换掉上面的)
final int[] flag = {0};
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
//首先检查flag[0]的值是否为0。如果为0,那么将flag[0]加1并立即返回,不执行下面的代码。
if (flag[0] == 0){
flag[0] = flag[0] + 1;
return;
}
//如果flag[0]的值不为0,那么会执行下面的代码
toast.setText(listForSpinner.get(i));
toast.show();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
这样一来,界面初始化时就不会出现监听器动作被执行了一次的情况了。
3. 不希望重复点击同一选项时没有动作
需要重写Spinner控件的部分代码。
(1)在java/com.xxx.xxx文件夹下新建一个ReSpinner.java
文件:
package com.example.myapplication;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
@SuppressLint("AppCompatCustomView")
public class ReSpinner extends Spinner {
public boolean isDropDownMenuShown = false;
/**
* @param context 用来解决原生spinner点击同一选项无反应的问题
*/
public ReSpinner(Context context) {
super(context);
}
public ReSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ReSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setSelection(int position, boolean animate){
boolean sameSelected = (position == getSelectedItemPosition());
super.setSelection(position, animate);
if (sameSelected){
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
//作用是在执行点击事件时,先设置一个标志位表示下拉菜单已经被显示过,然后再执行点击事件的相应操作
@Override
public boolean performClick(){
this.isDropDownMenuShown = true;
return super.performClick();
}
//调用super.setSelection(position)方法来设置Spinner选中的选项。这是非常重要的,因为只有通过调用父类的setSelection方法,才能将Spinner的选中状态更新为新的选项
@Override
public void setSelection(int position){
boolean sameSelected = (position == getSelectedItemPosition());
super.setSelection(position);
if (sameSelected){
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
(2)替换掉界面文件中的控件根名称,其他什么都不用动: 将
<Spinner
.../>
改为
<com.xxx.xxx.ReSpinner
.../>
这样一来,重复点击同一事件,也能正常多次触发监听器动作了。
5.自定义dialog样式
经过上面的修改,基本已经完成了对dropdown模式下的样式自定义和监听器动作自定义了,将spinnerMode改回dialog,增加一个prompt标签,增加dialog的标题:
(1)先在res/values/strings.xml文件中定义一个标题(必须步骤):
<resources>
<string name="app_name">My Application</string>
<string name="spinner_title">Spinner Title</string>
</resources>
(2)再在边界文件中引用它:
<com.xxx.xxx.ReSpinner
...
android:spinnerMode="dialog"
android:prompt="@string/spinner_title"
.../>
[参考](https://zhuanlan.zhihu.com/p/448561541)