当前位置: 首页 > news >正文

Flutter简单实现滑块验证

现在实现一个 Flutter 滑动验证组件,类似于许多网站和应用程序中常见的“滑动以验证”功能。它通过滑动一个滑块来完成验证操作,用户需要将滑块拖动到指定位置以完成验证。

前置知识点整理

StatefulWidget

在 Flutter 中,`StatefulWidget` 是一种可以拥有状态的组件,状态的变化会导致 UI 的重建。这与 `StatelessWidget` 不同,后者是无状态的,通常用于不需要维护状态的简单 UI 组件。

`StatefulWidget` 的基本结构

一个完整的 `StatefulWidget` 由两个类组成:

1.`StatefulWidget` 类:
  • 这个类本身是不可变的。
  • 它负责创建一个 `State` 对象,该对象持有所有与这个组件相关的状态。

2.`State` 类:
  • 这是一个泛型类,通常与特定的 `StatefulWidget` 绑定。
  • 负责存储与 `StatefulWidget` 相关的数据,并包含构建 UI 的逻辑。
  • 当状态改变时,通过调用 `setState` 方法来触发 UI 的重建。

`StatefulWidget` 的生命周期

1.`createState`:
  • 当 Flutter 框架准备构建 `StatefulWidget` 时调用。
  • 返回一个 `State` 对象,持有组件的状态。

2.`initState`:
  • 在 `State` 对象第一次被插入到树中时调用。
  • 通常用于初始化数据或订阅服务。

3.`didChangeDependencies`:
  • 当 `State` 对象的依赖关系发生变化时调用。
  • 例如,`InheritedWidget` 中的数据改变。

4.`build`:
  • 必须实现的方法,构建 UI。
  • 当您调用 `setState` 时,`build` 方法会被重新调用。

