Flutter 组件抽取:日期(DatePicker)、时间(TimePicker)弹窗选择器【仿照】

简介

仿照《Flutter 仿ios自定义一个DatePicker》实行的日期弹窗选择器(DatePicker)、时间弹窗选择器(TimePicker)

效果

在这里插入图片描述

范例

class _TestPageState extends State<TestPage> {
  
  void initState() {
    super.initState();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Picker')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            GestureDetector(
              child: Container(
                alignment: Alignment.center,
                width: 160,
                height: 60,
                child: const Text('日期选择(年月日)'),
              ),
              onTap: () {
                DatePicker.show(
                  context,
                  startDate: DateTime(2022, 2, 2),
                  selectedDate: DateTime(2023, 3, 3),
                  endDate: DateTime(2025, 5, 5),
                  onSelected: (date) {
                    MsgUtil.toast(date.toString());
                  },
                );
              },
            ),
            GestureDetector(
              child: Container(
                alignment: Alignment.center,
                width: 160,
                height: 60,
                child: const Text('日期选择(年月)'),
              ),
              onTap: () {
                DatePicker.show(
                  context,
                  hideDay: true,
                  startDate: DateTime(2022, 2),
                  selectedDate: DateTime(2023, 3),
                  endDate: DateTime(2025, 5),
                  onSelected: (date) {
                    MsgUtil.toast(date.toString());
                  },
                );
              },
            ),
            GestureDetector(
              child: Container(
                alignment: Alignment.center,
                width: 160,
                height: 60,
                child: const Text('时间选择(时分秒)'),
              ),
              onTap: () {
                TimePicker.show(
                  context,
                  startTime: TimeData(11, 11, 11),
                  selectedTime: TimeData(15, 15, 15),
                  endTime: TimeData(22, 22, 22),
                  onSelected: (time) {
                    MsgUtil.toast(time.toString());
                  },
                );
              },
            ),
            GestureDetector(
              child: Container(
                alignment: Alignment.center,
                width: 160,
                height: 60,
                child: const Text('时间选择(时分)'),
              ),
              onTap: () {
                TimePicker.show(
                  context,
                  hideSecond: true,
                  startTime: TimeData(11, 11),
                  selectedTime: TimeData(15, 15),
                  endTime: TimeData(22, 22),
                  onSelected: (time) {
                    MsgUtil.toast(time.toString());
                  },
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

说明(DatePicker)

1、支持选中日期(selectedDate)、开始日期(startDate)、结束日期(endDate)的配置
2、支持“年月日”的选择,也支持“年月”的选择

代码(DatePicker)

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

typedef OnSelected = Function(DateTime date);

class DatePicker extends StatefulWidget {
  static void show(
    BuildContext context, {
    DateTime? startDate,
    DateTime? endDate,
    DateTime? selectedDate,
    bool hideDay = false,
    Function()? onCancel,
    required OnSelected onSelected,
  }) async {
    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.transparent,
      builder: (BuildContext context) {
        return ClipRRect(
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(8),
            topRight: Radius.circular(8),
          ),
          child: DatePicker._(
            selectedDate: selectedDate,
            startDate: startDate,
            endDate: endDate,
            onSelected: onSelected,
            hideDay: hideDay,
          ),
        );
      },
    ).then((value) => onCancel?.call());
  }

  const DatePicker._({
    this.selectedDate,
    this.startDate,
    this.endDate,
    this.hideDay = false,
    required this.onSelected,
  });

  final DateTime? selectedDate;
  final DateTime? startDate;
  final DateTime? endDate;
  final bool hideDay;
  final OnSelected onSelected;

  
  State createState() => _DatePickerState();
}

class _DatePickerState extends State<DatePicker> {
  late FixedExtentScrollController yearScrollController;
  late FixedExtentScrollController monthScrollController;
  late FixedExtentScrollController dayScrollController;

  List<String> yearList = []; // 年数组
  List<String> monthList = []; // 月数组
  List<String> dayList = []; // 天数组

  int yearIndex = 0; // 年的索引
  int monthIndex = 0; // 月的索引
  int dayIndex = 0; //天的索引

  late DateTime startDate;
  late DateTime endDate;
  late DateTime selectedDate;

  final double itemExtent = 44;

  /// 初始化数据
  void initData() {
    // 初始化年份数
    for (int i = startDate.year; i <= endDate.year; i++) {
      yearList.add(i.toString());
    }
    int selectYear = selectedDate.year;
    int selectMonth = selectedDate.month;
    // 初始化月份数
    monthList = getMonthList(selectYear);
    // 初始化天数
    dayList = getDayList(selectYear, selectMonth);
    // 初始化时间索引
    final List uniqueYearList = Set.from(yearList).toList();
    final List uniqueMonthList = Set.from(monthList).toList();
    final List uniqueDayList = Set.from(dayList).toList();
    // 获取索引
    setState(() {
      yearIndex = uniqueYearList.indexOf("${selectedDate.year}");
      monthIndex = uniqueMonthList.indexOf("${selectedDate.month}");
      dayIndex = uniqueDayList.indexOf("${selectedDate.day}");
    });
    // 设置Picker初始值
    yearScrollController = FixedExtentScrollController(initialItem: yearIndex);
    monthScrollController = FixedExtentScrollController(initialItem: monthIndex);
    dayScrollController = FixedExtentScrollController(initialItem: dayIndex);
  }

  List<String> getMonthList(int selectYear) {
    List<String> monthList = [];
    if (selectYear == startDate.year) {
      for (int i = startDate.month; i <= 12; i++) {
        monthList.add(i.toString());
      }
    } else if (selectYear == endDate.year) {
      for (int i = 1; i <= endDate.month; i++) {
        monthList.add(i.toString());
      }
    } else {
      for (int i = 1; i <= 12; i++) {
        monthList.add(i.toString());
      }
    }
    return monthList;
  }

  List<String> getDayList(int selectYear, int selectMonth) {
    List<String> dayList = [];
    int days = getDayCount(selectYear, selectMonth);
    if (selectYear == startDate.year && selectMonth == startDate.month) {
      for (int i = startDate.day; i <= days; i++) {
        dayList.add(i.toString());
      }
    } else if (selectYear == endDate.year && selectMonth == endDate.month) {
      for (int i = 1; i <= endDate.day; i++) {
        dayList.add(i.toString());
      }
    } else {
      for (int i = 1; i <= days; i++) {
        dayList.add(i.toString());
      }
    }
    return dayList;
  }

  int getDayCount(int year, int month) {
    int dayCount = DateTime(year, month + 1, 0).day;
    return dayCount;
  }

  /// 选中年月后更新天
  void updateDayList() {
    int year = int.parse(yearList[yearIndex]);
    int month = int.parse(monthList[monthIndex]);
    setState(() {
      dayIndex = 0;
      dayList = getDayList(year, month);
      if (dayScrollController.positions.isNotEmpty) {
        dayScrollController.jumpTo(0);
      }
    });
  }

  /// 选中年后更新月
  void updateMonthList() {
    int selectYear = int.parse(yearList[yearIndex]);
    setState(() {
      monthIndex = 0;
      monthList = getMonthList(selectYear);
      if (monthScrollController.positions.isNotEmpty) {
        monthScrollController.jumpTo(0);
      }
    });
  }

  
  void initState() {
    super.initState();
    startDate = widget.startDate ?? DateTime(1970, 1, 1);
    endDate = widget.endDate ?? DateTime(2099, 1, 1);
    selectedDate = widget.selectedDate ?? DateTime.now();
    if (endDate.difference(startDate).inSeconds < 0) {
      endDate = startDate;
    }
    if (selectedDate.difference(startDate).inSeconds < 0) {
      selectedDate = startDate;
    }
    if (selectedDate.difference(endDate).inSeconds > 0) {
      selectedDate = endDate;
    }
    initData();
  }

  
  void dispose() {
    yearScrollController.dispose();
    monthScrollController.dispose();
    dayScrollController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Container(
            color: Colors.white,
            width: double.maxFinite,
            height: 200,
            child: Stack(
              alignment: AlignmentDirectional.center,
              children: [
                Container(
                  width: MediaQuery.of(context).size.width - 32,
                  height: itemExtent - 8,
                  decoration: BoxDecoration(
                    color: const Color(0xFFF1F1F1),
                    borderRadius: BorderRadius.circular(12),
                  ),
                ),
                Positioned(
                  left: 20,
                  right: 20,
                  top: 0,
                  bottom: 0,
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      Expanded(child: yearPickerView()),
                      Expanded(child: monthPickerView()),
                      widget.hideDay
                          ? const SizedBox()
                          : Expanded(child: dayPickerView()),
                    ],
                  ),
                ),
              ],
            ),
          ),
          Container(
            color: Colors.white,
            height: 68,
            padding: const EdgeInsets.only(left: 16, right: 16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Expanded(
                  child: TextButton(
                    child: const Text('取 消'),
                    onPressed: () {
                      Navigator.pop(context, false);
                    },
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: TextButton(
                    child: const Text('确 定'),
                    onPressed: () {
                      Navigator.pop(context, true);
                      widget.onSelected.call(DateTime(
                        int.parse(yearList[yearIndex]),
                        int.parse(monthList[monthIndex]),
                        int.parse(dayList[dayIndex]),
                      ));
                    },
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: MediaQuery.of(context).padding.bottom),
        ],
      ),
    );
  }

  /// 年Picker
  Widget yearPickerView() {
    return buildPickerBorder(
      child: CupertinoPicker(
        scrollController: yearScrollController,
        looping: false,
        selectionOverlay: const Center(),
        onSelectedItemChanged: (index) {
          setState(() {
            yearIndex = index;
          });
          updateMonthList();
          updateDayList();
        },
        itemExtent: itemExtent,
        children: buildYearWidget(),
      ),
    );
  }

  /// 月Picker
  Widget monthPickerView() {
    return buildPickerBorder(
      child: CupertinoPicker(
        scrollController: monthScrollController,
        looping: false,
        selectionOverlay: const Center(),
        onSelectedItemChanged: (index) {
          setState(() {
            monthIndex = index;
          });
          updateDayList();
        },
        itemExtent: itemExtent,
        children: buildMonthWidget(),
      ),
    );
  }

  /// 日Picker
  Widget dayPickerView() {
    return buildPickerBorder(
      child: CupertinoPicker(
        scrollController: dayScrollController,
        looping: false,
        selectionOverlay: const Center(),
        onSelectedItemChanged: (index) {
          setState(() {
            dayIndex = index;
          });
        },
        itemExtent: itemExtent,
        children: buildDayWidget(),
      ),
    );
  }

  /// 年Widget
  List<Widget> buildYearWidget() {
    List<Widget> widgets = [];
    for (var i = 0; i < yearList.length; i++) {
      widgets.add(
        Center(
          child: Text(
            '${yearList[i]}年',
            style: getTextStyle(i == yearIndex),
            maxLines: 1,
          ),
        ),
      );
    }
    return widgets;
  }

  /// 月Widget
  List<Widget> buildMonthWidget() {
    List<Widget> widgets = [];
    for (var i = 0; i < monthList.length; i++) {
      widgets.add(
        Center(
          child: Text(
            // monthList[i].padLeft(2, '0')
            '${monthList[i]}月',
            style: getTextStyle(i == monthIndex),
            maxLines: 1,
          ),
        ),
      );
    }
    return widgets;
  }

  /// 日Widget
  List<Widget> buildDayWidget() {
    List<Widget> widgets = [];
    for (var i = 0; i < dayList.length; i++) {
      widgets.add(
        Center(
          child: Text(
            // dayList[i].padLeft(2, '0')
            '${dayList[i]}日',
            style: getTextStyle(i == dayIndex),
            maxLines: 1,
          ),
        ),
      );
    }
    return widgets;
  }

  TextStyle getTextStyle(bool bold) {
    return TextStyle(
      color: Colors.black,
      fontSize: 20,
      height: 1,
      fontWeight: bold ? FontWeight.w600 : FontWeight.w400,
    );
  }

  Widget buildPickerBorder({required Widget child}) {
    return Stack(
      alignment: AlignmentDirectional.center,
      children: [
        /*Container(
          width: 90,
          height: itemExtent - 8,
          decoration: BoxDecoration(
            color: const Color(0xffEFEFF0),
            borderRadius: BorderRadius.circular(10),
          ),
        ),*/
        child,
      ],
    );
  }
}

说明(TimePicker)

1、支持选中时间(selectedtTime)、开始时间(starttTime)、结束时间(endtTime)的配置
2、支持“时分秒”的选择,也支持“时分”的选择
3、自定义时间数据类(TimeData)

代码(TimePicker)

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

typedef OnSelected = Function(TimeData time);
typedef PickerBuilder = Widget Function(BuildContext context);

class TimeData {
  final int hour;
  final int minute;
  final int second;

