Android自定义时间选择器

news2025/1/16 5:41:35

效果图

 

一、添加NumberPicker开源库 

需要添加以下控件 

仓库地址: https://github.com/ShawnLin013/NumberPicker

implementation 'io.github.ShawnLin013:number-picker:2.4.13'

二、 添加弹出框主题样式

在drawable文件夹下新建一个bg_bottom_dialog.xml,添加以下代码:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 角度 -->
    <corners
        android:topLeftRadius="20dp"
        android:topRightRadius="20dp" />
    <!-- 填充色 -->
    <solid android:color="@color/white" />
    <!--内边距-->
    <padding
        android:top="12dp"
        android:left="16dp"
        android:right="16dp"
        android:bottom="16dp" />
</shape>

三、添加时间选择器布局 

在layout文件夹下新建view_time_picker.xml文件,添加以下代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@drawable/bg_bottom_dialog">

    <TextView
        android:id="@+id/cancel"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toTopOf="@id/year"
        android:gravity="center"
        android:text="取消"
        android:textColor="#666666"
        android:clickable="true"
        android:focusable="true" />

    <TextView
        android:id="@+id/title"
        android:layout_width="0dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/cancel"
        app:layout_constraintBottom_toTopOf="@id/year"
        app:layout_constraintRight_toLeftOf="@id/ok"
        android:gravity="center"
        android:text="出生日期"
        android:textColor="#333333"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/ok"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/year"
        android:gravity="center"
        android:text="确定"
        android:textColor="#1580C8"
        android:textStyle="bold"
        android:clickable="true"
        android:focusable="true" />

    <com.shawnlin.numberpicker.NumberPicker
        android:id="@+id/year"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/title"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/month"
        app:np_formatter="%d"
        app:np_dividerColor="#2B000000"
        app:np_dividerThickness="1px"
        app:np_selectedTextColor="#333333"
        app:np_selectedTextSize="18sp"
        app:np_textSize="14sp"
        app:np_wheelItemCount="5"
        app:np_wrapSelectorWheel="false" />

    <com.shawnlin.numberpicker.NumberPicker
        android:id="@+id/month"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/title"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@id/year"
        app:layout_constraintRight_toLeftOf="@id/day"
        app:np_dividerColor="#2B000000"
        app:np_dividerThickness="1px"
        app:np_selectedTextColor="#333333"
        app:np_selectedTextSize="18sp"
        app:np_textSize="14sp"
        app:np_wheelItemCount="5"
        app:np_wrapSelectorWheel="false" />

    <com.shawnlin.numberpicker.NumberPicker
        android:id="@+id/day"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/title"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@id/month"
        app:layout_constraintRight_toRightOf="parent"
        app:np_dividerColor="#2B000000"
        app:np_dividerThickness="1px"
        app:np_selectedTextColor="#333333"
        app:np_selectedTextSize="18sp"
        app:np_textSize="14sp"
        app:np_wheelItemCount="5"
        app:np_wrapSelectorWheel="false" />

</androidx.constraintlayout.widget.ConstraintLayout>

四、添加时间选择器类 

 添加以下类,复制即用

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.onegrid.app.npmn.R;
import com.shawnlin.numberpicker.NumberPicker;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;

/**
 * 时间选择器
 *
 * @author DengLS
 * @date 2023/01/12
 */
public class TimePickerCustom {
    private final BottomSheetDialog bottomDialog;
    private final NumberPicker year;
    private final NumberPicker month;
    private final NumberPicker day;

    /**
     * 时间选择回调
     *
     * @author DengLS
     * @date 2023/01/12
     */
    public interface TimePickerCallback {
        /**
         * 回调
         *
         * @param year 年
         * @param month 月
         * @param day 日
         */
        void setDate(int year, int month, int day);
    }

