Spinner实现的下拉功能

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示: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的显示形式,有两个可选值:dialogdropdown(默认)。
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)
  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spinner控件本身不支持多选功能,但可以通过自定义适配器来实现多选下拉菜单。 以下是一个示例代码: ```java public class MultiSpinnerAdapter extends ArrayAdapter<String> implements OnItemClickListener { private List<String> items; private boolean[] selected; private Spinner spinner; public MultiSpinnerAdapter(Context context, int textViewResourceId, List<String> items, Spinner spinner) { super(context, textViewResourceId, items); this.items = items; this.selected = new boolean[items.size()]; this.spinner = spinner; spinner.setOnItemClickListener(this); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); TextView textView = (TextView) view.findViewById(android.R.id.text1); if (selected[position]) { textView.setTextColor(Color.RED); } else { textView.setTextColor(Color.BLACK); } return view; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selected[position] = !selected[position]; getView(position, view, parent); } public List<String> getSelectedItems() { List<String> selectedItems = new ArrayList<>(); for (int i = 0; i < items.size(); i++) { if (selected[i]) { selectedItems.add(items.get(i)); } } return selectedItems; } } ``` 在Activity中使用该适配器: ```java Spinner spinner = (Spinner) findViewById(R.id.spinner); List<String> items = Arrays.asList("Item 1", "Item 2", "Item 3", "Item 4"); MultiSpinnerAdapter adapter = new MultiSpinnerAdapter(this, android.R.layout.simple_spinner_item, items, spinner); spinner.setAdapter(adapter); // 获取选中的项 List<String> selectedItems = adapter.getSelectedItems(); ``` 以上代码实现了一个多选下拉菜单,当用户点击列表项时,会切换该项的选中状态,并且选中状态的文本颜色将变为红色。getSelectedItems()方法可以获取选中的项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值