  TimeData(this.hour, [this.minute = 0, this.second = 0])
      : assert(hour >= 0 && hour <= 23),
        assert(minute >= 0 && minute <= 59),
        assert(second >= 0 && second <= 59);

  factory TimeData.now() {
    var now = DateTime.now();
    return TimeData(now.hour, now.minute, now.second);
  }

  bool precede(TimeData other) {
    return (hour < other.hour) ||
        (hour == other.hour && minute < other.minute) ||
        (hour == other.hour && minute == other.minute && second < other.second);
  }

  
  String toString() {
    return '$hour:$minute:$second';
  }
}

class TimePicker extends StatefulWidget {
  static void show(
    BuildContext context, {
    TimeData? startTime,
    TimeData? endTime,
    TimeData? selectedTime,
    bool hideSecond = false,
    Function()? onCancel,
    required OnSelected onSelected,
  }) async {
    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.transparent,
      builder: (BuildContext context) {
        return ClipRRect(
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(8),
            topRight: Radius.circular(8),
          ),
          child: TimePicker._(
            selectedTime: selectedTime,
            startTime: startTime,
            endTime: endTime,
            hideSecond: hideSecond,
            onSelected: onSelected,
          ),
        );
      },
    ).then((value) => onCancel?.call());
  }

  const TimePicker._({
    this.selectedTime,
    this.startTime,
    this.endTime,
    this.hideSecond = false,
    required this.onSelected,
  });

  final TimeData? selectedTime;
  final TimeData? startTime;
  final TimeData? endTime;
  final bool hideSecond;
  final OnSelected onSelected;

  
  State createState() => _TimePickerState();
}