    public TimePickerCustom(Context context, String title, TimePickerCallback callback) {
        // 设置时间选择器的布局以及弹窗的高度
        bottomDialog = getBottomDialog(context, R.layout.view_time_picker, dpToPx(context, 350));
        Calendar calendar = Calendar.getInstance();
        // 设置标题
        ((TextView)bottomDialog.findViewById(R.id.title)).setText(title);
        // 年
        year = (NumberPicker)bottomDialog.findViewById(R.id.year);
        int yearNow = calendar.get(Calendar.YEAR);
        year.setMinValue(yearNow - 100);
        year.setMaxValue(yearNow + 100);
        year.setValue(yearNow);

        // 月
        month = (NumberPicker)bottomDialog.findViewById(R.id.month);
        String[] monthNum = new String[12];
        for (int i = 0; i < 12; i++) {
            monthNum[i] = (i + 1) + "月";
        }
        month.setMinValue(1);
        month.setMaxValue(monthNum.length);
        month.setDisplayedValues(monthNum);
        month.setValue(calendar.get(Calendar.MONTH));

        // 日
        day = (NumberPicker)bottomDialog.findViewById(R.id.day);
        day.setMinValue(1);
        int days = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        String[] newDays = getNewDays(days);
        day.setMaxValue(calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        day.setDisplayedValues(newDays);
        day.setValue(calendar.get(Calendar.DATE));

        // 年份和月份更改时对应的天数需要更改
        year.setOnValueChangedListener((picker, oldVal, newVal) -> {
            updateNumberOfDays();
            day.setValue(calendar.get(Calendar.DATE));
        });
        month.setOnValueChangedListener((picker, oldVal, newVal) -> {
            updateNumberOfDays();
            day.setValue(calendar.get(Calendar.DATE));
        });

        // 取消按钮和确定按钮事件绑定
        View cancel = bottomDialog.findViewById(R.id.cancel);
        View ok = bottomDialog.findViewById(R.id.ok);
        if (cancel != null) {
            cancel.setOnClickListener(v -> bottomDialog.dismiss());
        }
        if (ok != null) {
            ok.setOnClickListener(v -> {
                bottomDialog.dismiss();
                callback.setDate(year.getValue(), month.getValue(), day.getValue());
            });
        }
    }

    /**
     * 底部弹出框
     *
     * @param id 弹窗中的布局
     * @param height 弹窗高度
     */
    private BottomSheetDialog getBottomDialog(Context context, Integer id, int height) {
        BottomSheetDialog bottomSheet = new BottomSheetDialog(context);
        // 设置对框框中的布局
        bottomSheet.setContentView(id);
        // 设置点击外部是否可以取消
        bottomSheet.setCancelable(true);
        FrameLayout bottom = (FrameLayout)bottomSheet.findViewById(R.id.design_bottom_sheet);
        if (bottom != null) {
            // 设置背景透明颜色
            bottom.setBackgroundResource(R.color.transparent);
            // 修改弹窗的高度
            ViewGroup.LayoutParams layoutParams = bottom.getLayoutParams();
            layoutParams.height = height;
            bottom.setLayoutParams(layoutParams);
        }
        return bottomSheet;
    }

    /**
     * dp转px
     */
    private int dpToPx(Context context, float dp) {
        return (int)(dp * context.getResources().getDisplayMetrics().density + 0.5);
    }

    /**
     * 显示
     */
    public void show() {
        bottomDialog.show();
    }

    /**
     * 设置选中年份
     *
     * @param yearValue 年
     */
    public void setYearValue(int yearValue) {
        year.setValue(yearValue);
        updateNumberOfDays();
    }

    /**
     * 设置选中月份
     *
     * @param monthValue 月
     */
    public void setMonthValue(int monthValue) {
        month.setValue(monthValue);
        updateNumberOfDays();
    }

    /**
     * 设置选中天数
     *
     * @param dayValue 天
     */
    public void setDayValue(int dayValue) {
        day.setValue(dayValue);
    }

    /**
     * 更新天数
     *
     */
    private void updateNumberOfDays() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year.getValue());
        calendar.set(Calendar.MONTH, (month.getValue() - 1));
        calendar.set(Calendar.DATE, 1);
        calendar.roll(Calendar.DATE, -1);
        int date = calendar.get(Calendar.DATE);
        day.setMaxValue(date);
        day.setDisplayedValues(getNewDays(date));
    }

    /**
     * 格式化天数
     *
     * @param days 天数
     * @return {@link String[]}
     */
    private String[] getNewDays(int days) {
        List<String> dayList = new ArrayList<>();
        for (int i = 0; i < days; i++) {
            dayList.add((i + 1) + "日");
        }
        return dayList.toArray(new String[dayList.size()]);
    }
}

 五、使用