5.setState`:
  • 用来通知框架状态已经改变,并且需要重建 UI。
  • 只更新最小范围内的 UI。

6.`deactivate`:
  • 当 `State` 对象被从树中移除时调用。

7.`dispose`:
  • 当 `State` 对象永久性被从树中移除时调用。
  • 用于释放资源,比如取消订阅或者关闭动画控制器。

`StatefulWidget` 设计理念

  • 不可变性:`StatefulWidget` 本身是不可变的,任何需要改变的数据都应该放在 `State` 对象中。这是因为 `StatefulWidget` 仅用于描述 UI 的布局和配置,而状态变化应该由 `State` 管理。
  • 分离逻辑和状态:将状态管理逻辑放在 `State` 类中,可以更好地组织代码,使得 UI 和业务逻辑更易于维护和测试。

`State` 生命周期方法的使用

`initState()`:
  • 在这里进行初始化操作,例如创建动画控制器、订阅服务、初始化变量等。
  • 调用 `super.initState()` 是必须的。
`didChangeDependencies()`:
  • 当 `State` 依赖的 `InheritedWidget` 发生变化时调用。
  • 通常用于在依赖的环境改变时,重新计算一些需要的状态。
`setState()`:
  • 调用此方法后,Flutter 框架会在下一个帧重新调用 `build()` 方法。
  • 只应在 `State` 类中调用 `setState`,而不应在 `build()` 方法中调用,以避免无限的重建循环。
`dispose()`:
  • 在这里释放资源,例如取消订阅、销毁动画控制器等。
  • 确保调用 `super.dispose()` 以遵循框架的正确处理流程。

性能优化

最小化 `setState` 范围:

只更新需要改变的部分,不要在 `setState` 中更新整个 widget 树,以提升性能。

避免不必要的重建:

通过提取组件和使用 `const` 构造函数来减少无意义的重建。

使用 `Keys`:

在需要保持 widget 状态的一致性时,使用 `Keys` 来帮助 Flutter 底层算法识别 widget。

状态管理的扩展

Provider:

在更复杂的应用中,使用 `Provider` 或其他状态管理解决方案来管理跨多个 widget 的状态。

BLoC:

使用 BLoC 模式来分离业务逻辑和 UI,适合处理更复杂的交互和数据流。

Riverpod:

一个现代化的状态管理库,可以提供更灵活和简洁的方式来管理应用状态。

AnimationController

`AnimationController` 是 Flutter 中用于创建动画效果的核心类之一。它负责管理动画的时间线,包括动画的启动、停止、方向和速度控制。`AnimationController` 通常与其他动画类(如 `Tween` 和 `Animation`)结合使用,以创建复杂的动画效果。

基本用法

初始化

`AnimationController` 需要一个 `TickerProvider`,通常通过在 `State` 类中使用 `SingleTickerProviderStateMixin` 或 `TickerProviderStateMixin` 来实现。

代码示例
import 'package:flutter/material.dart';class MyAnimatedWidget extends StatefulWidget {const MyAnimatedWidget({super.key});@override_MyAnimatedWidgetState createState() {return _MyAnimatedWidgetState();}
}class _MyAnimatedWidgetState extends State<MyAnimatedWidget>with SingleTickerProviderStateMixin {late AnimationController _controller;@overrideWidget build(BuildContext context) {}@overridevoid initState() {super.initState();_controller =AnimationController(vsync: this, duration: const Duration(seconds: 2));}@overridevoid dispose() {_controller.dispose();super.dispose();}
}

使用 `AnimationController`
启动动画:
  • `forward()`: 正向播放动画。
  • `reverse()`: 反向播放动画。
  • `repeat()`: 循环播放动画,可以指定是否反向。

控制动画:
  • `stop()`: 停止动画。
  • `reset()`: 重置动画到初始状态。
  • `animateTo()`: 将动画移动到特定的值。

监听动画:
  • `addListener()`: 添加回调函数,每帧都会调用。
  • `addStatusListener()`: 监听动画状态变化(如开始、结束、前进、反向)。
结合 `Tween` 和 `AnimatedBuilder`

`Tween` 用于定义动画值的范围和插值方式。`AnimatedBuilder` 则用于在每一帧重新构建 UI。

  @overridedWidget build(BuildContext context) {return AnimatedBuilder(animation: _controller,builder: (context, child) {return Transform.scale(scale: _controller.value,child: child,);},child: Container(width: 100,height: 200,color: Colors.grey,),);}

进阶用法

使用 `CurvedAnimation`

`CurvedAnimation` 可以在 `AnimationController` 基础上应用不同的插值曲线(如加速、减速、弹性等)。

final Animation<double> _animation = CurvedAnimation(dparent: _controller,curve: Curves.easeInOut,
);

多控制器与 `TickerProviderStateMixin`

当需要同时管理多个动画时,可以使用 `TickerProviderStateMixin`,但要注意资源管理,确保在 `dispose()` 中释放所有 `AnimationController`。

注意事项

  • 资源释放:始终在 `dispose()` 方法中调用 `dispose()` 来释放 `AnimationController` 资源,以避免内存泄漏。
  • 性能优化:动画应尽量简化,不要在动画中执行复杂的计算或 I/O 操作。
  • 帧率:Flutter 尝试以每秒 60 帧的速率渲染动画,确保动画逻辑不会阻塞主线程以保持流畅。

通过灵活应用 `AnimationController`,可以在 Flutter 中创建丰富的动画效果,从简单的过渡到复杂的交互式动画。

GestureDetector

`GestureDetector` 是 Flutter 中用于检测用户手势的一个重要小部件。它提供了一种方式来捕获和响应屏幕上的各种触摸事件和手势,比如点击、双击、长按、拖动、缩放等。通过 `GestureDetector`,我们可以使应用对用户交互更具响应性和互动性。

基本功能

`GestureDetector` 通过一系列回调函数来处理不同类型的手势事件。

常用属性和回调

1.点击类手势:

  • `onTap`: 用户轻触屏幕时触发。
  • `onDoubleTap`: 用户双击屏幕时触发。
  • `onLongPress`: 用户长按屏幕时触发。

2.拖动类手势:

  • `onPanStart`: 用户开始拖动时触发。
  • `onPanUpdate`: 用户拖动时持续触发,返回拖动的位移。
  • `onPanEnd`: 用户结束拖动时触发。

3.缩放类手势:

  • `onScaleStart`: 用户开始进行缩放操作时触发。
  • `onScaleUpdate`: 用户缩放时持续触发,返回缩放比例。
  • `onScaleEnd`: 用户结束缩放操作时触发。

4.特定方向拖动手势:

  • `onVerticalDragStart` / `onVerticalDragUpdate` / `onVerticalDragEnd`: 检测垂直方向拖动。
  • `onHorizontalDragStart` / `onHorizontalDragUpdate` / `onHorizontalDragEnd`: 检测水平方向拖动。

代码示例

import 'package:flutter/material.dart';class DraggableBox extends StatefulWidget {const DraggableBox({super.key});@override_DraggableBoxState createState() {return _DraggableBoxState();}
}class _DraggableBoxState extends State<DraggableBox> {double _xOffset = 0.0;double _yOffset = 0.0;@overrideWidget build(BuildContext context) {return Scaffold(body: Center(child: GestureDetector(onPanUpdate: (details) {setState(() {_xOffset += details.delta.dx;_yOffset += details.delta.dy;});},child: Transform.translate(offset: Offset(_xOffset, _yOffset),child: Container(width: 100,height: 100,color: Colors.red,),),),),);}
}

高级用法和注意事项

事件冲突:

  • 在复杂的 UI 中,多个手势检测器可能重叠,导致事件冲突。可以使用 `GestureDetector` 的 `behavior` 属性来控制手势事件的分发,例如 `HitTestBehavior.opaque`、`HitTestBehavior.translucent`、`HitTestBehavior.deferToChild`。

手势优先级:

  • 当多个手势重叠时,Flutter 会根据手势识别机制来确定哪个手势有效。通过回调的返回值或 `GestureArena` 机制

手势优先级和冲突解决

手势识别冲突:

  • 当多个手势检测器同时监听同一事件流时,可能会发生冲突。Flutter 使用 `GestureArena` 来管理这种冲突。
  • `GestureDetector` 中的某些手势,如 `onTap` 和 `onDoubleTap`,可能会同时触发。在这种情况下,Flutter 会尝试根据手势的优先级和时间顺序来确定哪个手势应该生效。

使用 `behavior` 属性:

  • `behavior` 属性控制 `GestureDetector` 如何处理点击测试:
  • `HitTestBehavior.deferToChild`: 默认值,表示事件先传递给子组件。
  • `HitTestBehavior.opaque`: 组件即使透明也能接受事件。
  • `HitTestBehavior.translucent`: 透明区域可点击,但事件也会传递给下面的组件。

组合手势

组合多个手势:

  • 可以在一个 `GestureDetector` 中组合多个手势检测回调,以实现复杂的交互。例如,同时处理拖动和缩放:
GestureDetector(onPanUpdate: (details) {// 处理拖动},onScaleUpdate: (details) {// 处理缩放},
);

性能优化

避免不必要的重建:

  • 在手势回调中,尽量减少 `setState` 的调用范围,只更新需要改变的部分。
  • 对于复杂的计算或动画,考虑使用 `AnimationController` 或 `AnimatedBuilder` 来分离手势逻辑和 UI 重建。

其他注意事项

响应区域:

  • `GestureDetector` 默认的响应区域是其子组件的大小。如果想扩大响应区域,可以在 `GestureDetector` 外包裹一个较大的 `Container` 或使用 `Padding`。

与其他手势检测器的交互:

  • 当 `GestureDetector` 与其他手势检测器(如 `InkWell` 或 `RawGestureDetector`)一起使用时,需注意手势处理的顺序和优先级。

案例场景

  • 滑动删除:在列表项中使用 `GestureDetector` 实现滑动删除功能,结合 `Dismissible` 小部件。
  • 图片缩放与拖动:在画廊应用中,结合拖动和缩放手势,允许用户放大和移动图片。
  • 游戏中的手势控制:利用复杂的手势组合实现游戏中的角色移动、旋转和其他互动操作。

通过正确使用 `GestureDetector`,开发者可以为 Flutter 应用添加丰富的交互体验,使应用更加生动和用户友好。

Positioned

`Positioned` 是 Flutter 中用于在 `Stack` 小部件内精准定位子小部件的一个小部件。它允许你通过设置距离 `Stack` 边界的偏移量来定位子小部件。`Positioned` 只能作为 `Stack` 的子小部件使用。

基本用法

`Positioned` 提供了 `left`、`right`、`top` 和 `bottom` 属性,通过这些属性,你可以指定子部件相对于 `Stack` 容器的偏移量。这些属性可以组合使用,以便更精确地定位子部件。diam

代码示例

import 'package:flutter/material.dart';class PositionedExamplePage extends StatelessWidget {const PositionedExamplePage({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Positioned Example")),body: Center(child: Stack(children: <Widget>[Container(width: 200,height: 200,color: Colors.blue,),Positioned(top: 10,left: 10,child: Container(width: 100,height: 100,color: Colors.red,)),const Positioned(bottom: 10,right: 10,child: Text("Bottom Right"),)],),),);}
}

 高级用法和注意事项

1. 使用多个属性
  • 可以同时设置对立的边界(如 `left` 和 `right`),这会导致 `Positioned` 子部件的大小被拉伸以适应指定的边距。
  • 例如,如果你同时指定了 `left` 和 `right`,就可以控制子部件的宽度。
2. 自动适应大小
  • 如果没有指定宽度或高度,`Positioned` 将根据其子部件的大小进行调整。
3. 与 `Align` 的对比
  • `Positioned` 是通过固定偏移量定位子部件,而 `Align` 则通过比例(0 到 1)定位。
  • 如果需要相对位置(如居中、居左上角),可以考虑使用 `Align`。
4. 动态布局
  • 在响应式布局中,可能需要结合 `MediaQuery` 或 `LayoutBuilder` 动态计算偏移量,以适应不同的屏幕尺寸和方向。

通过正确使用 `Positioned`,你可以在 `Stack` 中灵活地布局子部件,实现复杂的界面设计。它非常适合用于需要精确控制子部件位置的场景,比如覆盖、标注和自定义布局。

Row

`Row` 是 Flutter 中用于水平布局的一个小部件,允许你将多个子小部件沿水平轴排列。它是一个非常常用的布局小部件,适合用于创建水平排列的组件集合。

基本用法

`Row` 小部件的核心功能是水平排列其子小部件,并提供了一些属性来控制子小部件的布局方式。

代码示例

import 'package:flutter/material.dart';class RowExamplePage extends StatelessWidget {const RowExamplePage({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Row Example")),body: const Center(child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,crossAxisAlignment: CrossAxisAlignment.center,children: <Widget>[Icon(Icons.star,color: Colors.red,size: 50,),Icon(Icons.star,color: Colors.grey,size: 50,),Icon(Icons.star,color: Colors.black,size: 50,)],),),);}
}

代码解析

`mainAxisAlignment`

1.控制子小部件在主轴(水平轴)上的对齐方式。

2.常用选项包括:

  • `MainAxisAlignment.start`: 子部件在行的起始处排列。
  • `MainAxisAlignment.end`: 子部件在行的末尾处排列。
  • `MainAxisAlignment.center`: 子部件在行的中心排列。
  • `MainAxisAlignment.spaceBetween`: 子部件均匀分布,第一个和最后一个子部件贴边。
  • `MainAxisAlignment.spaceAround`: 子部件均匀分布,每个子部件周围有相等的空间。
  • `MainAxisAlignment.spaceEvenly`: 子部件均匀分布,且空隙相等。

`crossAxisAlignment`

1.控制子小部件在交叉轴(垂直轴)上的对齐方式。

2.常用选项包括:

  • `CrossAxisAlignment.start`: 子部件在交叉轴起始处对齐。
  • `CrossAxisAlignment.end`: 子部件在交叉轴末尾处对齐。
  • `CrossAxisAlignment.center`: 子部件在交叉轴居中对齐。
  • `CrossAxisAlignment.stretch`: 子部件在交叉轴上拉伸以填满父容器。
  • `CrossAxisAlignment.baseline`: 子部件基于文本基线对齐(需要指定 `TextBaseline`)。

高级用法和注意事项

子小部件的尺寸
  • Row` 会根据其父容器的约束来布局子小部件。子小部件可以是灵活的(如使用 `Flexible` 或 `Expanded`),也可以是固定宽度的。
  • 如果子小部件的宽度超出了 `Row` 的可用空间,则可能会出现布局溢出。