class _TimePickerState extends State<TimePicker> {
  late FixedExtentScrollController hourScrollController;
  late FixedExtentScrollController minuteScrollController;
  late FixedExtentScrollController secondScrollController;

  List<String> hourList = [];
  List<String> minuteList = [];
  List<String> secondList = [];

  int hourIndex = 0;
  int minuteIndex = 0;
  int secondIndex = 0;

  late TimeData startTime;
  late TimeData endTime;
  late TimeData selectedTime;

  final double itemExtent = 44;

  /// 初始化数据
  void initData() {
    // 初始化时
    for (int i = startTime.hour; i <= endTime.hour; i++) {
      hourList.add(i.toString());
    }
    int selectHour = selectedTime.hour;
    int selectMinute = selectedTime.minute;
    // 初始化分
    minuteList = getMinuteList(selectHour);
    // 初始化秒
    secondList = getSecondList(selectHour, selectMinute);
    // 初始化时间索引
    final List uniqueHourList = Set.from(hourList).toList();
    final List uniqueMinuteList = Set.from(minuteList).toList();
    final List uniqueSecondList = Set.from(secondList).toList();
    // 获取索引
    setState(() {
      hourIndex = uniqueHourList.indexOf("${selectedTime.hour}");
      minuteIndex = uniqueMinuteList.indexOf("${selectedTime.minute}");
      secondIndex = uniqueSecondList.indexOf("${selectedTime.second}");
    });
    // 设置Picker初始值
    hourScrollController = FixedExtentScrollController(initialItem: hourIndex);
    minuteScrollController = FixedExtentScrollController(initialItem: minuteIndex);
    secondScrollController = FixedExtentScrollController(initialItem: secondIndex);
  }