TimePickerCustom timePickerCustom = new TimePickerCustom(context, "标题", (year, month, day) -> {
    // 确定按钮的回调
    Log.i("timePickerCustom", year + "------" + month + "--------" + day);
});
// 弹出
timePickerCustom.show();

👍点赞,你的认可是我创作的动力 !
🌟收藏,你的青睐是我努力的方向!
✏️评论,你的意见是我进步的财富!    

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jenkins结合gitlable企业集成部署实战

简介 Jenkins是一个开源软件项目&#xff0c;起源于Hudson&#xff08;Hudson是商用的&#xff09;&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成 1.0 …

新的跨平台渲染引擎:Ab3d.DXEngine 5.2 Crack

用于 WPF 和 WinForms 的 DirectX 11 3D 渲染引擎 Ab3d.DXEngine 是一种超快的 3D 渲染引擎&#xff0c;可用于 .Net 桌面应用程序。采集 by Ω578867473 Ab3d.DXEngine采用超快的多线程渲染技术&#xff0c;可以充分利用显卡&#xff0c;提供与使用C时几乎相同的极致性能。 该…

javaEE 初阶 — 线程安全的集合类

文章目录1. 多线程环境使用 ArrayList多线程使用队列3. 多线程环境使用哈希表3.1 Hashtable3.2 ConcurrentHashMap4. 相关面试题1. 多线程环境使用 ArrayList java 标准库里的大部分集合类都是 “线程不安全” 的。 多个线程使用同一个集合类对象&#xff0c;很有可能会出问题。…

WebDAV之葫芦儿·派盘+Air Explorer

Air Explorer 支持WebDAV方式连接葫芦儿派盘。 电脑本地硬盘不够,网盘云存储已经成为存储的一种趋势。网盘限额,数据存在多个网盘内,操作麻烦还费事。 Airexplorer可以完美解决这个困扰。Air Explorer是一款非常不错的云存储账户管理软件,常见的在线云存储服务器都支持;还…

六道算法基础题详解

目录 1.力扣第217题&#xff1a;存在重复元素 2.力扣第53题&#xff1a;最大子数组和 3.力扣第1题&#xff1a;两数之和 4.力扣第88题&#xff1a;合并两个有序数组 5.牛客BM1题&#xff1a;反转链表 6.牛客BM2题&#xff1a;链表内指定区间反转 1.力扣第217题&#xff1…

6.1、应用层概述

1、基本概述 应用层是计算机网络体系结构的最顶层\color{red}最顶层最顶层&#xff0c;是设计和建立计算机网络的最终目的\color{red}设计和建立计算机网络的最终目的设计和建立计算机网络的最终目的&#xff0c;也是计算机网络中发展最快的部分。 早期基于文本的应用(电子邮件…

RNNoise:学习噪声抑制

目录 1. RNNoise简介 2. 噪声抑制 3. 深度学习和循环神经网络 4. 一种混合的方法 6. 关于数据集 7. 从python到C语言 8. 其他资源 RNNoise&#xff1a;学习噪声抑制 原文地址&#xff1a;RNNoise: Learning Noise Suppression (jmvalin.ca) 1. RNNoise简介 该例子展示…

共享购深度解析——新玩法解读

共享经济模式以合理配置网络资源、减少销售市场交易费用、推动私营经济强势来袭等优点颠覆性创新地严重影响传统商业模式&#xff0c;根据“自由者”的协同&#xff0c;共享经济模式给供需彼此更自由选择和由上而下的制度变革&#xff0c;提高了经济形势高效率&#xff0c;变成…

Pytorch 环境和分布偏移与错误使用机器学习例子

假设我们训练了一个贷款申请人违约风险模型&#xff0c;用来预测谁将偿还贷款或违约。 这个模型发现申请人的鞋子与违约风险相关&#xff08;穿牛津鞋申请人会偿还&#xff0c;穿运动鞋申请人会违约&#xff09;。 此后&#xff0c;这个模型可能倾向于向所有穿着牛津鞋的申请人…

代码随想录算法训练营第十六天二叉树 java : 104.二叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数

文章目录前言深度是个啥&#xff0c;高度又是啥Leetcode 104.二叉树的最大深度题目讲解Leetcode 111.二叉树的最小深度题目讲解Leetcode 222.完全二叉树的节点个数&#xff08;优先掌握递归题目讲解总结前言 今天将主要围绕 深度和高度 来展开 复习一下递归三部曲 确定递归函…