灵活布局

使用 `Flexible` 和 `Expanded` 可以创建自适应的子小部件:

  • `Flexible`: 允许子小部件在可用空间内灵活调整大小。
  • `Expanded`: 强制子小部件填满 `Row` 的可用空间。

代码示例:Expanded`: 强制子小部件填满 `Row` 的可用空间

import 'package:flutter/material.dart';class RowExamplePageDemo1 extends StatelessWidget {const RowExamplePageDemo1({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Row Example")),body: Center(child: Row(children: <Widget>[Expanded(child: Container(color: Colors.red, height: 50)),Expanded(child: Container(color: Colors.green, height: 50)),Expanded(child: Container(color: Colors.blue, height: 50)),],),),);}
}

灵活布局示例

使用 `Flexible` 和 `Expanded` 可以让 `Row` 的子小部件在水平空间上进行灵活的大小调整:

import 'package:flutter/material.dart';class RowExamplePageDemo2 extends StatelessWidget {const RowExamplePageDemo2({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Row Example")),body: Center(child: Row(children: <Widget>[Expanded(flex: 1, // 占用1份可用空间child: Container(color: Colors.red, height: 50),),Expanded(flex: 2, // 占用2份可用空间child: Container(color: Colors.green, height: 50),),Expanded(flex: 1, // 占用1份可用空间child: Container(color: Colors.blue, height: 50),),]),),);}
}

 flex` 属性:`flex` 用于指定子小部件在 `Row` 的可用空间中占据的比例。上面的例子中,绿色的容器将占用红色和蓝色容器两倍的宽度。

使用 `Flexible` 的场景

`Flexible` 可以让子小部件在 `Row` 中占据一定比例的空间,而不强制其填满整个可用空间,这在某些需要固定或最小宽度的场景中特别有用。