  List<String> getMinuteList(int selectHour) {
    List<String> list = [];
    if (selectHour == startTime.hour) {
      for (int i = startTime.minute; i <= 59; i++) {
        list.add(i.toString());
      }
    } else if (selectHour == endTime.hour) {
      for (int i = 0; i <= endTime.minute; i++) {
        list.add(i.toString());
      }
    } else {
      for (int i = 0; i <= 59; i++) {
        list.add(i.toString());
      }
    }
    return list;
  }

  List<String> getSecondList(int selectHour, int selectMinute) {
    List<String> list = [];
    if (selectHour == startTime.hour && selectMinute == startTime.minute) {
      for (int i = startTime.second; i <= 59; i++) {
        list.add(i.toString());
      }
    } else if (selectHour == endTime.hour && selectMinute == endTime.minute) {
      for (int i = 0; i <= endTime.second; i++) {
        list.add(i.toString());
      }
    } else {
      for (int i = 0; i <= 59; i++) {
        list.add(i.toString());
      }
    }
    return list;
  }

  /// 选中时分后更新秒
  void updateSecondList() {
    int hour = int.parse(hourList[hourIndex]);
    int minute = int.parse(minuteList[minuteIndex]);
    setState(() {
      secondIndex = 0;
      secondList = getSecondList(hour, minute);
      if (secondScrollController.positions.isNotEmpty) {
        secondScrollController.jumpTo(0);
      }
    });
  }