已解决微软Office2016 Excel卡顿\缓慢、打开第二个文件加载很慢问题(亲测有效)

已解决微软Office2016 Excel卡顿\缓慢、打开第二个文件加载很慢问题&#xff08;亲测有效&#xff09; 文章目录问题描述问题分析解决方法1解决方法2解决方法31) 修改基本设置2&#xff09;修改配置文件问题描述 我的电脑环境是&#xff1a;Windows 10 Excel 2016版本。 文件…

【前端之旅】Nginx快速入门

一名软件工程专业学生的前端之旅,记录自己对三件套(HTML、CSS、JavaScript)、Jquery、Ajax、Axios、Bootstrap、Node.js、Vue、小程序开发(Uniapp)以及各种UI组件库、前端框架的学习。 【前端之旅】Web基础与开发工具 【前端之旅】手把手教你安装VS Code并附上超实用插件…

【Blender UV映射02】智能UV映射 创建和应用法线纹理

写在前面 前面的学习记录&#xff1a; 【Blende UV映射01】创建UV 使用UV贴图处理纹理 依旧是跟着Blender 2.8 UV Mapping教程&#xff0c;本文是教程的P8-P12的过程记录。 1 一些操作记录 调整滚轮缩放 如果发现Blender缩放过快&#xff0c; 键盘的"/"数字键…

Java并发编程实战 学习笔记 Day7

并发编程是比较进阶的知识&#xff0c;涉及到很多底层的东西&#xff0c;学习起来是比较困难的。并发编程的bug更多的是偶发性的&#xff0c;很难复现&#xff0c;排查起来也很困难&#xff0c;要想快速解决问题&#xff0c;就要理解并发编程的本质&#xff0c;追本溯源&#x…

Android ANR bugreport log分析

最近工作中频繁遇到设备ANR问题&#xff0c;而且是概率性的那种&#xff0c;于是决定花点时间找找规律复现分析下 说道这里&#xff0c;抓日志是问题解决的最有效途径&#xff0c;这里不得不说一下 bugreport log,其实网上关于它的分析方法有很多&#xff0c;在此仅仅是为了记录…

小型水库在线监测解决方案

一、方案背景水利部全国水利普查显示我国共有水库98002座&#xff0c;其中小型水库93308座。水库对防汛减灾、供水保障和农业灌溉等至关重要&#xff0c;水库的稳定运行关系到下游人民群众的生命财产安全&#xff0c;关系到当地经济发展和社会稳定。在2020年11月18日国务院常务…

EasyVim:简单强大的VIM配置

EasyVim 简单强大的vim配置&#xff0c;熟练后可大大提高开发效率&#xff08;VS Code的两倍以上&#xff09;。 安装 安装过程需要从github下载很多插件&#xff0c;国内尽量挂VPN git clone https://github.com/yuesong-feng/EasyVim cd EasyVim/ sh ./install.sh vim :P…

JavaScript基础(16)_数组方法、数组遍历、foreach

数组方法unshift():向数组开头添加一个或多个元素&#xff0c;并返回新的数组长度。向前边插入元素以后&#xff0c;其他的元素索引会依次调整。push():向数组的末尾添加一个或多个元素&#xff0c;并返回数组新的长度。该方法会将数组新的长度作为返回值返回。shift():删除数组…

【工具推荐】 Obsidian 插件 Obsidian to Flomo 一键同步内容到 Flomo 插件

目录一、Obsidian、Flomo、Obsidian to Flomo 他们都是什么&#xff1f;1. 什么是 Obsidian &#xff1f;2. 什么是Flomo &#xff1f;3. 什么是Obsidian to Flomo &#xff1f;二、如何安装 Obsidian to Flomo &#xff1f;三、插件使用方法1. 启用插件并配置API四、如何使用插…

《2022大数据产业年度创新技术突破》榜重磅发布丨金猿奖

‍年度金猿榜单/奖项本届“数据猿年度金猿策划活动——2022大数据产业创新技术突破榜单/奖项”由金猿&数据猿共同推出。‍数据智能产业创新服务媒体——聚焦数智 改变商业2022年下半年度&#xff0c;由数据猿、金猿组委会共同推出的第五届 “年度金猿季大型主题策划活动”…