import 'package:flutter/material.dart';class RowExamplePageDemo3 extends StatelessWidget {const RowExamplePageDemo3({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Row Example")),body: Center(child: Row(children: <Widget>[Flexible(flex: 1,fit: FlexFit.tight, // 强制子小部件填满可用空间child: Container(color: Colors.red,height: 50,),),Flexible(flex: 1,fit: FlexFit.loose,// 子小部件根据本身大小适应可用空间child: Container(color: Colors.green,height: 50,),),Flexible(fit: FlexFit.tight,flex: 1,child: Container(color: Colors.blue,height: 50,),)],)));}
}

注意事项

布局溢出


当 `Row` 中的子小部件总宽度超过 `Row` 的可用宽度时,会出现布局溢出错误(通常在调试模式下显示为红色的溢出警告)。这时可以考虑以下解决方案:

  • 使用 `Expanded` 或 `Flexible` 使子小部件自适应。
  • 通过 `SingleChildScrollView` 包裹 `Row`,提供水平滚动功能。
SingleChildScrollView(scrollDirection: Axis.horizontal,child: Row(children: <Widget>[Container(color: Colors.red, width: 400, height: 50),Container(color: Colors.green, width: 400, height: 50),Container(color: Colors.blue, width: 400, height: 50),],),
)

嵌套布局
  • 如果需要在 `Row` 中嵌套其他布局(如 `Column` 或 `Stack`),确保对齐方式和布局约束被正确处理,以避免不期望的布局结果。

总结

  • `Row` 是构建水平布局的基本工具,通过结合 `mainAxisAlignment` 和 `crossAxisAlignment` 可以实现丰富的布局对齐。
  • 使用 `Flexible` 和 `Expanded` 可以实现灵活和自适应的布局。
  • 注意处理可能的布局溢出,并根据需要结合其他布局小部件(如 `SingleChildScrollView`)来提供更好的用户体验。

Clip.hardEdge

`Clip.hardEdge` 是 Flutter 中的一个枚举值,用于决定如何裁剪(clip)一个小部件的边界。`Clip` 是一个重要的概念,尤其是在设计复杂的 UI 时,通过裁剪来控制子小部件的可视区域。

Clip 枚举

在 Flutter 中,`Clip` 枚举用于指定裁剪行为的类型,主要包含以下几种值:

  • `Clip.none`:默认值,不进行任何裁剪,子小部件可能会超出其父容器的边界。
  • `Clip.hardEdge`:使用硬边界裁剪,裁剪结果的边界是锐利的。
  • `Clip.antiAlias`:进行裁剪并抗锯齿,边缘会变得更加平滑。
  • `Clip.antiAliasWithSaveLayer`:与 `Clip.antiAlias` 类似,但它会在裁剪前保存图层,有助于在某些情况下提高性能,但可能会增加内存消耗。

`Clip.hardEdge` 详解

`Clip.hardEdge` 是一种简单高效的裁剪方法,适用于需要快速裁剪但对抗锯齿效果要求不高的场景。它是通过直接裁剪像素来实现的,因此边缘是锐利的。

使用场景

  • 性能优先:如果裁剪操作需要非常高效并且对边缘的光滑度没有严格要求,`Clip.hardEdge` 是一个很好的选择。
  • 简单形状裁剪:适用于简单的矩形或其他几何形状的裁剪,而不需要边缘过渡效果。

代码示例

import 'package:flutter/material.dart';class ClipHardEdgeExample extends StatelessWidget {const ClipHardEdgeExample({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Clip.hardEdge Example")),body: Center(child: ClipRect(clipBehavior: Clip.hardEdge,child: Container(width: 200,height: 200,color: Colors.blue,child: Align(alignment: Alignment.topLeft,child: Container(width: 300,height: 300,color: Colors.red,),),),),),);}
}

注意事项

  • 视觉效果:`Clip.hardEdge` 的裁剪边缘是锐利的,没有抗锯齿处理,因此在某些情况下可能会出现锯齿效果。
  • 性能:由于不进行抗锯齿处理,`Clip.hardEdge` 通常比其他裁剪方法(如 `Clip.antiAlias`)更高效。
  • 应用场景:适用于不需要光滑边缘的简单裁剪任务。对于需要光滑边缘的裁剪,考虑使用 `Clip.antiAlias`。

通过了解和正确使用 `Clip.hardEdge`,开发者可以在需要时实现高效的裁剪操作,同时确保应用性能和视觉效果的平衡。

AnimationController vsync参数含义

在 Flutter 中,`AnimationController` 是用于控制动画的一个类,而 `vsync` 参数在创建 `AnimationController` 时扮演着关键角色。理解 `vsync` 的作用有助于优化动画的性能和资源使用。

什么是 `vsync`?

`vsync` 是 `AnimationController` 的一个参数,它用来防止动画在不必要的情况下消耗资源。具体来说,`vsync` 是一种机制,用于同步动画的帧速率与屏幕的刷新率。

`vsync` 的作用

  • 节省资源:通过 `vsync`,Flutter 可以在动画不在屏幕上时暂停动画的帧更新。这意味着当动画不在需要被绘制时,它不会占用 CPU 资源进行计算。
  • 帧同步:`vsync` 确保动画的帧更新与设备的屏幕刷新同步,从而提供更平滑的动画效果。

如何实现 `vsync`

在 Flutter 中,`TickerProvider` 是负责提供 `vsync` 的对象。通常,你可以通过让你的类实现 `TickerProvider` 或者更常用的 `TickerProviderStateMixin` 来提供 `vsync`。

总结

  • `vsync` 是一个机制,用于将动画的帧速率与设备的屏幕刷新同步。
  • 实现 `vsync` 可以通过 `TickerProvider`,通常通过 `TickerProviderStateMixin` 来实现。
  • 正确使用 `vsync` 可以提高动画性能,节省设备资源,并提供平滑的动画体验。

通过理解和正确使用 `vsync`,开发者可以更有效地管理 Flutter 应用中的动画,确保应用流畅运行并优化资源使用。

CurvedAnimation

`CurvedAnimation` 是 Flutter 中一个用于创建非线性动画的类。通过使用曲线,开发者可以使动画的变化更加自然和流畅,模拟现实世界中的运动效果,比如加速、减速、弹跳等。

基本概念

`CurvedAnimation` 是一个包装器,它通过将 `Animation` 对象与 `Curve` 结合来生成具有特定速率变化的动画。`Curve` 描述了动画的速率变化模式。

关键属性

  • `parent`:一个 `Animation` 对象,通常是一个 `AnimationController`,它驱动 `CurvedAnimation` 的值变化。
  • `curve`:一个 `Curve` 对象,定义了动画的速率变化模式。
  • `reverseCurve`:一个可选的 `Curve` 对象,用于定义反向动画的曲线。

代码示例

import 'package:flutter/material.dart';class CurvedAnimationExample extends StatefulWidget {const CurvedAnimationExample({super.key});@override_CurvedAnimationExampleState createState() {return _CurvedAnimationExampleState();}
}class _CurvedAnimationExampleState extends State<CurvedAnimationExample>with SingleTickerProviderStateMixin {late AnimationController _controller;late Animation<double> _animation;@overridevoid initState() {super.initState();_controller =AnimationController(vsync: this, duration: const Duration(seconds: 2));// 浣跨敤鍐呯疆鐨?easeInOut 鏇茬嚎_animation = CurvedAnimation(parent: _controller, curve: Curves.easeInOut);_controller.forward();}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('CurvedAnimation Example')),body: Center(child: AnimatedBuilder(animation: _animation,builder: (context, child) {return Transform.scale(scale: _animation.value,child: child,);},child: Container(width: 100,height: 100,color: Colors.blue,),),),);}
}

常用曲线

Flutter 提供了一些内置的曲线,常用于创建不同风格的动画效果:

  • `Curves.linear`:线性曲线,匀速变化。
  • `Curves.easeIn`:缓入曲线,动画开始时较慢。
  • `Curves.easeOut`:缓出曲线,动画结束时较慢。
  • `Curves.easeInOut`:缓入缓出曲线,动画的开始和结束都较慢。
  • `Curves.bounceIn`:动画开始时有弹跳效果。
  • `Curves.bounceOut`:动画结束时有弹跳效果。

AnimationController

`AnimationController` 是 Flutter 中用于控制动画的一个核心类。它提供了一种方式来驱动动画,控制其开始、停止、反向、重复等行为。`AnimationController` 本质上是一个特殊的 `Animation`,其值在给定时间段内从 0.0 变到 1.0 或者反过来。

关键属性和方法

  • `duration`:动画的持续时间,决定了动画从开始到结束的时长。
  • `value`:当前动画的值,通常在 0.0 到 1.0 之间变化,但可以通过 `Animation` 和 `Tween` 进行扩展。
  • `status`:表示动画的当前状态,可以是 `dismissed`(动画初始状态)、`forward`(动画正在前进)、`reverse`(动画正在反向)、`completed`(动画结束)。
  • `forward()`:启动动画并向前播放。
  • `reverse()`:反向播放动画。
  • `repeat()`:重复播放动画,可以指定是否反向。
  • `stop()`:暂停动画。
  • `reset()`:重置动画到初始状态。
  • `addListener()`:添加一个监听器,每当动画的值发生变化时调用。
  • `addStatusListener()`:添加一个状态监听器,每当动画的状态发生变化时调用。

使用步骤

1.创建 `AnimationController`:在 `initState` 方法中初始化控制器。

2.设置动画属性:指定 `duration` 和 `vsync`(通常由 `TickerProvider` 提供)。

3.控制动画:使用 `forward()`、`reverse()` 等方法来启动或控制动画。

4.清理资源:在 `dispose` 方法中调用 `dispose()` 来释放控制器。

代码示例

import 'package:flutter/material.dart';class AnimationControllerExample extends StatefulWidget {const AnimationControllerExample({super.key});@override_AnimationControllerExampleState createState() {return _AnimationControllerExampleState();}
}class _AnimationControllerExampleState extends State<AnimationControllerExample>with SingleTickerProviderStateMixin {late AnimationController _controller;late Animation<double> _animation;@overridevoid initState() {super.initState();_controller =AnimationController(vsync: this, duration: const Duration(seconds: 2));_animation = Tween<double>(begin: 0.5, end: 1.5).animate(_controller);_controller.forward();}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('AnimationController Example')),body: Center(child: AnimatedBuilder(animation: _animation,builder: (context, child) {return Transform.scale(scale: _animation.value,child: child,);},child: Container(width: 100,height: 100,color: Colors.blue,),),),);}
}

代码解析

  • `SingleTickerProviderStateMixin`:提供 `vsync` 参数以优化动画性能,防止动画在不需要更新时仍然消耗资源。
  • `AnimationController`:控制动画的核心类,通过设置 `duration` 来定义动画时长。
  • `Tween`:定义了动画的范围。在示例中,`Tween` 的 `begin` 值为 0.5,`end` 值为 1.5。通过 `animate()` 方法,这些值被应用到 `AnimationController` 上,从而生成一个新的 `Animation` 对象。
  • `AnimatedBuilder`:用于将动画与 UI 组件分离,以优化性能。在构建 UI 时,`AnimatedBuilder` 监听动画的变化,并在每一帧更新时调用 `builder` 方法重建其子部件。
  • `Transform.scale`:根据动画的当前值缩放 `Container`。`_animation.value` 随着时间变化,因此 `Container` 会在动画过程中缩放。

反向动画

通过 `reverse()` 方法,您可以让动画反向播放。例如,当用户执行某个操作时,您可能希望动画从结束状态返回到初始状态。

// 反向动画
_controller.reverse();

循环动画

`AnimationController` 可以通过 `repeat()` 方法循环播放动画,并可以指定是否反向。

// 循环播放动画,反向播放
_controller.repeat(reverse: true);

动画完成事件

通过 `addStatusListener()`,您可以监听动画的状态变化,执行特定的逻辑。例如,动画完成后执行某个操作:

_controller.addStatusListener((status) {if (status == AnimationStatus.completed) {// 动画完成,执行某些操作}
});

多个动画组合

可以通过多个 `Tween` 和 `CurvedAnimation` 组合来创建复杂的动画效果。例如,创建一个具有不同曲线效果的动画序列:

_animation = Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: _controller,curve: Curves.easeIn,),
);

动画的中途控制

可以在动画进行中,通过更改 `value` 动态控制动画。例如,将动画设置到特定位置:

// 设置动画到一半的位置
_controller.value = 0.5;

总结

`AnimationController` 是实现 Flutter 动画的核心工具,它提供了对动画生命周期的精细控制。通过合理使用 `AnimationController`,结合 `Tween` 和 `CurvedAnimation`,开发者可以在应用中创建丰富、动态的用户体验。

在实际开发中,理解 `AnimationController` 的工作机制和灵活运用其方法和属性,是提升 Flutter 动画效果和应用性能的关键。无论是简单的过渡动画还是复杂的交互动画,`AnimationController` 都是一个不可或缺的组件。

DragStartDetails

`DragStartDetails` 是 Flutter 中用于处理拖动手势的类之一。它主要用于描述拖动手势开始时的信息。在处理用户交互和手势识别时,`DragStartDetails` 提供了必要的细节来确定用户如何开始拖动操作。

关键属性

  • globalPosition`:`Offset` 类型,表示拖动开始时触点在全局坐标系中的位置。这个属性通常用于识别手势相对于整个屏幕的位置。
  • `localPosition`:`Offset` 类型,表示拖动开始时触点在局部坐标系中的位置。这个属性是相对于触发拖动事件的小部件的位置。
  • `sourceTimeStamp`:`Duration` 类型,表示事件发生的时间戳。这个属性可以用于计算拖动的时间间隔,但在某些平台上可能为 `null`。

使用场景

`DragStartDetails` 通常与 `GestureDetector` 或 `Listener` 小部件一起使用,以捕获和处理拖动手势。它在以下场景中非常有用:

  • 自定义拖拽行为:在实现自定义拖拽效果时,你可以使用 `DragStartDetails` 来确定拖动的起始位置,从而调整 UI 元素的初始状态。
  • 复杂手势识别:在实现需要更复杂手势处理的应用中(例如绘图应用或拖拽排序),`DragStartDetails` 提供的坐标信息可以帮助您识别并响应用户的拖动手势。

实际应用场景

1.拖动排序:在某些应用中,用户可能需要通过拖动来重新排序列表项。`DragStartDetails` 可以帮助你识别用户点击的位置,以便在拖动开始时提供视觉反馈。

2.绘图应用:在绘图或签名应用中,`DragStartDetails` 可以用于确定用户开始绘制的位置,从而在该点开始渲染绘图路径。

3.游戏开发:在某些游戏中,用户可能需要通过拖动来控制角色或对象的移动。利用 `DragStartDetails` 可以在用户拖动开始时准确调整游戏对象的初始状态。

提示和最佳实践

  • 响应速度:确保在手势开始时能够快速响应,以提供流畅的用户体验。使用 `DragStartDetails` 的位置信息来立即更新 UI,可以有效减少拖动时的延迟。
  • 坐标系转换:如果需要在不同坐标系(如全局与局部)之间转换位置,可以使用 `RenderBox` 的 `globalToLocal` 和 `localToGlobal` 方法。
  • 事件处理:在复杂的手势处理逻辑中,可能需要结合 `onPanStart`、`onPanUpdate` 和 `onPanEnd` 来实现完整的拖动体验。确保在每个阶段都正确处理用户输入。

总结

`DragStartDetails` 是一个重要的工具,在处理拖动手势时为开发者提供了精准的位置信息。通过理解和利用这些信息,可以实现更复杂和精细的用户交互,增强应用的用户体验。在设计与实现拖动相关功能时,灵活运用 `DragStartDetails` 和其他手势事件,可以极大地提升应用的交互性和响应速度。

实现滑块验证代码学习

import 'package:flutter/material.dart';class SlideVerifyPage extends StatelessWidget {const SlideVerifyPage({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("SlideVerifyPage"),),body: const Center(child: SlideVerify(sliderImage: "static/demo.png",successText: "验证成功",initText: "滑动验证",),),);}
}class SlideVerify extends StatefulWidget {final double height;final double width;final Color borderColor;final Color bgColor;final Color moveColor;final String? successText;final String? sliderImage;final String? initText;final String? initImage;final TextStyle successTextStyle;final TextStyle initTextStyle;final VoidCallback? successListener;const SlideVerify({super.key,this.height = 60,this.width = 250,this.successText,this.initText,this.sliderImage,this.initImage,this.successTextStyle =const TextStyle(fontSize: 14, color: Colors.white),this.initTextStyle = const TextStyle(fontSize: 14, color: Colors.black12),this.bgColor = Colors.grey,this.moveColor = Colors.blue,this.borderColor = Colors.blueAccent,this.successListener});@overrideState<StatefulWidget> createState() {return SlideVerifyState();}}class SlideVerifyState extends State<SlideVerify>with TickerProviderStateMixin {AnimationController? _animController;Animation? _curve;//`initX`:记录拖动开始时的初始位置。double initX = 0.0;double height = 0;double width = 0;//`moveDistance`:记录滑块的移动距离。double moveDistance = 0;double sliderWidth = 0;//`verifySuccess`:标记验证是否成功。bool verifySuccess = false;//`enable`:控制滑块是否可用。bool enable = true;void _init() {//初始化滑块的宽度sliderWidth = widget.height - 4;// sliderWidth = widget.height;_animController = AnimationController(duration: const Duration(milliseconds: 400), vsync: this);_curve = CurvedAnimation(parent: _animController!, curve: Curves.easeOut);_curve?.addListener(() {setState(() {moveDistance = moveDistance - moveDistance * _curve!.value;if (moveDistance <= 0) {moveDistance = 0;}});});_animController?.addStatusListener((status) {//动画执行完成if (status == AnimationStatus.completed) {enable = true;//重置动画到初始状态。_animController?.reset();}});}@overridevoid initState() {super.initState();//初始化width 和  height  记录控件的宽度  和 高度width = widget.width;height = widget.height;_init();}@overridevoid dispose() {//资源释放_animController?.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return GestureDetector(onHorizontalDragStart: (DragStartDetails details) {if (!enable) {return;}//初始化开始点initX = details.globalPosition.dx;},onHorizontalDragUpdate: (DragUpdateDetails details) {if (!enable) {return;}//计算滑动距离moveDistance = details.globalPosition.dx - initX;if (moveDistance < 0) {moveDistance = 0;}if (moveDistance > width - sliderWidth) {moveDistance = width - sliderWidth;//滑块不可用的条件是:滑动距离 > 组件宽度-滑块宽度enable = false;verifySuccess = true;if (widget.successListener != null) {widget.successListener?.call();}}setState(() {});},onHorizontalDragEnd: (DragEndDetails details) {//只有未验证成功才需要回退if (enable) {enable = false;//启动动画并向前播放。_animController?.forward();}},child: Container(height: height,width: width,clipBehavior: Clip.hardEdge,decoration: BoxDecoration(color: widget.bgColor,border: Border.all(color: widget.borderColor),borderRadius: BorderRadius.all(Radius.circular(height))),child: Stack(alignment: Alignment.centerLeft,children: <Widget>[Positioned(top: 0,left: 0,child: Container(height: height - 2,//滑动的时候蓝色块的宽度(即滑动部分的宽度)width: moveDistance < 1 ? 0 : moveDistance + sliderWidth / 2,decoration: BoxDecoration(color: widget.moveColor,),),),Center(child: Text(verifySuccess? widget.successText ?? "": widget.initText ?? "",style: verifySuccess? widget.successTextStyle: widget.initTextStyle,),),//下面部分表示滑块Positioned(top: 1,left:moveDistance > sliderWidth ? moveDistance - 2 : moveDistance,child: Container(width: sliderWidth,height: sliderWidth,alignment: Alignment.center,clipBehavior: Clip.hardEdge,decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.all(Radius.circular(sliderWidth),),),child: Row(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: <Widget>[if (widget.sliderImage != null)Image.asset(widget.sliderImage!,height: sliderWidth,width: sliderWidth,fit: BoxFit.cover,),],),),),],),),);}
}

相关文章:

Flutter简单实现滑块验证

现在实现一个 Flutter 滑动验证组件&#xff0c;类似于许多网站和应用程序中常见的“滑动以验证”功能。它通过滑动一个滑块来完成验证操作&#xff0c;用户需要将滑块拖动到指定位置以完成验证。 前置知识点整理 StatefulWidget 在 Flutter 中&#xff0c;StatefulWidget 是…...

第33周:运动鞋识别(Tensorflow实战第五周)

目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 1.3 查看数据 二、数据预处理 2.1 加载数据 2.2 可视化数据 2.3 再次检查数据 2.4 配置数据集 2.4.1 基本概念介绍 2.4.2 代码完成 三、构建CNN网络 四、训练模型 4.1 设置动态学习率 4.2 早停与保存最佳模型…...

C#中switch语句使用

编写一个程序&#xff0c;使用switch语句将用户输入的分数转换成等级&#xff0c;如表 private static void Main(string[] args) { Console.WriteLine("请输入分数&#xff1a;"); int score int.Parse(Console.ReadLine()); switch (score) …...

2024.11.28(作业)

思维导图 功能函数声明文件 #ifndef _FUN_H__ #define _FUN_H__ #include <myhead.h>#define MAX 50 //数组大小 #define QAZ 20 //长度和字符串大小typedef int datatype; //数据元素类型//2.1 定义顺序表类型 typedef struct {datatype data[MAX];int len; }S…...

充分统计量(Sufficient Statistic)概念与应用: 中英双语

充分统计量&#xff1a;概念与应用 在统计学中&#xff0c;充分统计量&#xff08;Sufficient Statistic&#xff09; 是一个核心概念。它是从样本中计算得出的函数&#xff0c;能够完整且无损地表征样本中与分布参数相关的信息。在参数估计中&#xff0c;充分统计量能够帮助我…...

2. STM32_中断

中断 中断是什么&#xff1a; 打断CPU执行正常的程序&#xff0c;转而处理紧急程序&#xff0c;然后返回原暂停的程序继续运行&#xff0c;就叫中断。 中断的意义&#xff1a; 中断可以高效处理紧急程序&#xff0c;不会一直占用CPU资源。如实时控制、故障处理、处理不确定…...

CAD 文件 批量转为PDF或批量打印

CAD 文件 批量转为PDF或批量打印&#xff0c;还是比较稳定的 1.需要本地安装CAD软件 2.通过 Everything 搜索工具搜索&#xff0c;DWG To PDF.pc3 &#xff0c;获取到文件目录 &#xff0c;替换到代码中&#xff0c; originalValue ACADPref.PrinterConfigPath \ r"C:…...

明明的随机数

题目描述 明明想在学校中请一些同学一起做一项问卷调查&#xff0c;为了实验的客观性&#xff0c;他先用计算机生成了N个1到1000之间的随机整数&#xff08;N≤100&#xff09;&#xff0c;对于其中重复的数字&#xff0c;只保留一个&#xff0c;把其余相同的数去掉&#xff…...

2024金盾信安杯线上赛 MISC ezpng[wp]

下载题目发现给了个password和png 图片发现损坏的 password丢随波逐流一键解 base64 给出解码的结果是 cimbar搜索发现在Github有工具 然后对附件中的图片进行小厨房xor 得到一张新图片 利用工具进行跑出答案...

C与指针。

目录 1_指针理解 1.1变量的值 1.2变量的地址 1.3指针 1.4取变量的地址 2_分析指针 2.1分析指针变量的要素 2.2根据需求定义指针变量 3_指针的使用 3.1指针对变量的读操作 3.2指针对变量的写操作 4_指针占用空间的大小与位移 4.1指针占用空间的大小 4.2指针的位移…...

使用 Selenium 和 Python 爬取腾讯新闻:从基础到实践

使用 Selenium 和 Python 爬取腾讯新闻&#xff1a;从基础到实践 在这篇博客中&#xff0c;我们将介绍如何利用 Selenium 和 Python 爬取腾讯新闻的内容&#xff0c;并将结果保存到 CSV 文件中。本教程包含以下内容&#xff1a; 项目简介依赖安装实现功能的代码实现中的关键技…...

ElasticSearch的下载和基本使用(通过apifox)

1.概述 一个开源的高扩展的分布式全文检索引擎&#xff0c;近乎实时的存储&#xff0c;检索数据 2.安装路径 Elasticsearch 7.8.0 | Elastic 安装后启动elasticsearch-7.8.0\bin里的elasticsearch.bat文件&#xff0c; 启动后就可以访问本地的es库http://localhost:9200/ …...

处理HTTP请求的两种常见方式:多个处理器(Handler)、多个处理函数(HandleFunc),两者有什么区别

一、多个处理器(Handler)、多个处理函数(HandleFunc)&#xff0c;两者的区别&#xff1a; 在Go语言中&#xff0c;处理HTTP请求的两种常见方式是使用http.Handler接口和http.HandleFunc函数。它们都用于定义如何处理HTTP请求&#xff0c;但它们之间有一些关键的区别&#xff1…...

在oracle下载jdk显示400 Bad Request Request Header Or Cookie Too Large

下载JDK17&#xff0c;官网地址&#xff1a;【https://www.oracle.com/cn/java/technologies/downloads/#jdk17-windows】 问题&#xff1a; 出现 400 Bad Request: Request Header Or Cookie Too Large 错误&#xff0c;通常是由于浏览器存储的 Cookies 或请求头过大所导致的…...

机器学习与深度学习-2-Softmax回归从零开始实现

机器学习与深度学习-2-Softmax回归从零开始实现 1 前言 内容来源于沐神的《动手学习深度学习》课程&#xff0c;本篇博客对于Softmax回归从零开始实现进行重述&#xff0c;依旧是根据Python编程的PEP8规范&#xff0c;将沐神的template代码进行简单的修改。近期有点懒散哈哈哈…...

Vue3之弹窗

文章目录 第一步、引入JS第二步、弹框 在前端开发语言Vue3&#xff0c;在管理端如何进行弹窗&#xff1f;下面根据API实现效果。 Element API文档&#xff1a; Element-plus文档 搭建环境可参考博客【 初探Vue3环境搭建与nvm使用】 第一步、引入JS <script lang"ts&…...

计算机的错误计算(一百七十一)

摘要 探讨 MATLAB 中秦九韶&#xff08;Horner&#xff09;多项式的错误计算。 例1. 用秦九韶&#xff08;Horner&#xff09;算法计算&#xff08;一百零七&#xff09;例1中多项式 直接贴图吧&#xff1a; 这样&#xff0c;MATLAB 给出的仍然是错误结果&#xff0c;因为准…...

利用Python爬虫精准获取淘宝商品详情的深度解析

在数字化时代&#xff0c;数据的价值日益凸显&#xff0c;尤其是在电子商务领域。淘宝作为中国最大的电商平台之一&#xff0c;拥有海量的商品数据&#xff0c;对于研究市场趋势、分析消费者行为等具有重要意义。本文将详细介绍如何使用Python编写爬虫程序&#xff0c;精准获取…...

_C#_串口助手_字符串拼接缺失问题(未知原理)

最近使用WPF开发串口助手时&#xff0c;遇到一个很奇怪的问题&#xff0c;无论是主线程、异步还是多线程&#xff0c;当串口接收速度达到0.016s一次以上&#xff0c;就会发生字符串缺失问题并且很卡。而0.016s就一切如常&#xff0c;仿佛0.015s与0.016s是天堑之隔。 同一份代码…...

volcano k8s 部署

下载volcano-development文件 官网 https://volcano.sh/zh/docs/installation/volcano-development.yaml wget https://raw.githubusercontent.com/volcano-sh/volcano/master/installer/volcano-development.yaml部署volcano 查下需要下载的镜像 grep vc- volcano-develo…...

Linux---对时/定时服务

文章目录 目录 文章目录 前言 一.对时服务 服务端配置 客户端配置 二.定时服务 单次定时任务 循环定时任务 前言 在当今信息化高速发展的时代&#xff0c;时间的准确性和任务的定时执行对于各种系统和服务来说至关重要。Linux操作系统&#xff0c;凭借其强大的功能和灵活的…...

13 设计模式之外观模式(家庭影院案例)

一、什么是外观模式&#xff1f; 1.定义 在日常生活中&#xff0c;许多人喜欢通过遥控器来控制家中的电视、音响、DVD 播放器等设备。虽然这些设备各自独立工作&#xff0c;但遥控器提供了一个简洁的界面&#xff0c;让用户可以轻松地操作多个设备。而这一设计理念正是 外观模…...

spring boot整合ArtemisMQ进行手动消息确认

1、SpringBoot整合ArtemisMQ进行手动消息确认使用的是&#xff1a; factory.setSessionTransacted(false); factory.setSessionAcknowledgeMode(ActiveMQJMSConstants.INDIVIDUAL_ACKNOWLEDGE); 2、SpringBoot整合ActiveMQ进行手动消息确认使用的是&#xff1a; factory.setSe…...

dpwwn02靶场

靶机下载地址&#xff1a;https://download.vulnhub.com/dpwwn/dpwwn-02.zip 信息收集 ip add 查看kali Linux虚拟机的IP为&#xff1a;10.10.10.128 https://vulnhub.com/entry/dpwwn-2,343/中查看靶机的信息&#xff0c;IP固定为10.10.10.10 所以kali Linux添加仅主机网卡…...

展示和添加篮球队信息--laravel与elementplus

之前使用laravel与inertia来做过一样的功能,感觉不满意,因此再结合elementplus重做一遍,先展示下重做后的效果。重写后的代码相比之下比较优雅。 球队首页 球队添加页 球员首页 很明显的改变,我新增了侧栏菜单来控制局部模块(这里是指NBABasketba…...

K8S疑难概念理解——Pod,应该以哪种Kind来部署应用,为什么不直接Pod这种kind?

文章目录 一、Pod概念深度理解&#xff0c;为什么一般不直接以kindPod资源类型来部署应用?二、究竟应该以哪种资源类型来部署应用 一、Pod概念深度理解&#xff0c;为什么一般不直接以kindPod资源类型来部署应用? Pod是Kubernetes中的最小部署单元&#xff0c;可以包含一个或…...

centos7怎么安装keepalive+nginx

在CentOS 7上安装Keepalived和Nginx&#xff0c;可以按照以下步骤进行&#xff1a; 安装Nginx 添加Nginx到Yum源&#xff1a; rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm安装Nginx&#xff1a; yum install -y ng…...

DevOps工程技术价值流:Jenkins驱动的持续集成与交付实践

一、Jenkins系统概述 Jenkins&#xff1a;开源CI/CD引擎的佼佼者 Jenkins&#xff0c;作为一款基于Java的开源持续集成&#xff08;CI&#xff09;与持续交付&#xff08;CD&#xff09;系统&#xff0c;凭借其强大的插件生态系统&#xff0c;成为DevOps实践中不可或缺的核心…...

el-select 修改样式

这样漂亮的页面&#xff0c;搭配的却是一个白色风格的下拉框 &#xff0c;这也过于刺眼。。。 调整后样式为&#xff1a; 灯红酒绿总有人看着眼杂&#xff0c;但将风格统一终究是上上选择。下面来处理这个问题。 分为两部分。 第一部分&#xff1a;是修改触发框的样式 第二部…...

文本内容处理命令和正则表达式

文本内容处理命令 grep 用来过滤文本内容&#xff0c;以匹配要查询的结果。 -m 数字 匹配几次后停止&#xff1a; grep -m 1 /root/etc/passwd #查找包含root的行 -v 取反 -i 忽略字符的大小写&#xff0c;默认的&#xff0c;可以不加 -n 显示匹配的行号 -c 统计匹配的…...

【PlantUML系列】类图(一)

目录 一、类 二、接口 三、抽象类 四、泛型类 五、类之间的关系 六、添加注释 七、包图 八、皮肤参数 一、类 使用class关键字定义类&#xff0c;类名后跟大括号&#xff0c;声明类的属性和方法。 属性&#xff1a;格式为{visibility} attributeName : AttributeType…...

【Leetcode Top 100】21. 合并两个有序链表

问题背景 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 数据约束 两个链表的节点数目范围是 [ 0 , 50 ] [0, 50] [0,50] − 100 ≤ N o d e . v a l ≤ 100 -100 \le Node.val \le 100 −100≤Node.val≤100 l 1 l_1 …...

【真正离线安装】Adobe Flash Player 32.0.0.156 插件离线安装包下载(无需联网安装)

网上很多人声称并提供的flash离线安装包是需要联网才能安装成功的&#xff0c;其实就是在线安装包&#xff0c;而这里提供的是真正的离线安装包&#xff0c;无需联网即可安装成功。 点击下面地址下载离线安装包&#xff1a; Adobe Flash Player 32.0.0.156 for IE Adobe Fla…...

UG NX二次开发(C#)-如何进行NX多版本的编译

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、以删除对象为例3、解决方案1、前言 由于UG NX的版本不同,新版本与旧版本开发过程中,如果是在一个工程中,其会出现低版本不能编译高版本NX的问题,这是因为高版本会引入新的函数,或者…...

Spark优化--开发调优、资源调优、数据倾斜调优和shuffle调优等

针对Spark优化&#xff0c;我们可以从多个角度进行&#xff0c;包括开发调优、资源调优、数据倾斜调优和shuffle调优等。以下是一些具体的优化方法&#xff1a; 1. 开发调优 避免创建重复的RDD&#xff1a;对于同一份数据&#xff0c;只应该创建一个RDD&#xff0c;避免创建多…...

911事件反思:灾难通信和ddos之间的取舍

流量分析与监控 建立基线流量模型&#xff1a;在正常情况下监控和记录网络流量&#xff0c;建立正常流量的基线。这样&#xff0c;当突发请求发生时&#xff0c;可以更容易地识别出流量的异常变化。 实时流量监控&#xff1a;使用流量分析工具实时监控网络流量&#xff0c;快速…...

网络安全之IP伪造

眼下非常多站点的涉及存在一些安全漏洞&#xff0c;黑客easy使用ip伪造、session劫持、xss攻击、session注入等手段危害站点安全。在纪录片《互联网之子》&#xff08;建议搞IT的都要看下&#xff09;中。亚伦斯沃茨&#xff08;真实人物&#xff0c;神一般的存在&#xff09;涉…...

算法笔记:力扣24. 两两交换链表中的节点

思路&#xff1a; 本题最简单的就是通过递归的形式去实现 class Solution {public ListNode swapPairs(ListNode head) {if(head null || head.next null){return head;}ListNode next head.next;head.next swapPairs(next.next);next.next head;return next;} } 对于链…...

Shell脚本小练习

学习了这么长时间Shell脚本&#xff0c;总得来一次小小的练习吧&#xff0c;那么请看下文&#xff01; 1.用Shell写一个小计算器。 通过read命令获取用户输入的表达式&#xff0c;表达式的格式设定为操作数1 运算符 操作数2&#xff0c;例如53&#xff0c;然后利用设计的脚本…...

Fastify装饰器:增强你的路由处理功能加入日志

Fastify以其出色的性能和扩展性脱颖而出。装饰器是Fastify提供的一个强大功能&#xff0c;它允许开发者在不修改核心代码的情况下&#xff0c;向请求&#xff08;Request&#xff09;和响应&#xff08;Response&#xff09;对象添加自定义属性和方法。本文将通过一个简单的示例…...

node.js基础学习-url模块-url地址处理(二)

前言 前面我们创建了一个HTTP服务器&#xff0c;如果只是简单的http://localhost:3000/about这种链接我们是可以处理的&#xff0c;但是实际运用中一般链接都会带参数&#xff0c;这样的话如果我们只是简单的判断链接来分配数据&#xff0c;就会报404找不到链接。为了解决这个问…...

Vue如何加载十万条数据

加载十万条数据到 Vue 应用中是一个相对复杂的问题&#xff0c;主要因为渲染大量数据可能会导致性能瓶颈&#xff0c;尤其是在前端性能较低的设备上。为了确保加载大量数据时&#xff0c;页面不会卡顿或崩溃&#xff0c;我们通常采取一些优化手段&#xff0c;以下是几种常用的方…...

重生之我在异世界学编程之C语言:二维数组篇

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文一 二维数组的创建1. 二维数组的…...

linux——进程间通信及管道的应用场景

linux进程的控制-CSDN博客 liunx——进程间通信&#xff08;管道通信&#xff09;-CSDN博客 文章目录 文章目录 前言 二、管道的应用 1.创建子进程 1、描述&#xff1a; 2.创建进程及管理 3、子进程接受任务 4、控制子进程 总结 前言 上篇博客我们学习了进程间通信&…...

深度学习基础3

目录 1.过拟合与欠拟合 1.1 过拟合 1.2 欠拟合 1.2 解决欠拟合 1.2.1 L2正则化 1.2.2 L1正则化 1.2.3 Dropout 1.2.4 简化模型 1.2.5 数据增强 1.2.6 早停 1.2.7 模型集成 1.2.8 交叉验证 2.批量标准化 2.1 实现过程 2.1.1 计算均值和方差 2.1.2 标准化 2.1.3…...

靶机dpwwn-01

靶机下载地址&#xff1a;https://download.vulnhub.com/dpwwn/dpwwn-01.zip 信息收集 扫描靶机的IP地址 arp-scan -l 获得靶机的IP地址&#xff1a;192.168.200.130 查看靶机的服务类型&#xff0c;端口信息 nmap -sS -sV -T4 -A -p- 192.168.200.130 开启了22&#xf…...

Python毕业设计选题:基于django+vue的智慧社区可视化平台的设计与实现+spider

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 养老机构管理 业主管理 社区安防管理 社区设施管理 车位…...

大语言模型微调与 XTuner 微调实战

1 大语言模型微调 1.1 什么是微调 大语言模型微调&#xff08;Fine-tuning of Large Language Models&#xff09;是指在预训练的大型语言模型基础上&#xff0c;使用特定任务的数据进一步训练模型&#xff0c;以使其更好地适应和执行特定任务的过程&#xff0c;用于使LLM&am…...

数据结构-查找(四)总结与对比

查找算法总结 文章目录 查找算法总结一、查找的基本概念二、顺序查找法适用场景 三、分块查找法适用场景 四、折半查找法&#xff08;Binary Search&#xff09;适用场景 五、树型查找1. 二叉搜索树&#xff08;BST&#xff09;2. 平衡二叉树&#xff08;AVL&#xff09;3. 红黑…...

c++总复习

一、什么是 C 中的函数对象&#xff1f;它有什么特点&#xff1f; 在 C 中&#xff0c;函数对象&#xff08;Function Object&#xff09;也称为仿函数&#xff08;Functor&#xff09;&#xff0c;它是一个类的实例&#xff0c;该类重载了函数调用运算符()&#xff0c;使得这个…...