  /// 选中时后更新分
  void updateMinuteList() {
    int selectHour = int.parse(hourList[hourIndex]);
    setState(() {
      minuteIndex = 0;
      minuteList = getMinuteList(selectHour);
      if (minuteScrollController.positions.isNotEmpty) {
        minuteScrollController.jumpTo(0);
      }
    });
  }

  
  void initState() {
    super.initState();
    DateTime now = DateTime.now();
    startTime = widget.startTime ?? TimeData(0, 0, 0);
    endTime = widget.endTime ?? TimeData(23, 59, 59);
    selectedTime = widget.selectedTime ?? TimeData(now.hour, now.minute, now.second);
    if (endTime.precede(startTime)) {
      endTime = startTime;
    }
    if (selectedTime.precede(startTime)) {
      selectedTime = startTime;
    }
    if (endTime.precede(selectedTime)) {
      selectedTime = endTime;
    }
    initData();
  }

  
  void dispose() {
    hourScrollController.dispose();
    minuteScrollController.dispose();
    secondScrollController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Container(
            color: Colors.white,
            width: double.maxFinite,
            height: 200,
            child: Stack(
              alignment: AlignmentDirectional.center,
              children: [
                Container(
                  width: MediaQuery.of(context).size.width - 32,
                  height: itemExtent - 8,
                  decoration: BoxDecoration(
                    color: const Color(0xFFF1F1F1),
                    borderRadius: BorderRadius.circular(12),
                  ),
                ),
                Positioned(
                  left: 20,
                  right: 20,
                  top: 0,
                  bottom: 0,
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      Expanded(child: hourPickerView()),
                      Expanded(child: minutePickerView()),
                      widget.hideSecond
                          ? const SizedBox()
                          : Expanded(child: secondPickerView()),
                    ],
                  ),
                ),
              ],
            ),
          ),
          Container(
            color: Colors.white,
            height: 68,
            padding: const EdgeInsets.only(left: 16, right: 16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Expanded(
                  child: TextButton(
                    child: const Text('取 消'),
                    onPressed: () {
                      Navigator.pop(context, false);
                    },
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: TextButton(
                    child: const Text('确 定'),
                    onPressed: () {
                      Navigator.pop(context, true);
                      widget.onSelected.call(TimeData(
                        int.parse(hourList[hourIndex]),
                        int.parse(minuteList[minuteIndex]),
                        int.parse(secondList[secondIndex]),
                      ));
                    },
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: MediaQuery.of(context).padding.bottom),
        ],
      ),
    );
  }

  /// 时Picker
  Widget hourPickerView() {
    return buildPickerBorder(
      child: CupertinoPicker(
        scrollController: hourScrollController,
        looping: false,
        selectionOverlay: const Center(),
        onSelectedItemChanged: (index) {
          setState(() {
            hourIndex = index;
          });
          updateMinuteList();
          updateSecondList();
        },
        itemExtent: itemExtent,
        children: buildHourWidget(),
      ),
    );
  }

  /// 分Picker
  Widget minutePickerView() {
    return buildPickerBorder(
      child: CupertinoPicker(
        scrollController: minuteScrollController,
        looping: false,
        selectionOverlay: const Center(),
        onSelectedItemChanged: (index) {
          setState(() {
            minuteIndex = index;
          });
          updateSecondList();
        },
        itemExtent: itemExtent,
        children: buildMinuteWidget(),
      ),
    );
  }

  /// 秒Picker
  Widget secondPickerView() {
    return buildPickerBorder(
      child: CupertinoPicker(
        scrollController: secondScrollController,
        looping: false,
        selectionOverlay: const Center(),
        onSelectedItemChanged: (index) {
          setState(() {
            secondIndex = index;
          });
        },
        itemExtent: itemExtent,
        children: buildSecondWidget(),
      ),
    );
  }

  /// 时Widget
  List<Widget> buildHourWidget() {
    List<Widget> widgets = [];
    for (var i = 0; i < hourList.length; i++) {
      widgets.add(
        Center(
          child: Text(
            // hourList[i].padLeft(2, '0')
            '${hourList[i]}时',
            style: getTextStyle(i == hourIndex),
            maxLines: 1,
          ),
        ),
      );
    }
    return widgets;
  }

  /// 分Widget
  List<Widget> buildMinuteWidget() {
    List<Widget> widgets = [];
    for (var i = 0; i < minuteList.length; i++) {
      widgets.add(
        Center(
          child: Text(
            // minuteList[i].padLeft(2, '0')
            '${minuteList[i]}分',
            style: getTextStyle(i == minuteIndex),
            maxLines: 1,
          ),
        ),
      );
    }
    return widgets;
  }

  /// 秒Widget
  List<Widget> buildSecondWidget() {
    List<Widget> widgets = [];
    for (var i = 0; i < secondList.length; i++) {
      widgets.add(
        Center(
          child: Text(
            // secondList[i].padLeft(2, '0')
            '${secondList[i]}秒',
            style: getTextStyle(i == secondIndex),
            maxLines: 1,
          ),
        ),
      );
    }
    return widgets;
  }

  TextStyle getTextStyle(bool bold) {
    return TextStyle(
      color: Colors.black,
      fontSize: 20,
      height: 1,
      fontWeight: bold ? FontWeight.w600 : FontWeight.w400,
    );
  }

  Widget buildPickerBorder({required Widget child}) {
    return Stack(
      alignment: AlignmentDirectional.center,
      children: [
        /*Container(
          width: 90,
          height: itemExtent - 8,
          decoration: BoxDecoration(
            color: const Color(0xffEFEFF0),
            borderRadius: BorderRadius.circular(10),
          ),
        ),*/
        child,
      ],
    );
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ros基础笔记

1创建工作空间 catkin_init_workspace 将文件夹初始化成ros文件 编译工作空间catkin_make vi ~/.bashrc 加入环境变量bashrc一下在任何终端都生效 catkin_create_pkg learning_communication通讯机制 std_msgs数据结构 rospy roscpp catkin_create_pkg mbot_description ur…

SpringBoot实现导出Excel功能

1 问题背景 需求要做一个导出excel的功能 2 前言 本篇着重阐述后端怎么实现&#xff0c;前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的&#xff0c;不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。再次声明&#xff0c;…

题目 3166: 蓝桥杯2023年第十四届省赛真题-阶乘的和--不能完全通过,最好情况通过67.

原题链接&#xff1a; 题目 3166: 蓝桥杯2023年第十四届省赛真题-阶乘的和 https://www.dotcpp.com/oj/problem3166.html 致歉 害&#xff0c;首先深感抱歉&#xff0c;这道题还是没有找到很好的解决办法。目前最好情况就是67分。 这道题先这样跳过吧&#xff0c;当然以后还…

day9 实现UDP通信

目录 socket函数拓展 UDP通信实现过程 代码实现 socket函数拓展 send与recv函数&#xff1a; /*用于发送数据*/ ssize_t send(int sockfd, const void *buf, size_t len,int flags);/*用于接收数据*/ ssize_t recv(int sockfd, void *buf, size_t len,int flags);/*前三个…

【Python习题集5】函数的设计

函数的设计 一、实验内容二、实验总结 一、实验内容 1.编写两个函数分别按单利和复利计算利息&#xff0c;根据本金、年利率、存款年限得到本息和和利息。调用这两个函数计算1000元在银行存3年&#xff0c;在年利率是6%的情况下&#xff0c;单利和复利分别获得的本息和和利息。…

程序员不得不知道的 API 接口常识

1、初识 API 接口 记得在我初学 web 开发的时候&#xff0c;后端框架相关的教程基本都会教学生写渲染模版&#xff08;不分语言&#xff09;&#xff0c;也就是说后端返回的是整个网页的数据&#xff0c;浏览器只负责渲染。 一般这类模版在后端都会对应一个路由&#xff0c;比…

Vue——组合式函数

目录 什么是“组合式函数”&#xff1f;​ 鼠标跟踪器示例​ 异步状态示例​ 约定和最佳实践​ 命名​ 输入参数​ 返回值​ 副作用​ 使用限制​ 通过抽取组合式函数改善代码结构 选项式 API 中使用组合式函数​ 与其他模式的比较​ 和 Mixin 的对比​ 和无渲染…

计算机视觉的应用3-批量图片风格迁移之素描图片生成的应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用3-批量图片生成素描图片的应用&#xff0c;将一张图像转换为素描风格的图像的其实是模拟了人类视觉在观察物体时受到的光照条件。素描风格的图像在灰度值上表现出明暗交替的效果&#xff0c;这种效…

渗透测试 | 目录扫描

0x00 免责声明 本文仅限于学习讨论与技术知识的分享&#xff0c;不得违反当地国家的法律法规。对于传播、利用文章中提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;本文作者不为此承担任何责任&#xff0c;一旦造成后果请自行承担…

electron源码保护

electron 程序发布后&#xff0c;如果未对程序做保护&#xff0c;则极容易受到破坏&#xff0c;比如被轻松破解密码&#xff0c;或者被修改程序&#xff0c;所以必须对程序做一些安全防护。虽然没有100%的安全防护&#xff0c;但是提升破解难度&#xff0c;直至破解代价超出了范…

MyBatis:使用代码整合

文章目录 MyBatis&#xff1a;Day 04框架1. 依赖&#xff1a;pom.xml2. 外部配置文件&#xff1a;db.properties3. 核心配置文件&#xff1a;mybatis-config.xml4. 实体类5. 接口&#xff1a;xxxMapper.java6. 实现类&#xff1a;xxxMapper.xml7. 测试 MyBatis&#xff1a;Day …

利用C#实现动态替换桌面快捷方式对应的应用程序

公司有一个特殊的业务可能会用到这个&#xff0c;至于什么业务就不展开了。本文的内容作为备用方案。 实现思路&#xff1a; 1 获取当前exe程序运行的全路径 2 获取桌面的所有快捷方式 3 遍历快捷方式&#xff0c;获取快捷键方式对应程序的运行路径&#xff0c;并与当前…

Java编程中的20种常见异常及其原因,你知道多少

本文介绍了在Java编程中可能遇到的20种常见异常&#xff0c;包括空指针异常、类未找到异常、数组下标越界异常等&#xff0c;并简要解释了每种异常发生的原因。这些异常可能由于编程错误、运行时资源不足或权限受限等多种原因触发&#xff0c;了解它们有助于更高效地进行程序调…

黑马程序员Dubbo快速入门,Java分布式框架dubbo教程

分布式系统中的相关概念 &#xff08;一&#xff09;互联网项目架构目标-特点 &#xff08;二&#xff09;互联网项目架构目标-目标 &#xff08;三&#xff09;集群和分布式 &#xff08;四&#xff09;架构演进 Dubbo概述 &#xff08;一&#xff09;dubbo概述 1、dub…

针对Vue前后端分离项目的渗透思路

引言 在目前的开发环境下&#xff0c;越来越多的厂商选择 Vue.js 来实现前端功能的编写&#xff0c;且成熟的前端框架已经可以实现后端代码实现的功能&#xff0c;导致后端目前只负责提供 Api 接口和文档&#xff0c;方便前端的同时去调用。本文主要介绍如何针对这类前后端分离…

java版鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统源代码

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

java紫砂壶交易购物系统 mysql

网络紫砂壶可充通过色彩、图片、说明、设置动画加强了产品了宣传&#xff0c;大大达到了陶瓷业的“色型”要求。实现产品管理方便&#xff0c;起到立竿见影的效果&#xff0c;不用因为更改菜色而重新印刷。只要在后台鼠标轻轻一点&#xff0c;全线马上更新。采用B/S模式&#x…

mybatisPlus初识

文章目录 什么是mybatisplus依赖入门案例自动填充乐观锁悲观锁乐观锁 mybatisPlus实现乐观锁批量查询根据指定条件查询 什么是mybatisplus mybatisplus是mybatis的增强工具&#xff0c;支持多种类型的数据库。 依赖 <dependency><groupId>com.baomidou</group…

快速了解车联网V2X通信

自动驾驶拥有极其巨大的潜力&#xff0c;有可能改变我们的出行方式。它不仅有望永远改变车辆的设计和制造&#xff0c;还会永远改变汽车的所有权乃至整个交通运输业务。要实现全自动驾驶的目标&#xff0c;开发人员需要开发极为复杂的软件&#xff0c;软件中融入的人工智能(AI)…

从一到无穷大 #7 Database-as-a-Service租户隔离挑战与解决措施

文章目录 引言计算侧多租户隔离2DFQSQLVMRetro 其他隔离方法其他 引言 在云环境中租户之间的资源共享对于运营商的成本效益来说非常重要&#xff0c;但是一个主要问题是租户之间的资源隔离&#xff0c;这通常与Qos息息相关&#xff0c;从多租户的角度讲&#xff0c;安全性/性能…