Flutter(九)Flutter动画和自定义组件
目录
- 1.动画简介
- 2.动画实现和监听
- 3. 自定义路由切换动画
- 4. Hero动画
- 5.交织动画
- 6.动画切换
- 7.Flutter预置的动画过渡组件
- 自定义组件
- 1.简介
- 2.组合组件
- 3.CustomPaint 和 RenderObject
1.动画简介
Animation、Curve、Controller、Tween这四个角色,它们一起配合来完成一个完整动画
- Animation
Animation是抽象类,和UI渲染没有关系,功能是保存动画的插值和状态;比较常用的是Animation
addListener:帧监听器中最常见的行为是改变状态后调用setState()来触发UI重建
addStatusListener:动画开始、结束、正向或反向(见AnimationStatus定义)时会调用状态改变的监听器。 - Curve
动画过程可以是匀速的、匀加速的或者先加速后减速等。Flutter中通过Curve(曲线)来描述动画过程,我们把匀速动画称为线性的(Curves.linear),而非匀速动画称为非线性的。
final CurvedAnimation curve =CurvedAnimation(parent: controller, curve: Curves.easeIn);
Curves曲线 动画过程
linear 匀速的
decelerate 匀减速
ease 开始加速,后面减速
easeIn 开始慢,后面快
easeOut 开始快,后面慢
easeInOut 开始慢,然后加速,最后再减速
也可以自定义一个正弦曲线:
class ShakeCurve extends Curve {@overridedouble transform(double t) {return math.sin(t * math.PI * 2);}
}
- AnimationController
AnimationController用于控制动画,它包含动画的启动forward()、停止stop() 、反向播放 reverse()等
final AnimationController controller = AnimationController( duration: const Duration(milliseconds: 2000), lowerBound: 10.0,upperBound: 20.0,vsync: this
);
- Tween
默认AnimationController对象值的范围是[0.0,1.0],但可以使用Tween来改变范围
例如,像下面示例,Tween生成[-200.0,0.0]的值
final Tween doubleTween = Tween<double>(begin: -200.0, end: 0.0);
完整示例:
以下示例构建了一个控制器、一条曲线和一个 Tween:
final AnimationController controller = AnimationController(duration: const Duration(milliseconds: 500), vsync: this,
);
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(curve);
线性插值lerp函数:
//a 为起始颜色,b为终止颜色,t为当前动画的进度[0,1]
Color.lerp(a, b, t);
2.动画实现和监听
AnimatedBuilder可以封装常见的过渡效果来复用动画
class GrowTransition extends StatelessWidget {const GrowTransition({Key? key,required this.animation,this.child,}) : super(key: key);final Widget? child;final Animation<double> animation;@overrideWidget build(BuildContext context) {return Center(child: AnimatedBuilder(animation: animation,builder: (BuildContext context, child) {return SizedBox(height: animation.value,width: animation.value,child: child,);},child: child,),);}
}
...
Widget build(BuildContext context) {return GrowTransition(child: Image.asset("images/avatar.png"), animation: animation,);
}
Flutter中正是通过这种方式封装了很多动画,如:FadeTransition、ScaleTransition、SizeTransition等,很多时候都可以复用这些预置的过渡类
Animation的addStatusListener()方法来添加动画状态改变监听器。Flutter中,有四种动画状态,在AnimationStatus枚举类中定义
dismissed 动画在起始点停止
forward 动画正在正向执行
reverse 动画正在反向执行
completed 动画在终点停止
3. 自定义路由切换动画
无论是MaterialPageRoute、CupertinoPageRoute,还是PageRouteBuilder,它们都继承自PageRoute
MaterialPageRoute组件,它可以使用和平台风格一致的路由切换动画,如在iOS上会左右滑动切换,而在Android上会上下滑动切换
CupertinoPageRoute是Cupertino组件库提供的iOS风格的路由切换组件,它实现的就是左右滑动切换。
自定义切换动画优先考虑使用PageRouteBuilder
Navigator.push(context,PageRouteBuilder(transitionDuration: Duration(milliseconds: 500), //动画时间为500毫秒pageBuilder: (BuildContext context, Animation animation,Animation secondaryAnimation) {return FadeTransition(//使用渐隐渐入过渡,opacity: animation,child: PageB(), //路由B);},),
);
但是有些时候PageRouteBuilder是不能满足需求的,例如在应用过渡动画时我们需要读取当前路由的一些属性,这时就只能通过继承PageRoute的方式了
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,Animation<double> secondaryAnimation, Widget child) {//当前路由被激活,是打开新路由if(isActive) {return FadeTransition(opacity: animation,child: builder(context),);}else{//是返回,则不应用过渡动画return Padding(padding: EdgeInsets.zero);}
}
4. Hero动画
在Flutter中将图片从一个路由“飞”到另一个路由称为hero动画
例如A路由有一个圆形用户头像,点击后跳到B路由,可以查看大图
class HeroAnimationRouteA extends StatelessWidget {const HeroAnimationRouteA({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return Container(alignment: Alignment.topCenter,child: Column(children: <Widget>[InkWell(child: Hero(tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同child: ClipOval(child: Image.asset("imgs/avatar.png",width: 50.0,),),),onTap: () {//打开B路由Navigator.push(context, PageRouteBuilder(pageBuilder: (BuildContext context,animation,secondaryAnimation,) {return FadeTransition(opacity: animation,child: Scaffold(appBar: AppBar(title: const Text("原图"),),body: const HeroAnimationRouteB(),),);},));},),const Padding(padding: EdgeInsets.only(top: 8.0),child: Text("点击头像"),)],),);}
}
class HeroAnimationRouteB extends StatelessWidget {@overrideWidget build(BuildContext context) {return Center(child: Hero(tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同child: Image.asset("imgs/avatar.png"),),);}
}
实现 Hero 动画只需要用Hero组件将要共享的 widget 包装起来,并提供一个相同的 tag 即可
5.交织动画
比如:有一个柱状图,需要在高度增长的同时改变颜色,等到增长到最大高度后,我们需要在X轴上平移一段距离。可以发现上述场景在不同阶段包含了多种动画,要实现这种效果,使用交织动画(Stagger Animation)会非常简单
实现步骤:
1.要创建交织动画,需要使用多个动画对象(Animation)。
2.一个AnimationController控制所有的动画对象。
3.给每一个动画对象指定时间间隔(Interval)
class StaggerAnimation extends StatelessWidget {StaggerAnimation({Key? key,required this.controller,}) : super(key: key) {//高度动画height = Tween<double>(begin: .0,end: 300.0,).animate(CurvedAnimation(parent: controller,curve: const Interval(0.0, 0.6, //间隔,前60%的动画时间curve: Curves.ease,),),);color = ColorTween(begin: Colors.green,end: Colors.red,).animate(CurvedAnimation(parent: controller,curve: const Interval(0.0, 0.6, //间隔,前60%的动画时间curve: Curves.ease,),),);padding = Tween<EdgeInsets>(begin: const EdgeInsets.only(left: .0),end: const EdgeInsets.only(left: 100.0),).animate(CurvedAnimation(parent: controller,curve: const Interval(0.6, 1.0, //间隔,后40%的动画时间curve: Curves.ease,),),);}late final Animation<double> controller;late final Animation<double> height;late final Animation<EdgeInsets> padding;late final Animation<Color?> color;Widget _buildAnimation(BuildContext context, child) {return Container(alignment: Alignment.bottomCenter,padding: padding.value,child: Container(color: color.value,width: 50.0,height: height.value,),);}@overrideWidget build(BuildContext context) {return AnimatedBuilder(builder: _buildAnimation,animation: controller,);}
}
StaggerAnimation中定义了三个动画,分别是对Container的height、color、padding属性设置的动画,然后通过Interval来为每个动画指定在整个动画过程中的起始点和终点
使用:
class StaggerRoute extends StatefulWidget {@override_StaggerRouteState createState() => _StaggerRouteState();
}class _StaggerRouteState extends State<StaggerRoute>with TickerProviderStateMixin {late AnimationController _controller;@overridevoid initState() {super.initState();_controller = AnimationController(duration: const Duration(milliseconds: 2000),vsync: this,);}_playAnimation() async {try {//先正向执行动画await _controller.forward().orCancel;//再反向执行动画await _controller.reverse().orCancel;} on TickerCanceled {//捕获异常。可能发生在组件销毁时,计时器会被取消。}}@overrideWidget build(BuildContext context) {return Center(child: Column(children: [ElevatedButton(onPressed: () => _playAnimation(),child: Text("start animation"),),Container(width: 300.0,height: 300.0,decoration: BoxDecoration(color: Colors.black.withOpacity(0.1),border: Border.all(color: Colors.black.withOpacity(0.5),),),//调用我们定义的交错动画Widgetchild: StaggerAnimation(controller: _controller),),],),);}
}

6.动画切换
AnimatedSwitcher组件,它定义了一种通用的UI切换抽象
const AnimatedSwitcher({Key? key,this.child,required this.duration, // 新child显示动画时长this.reverseDuration,// 旧child隐藏的动画时长this.switchInCurve = Curves.linear, // 新child显示的动画曲线this.switchOutCurve = Curves.linear,// 旧child隐藏的动画曲线this.transitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, // 动画构建器this.layoutBuilder = AnimatedSwitcher.defaultLayoutBuilder, //布局构建器
})
当AnimatedSwitcher的 child 发生变化时(类型或 Key 不同),旧 child 会执行隐藏动画,新 child 会执行执行显示动画。究竟执行何种动画效果则由transitionBuilder参数决定,该参数接受一个AnimatedSwitcherTransitionBuilder类型的 builder
typedef AnimatedSwitcherTransitionBuilder =Widget Function(Widget child, Animation<double> animation);
defaultTransitionBuilder :默认AnimatedSwitcher会对新旧child执行“渐隐”和“渐显”动画
现一个计数器,然后在每一次自增的过程中,旧数字执行缩小动画隐藏,新数字执行放大动画显示
import 'package:flutter/material.dart';class AnimatedSwitcherCounterRoute extends StatefulWidget {const AnimatedSwitcherCounterRoute({Key key}) : super(key: key);@override_AnimatedSwitcherCounterRouteState createState() => _AnimatedSwitcherCounterRouteState();}class _AnimatedSwitcherCounterRouteState extends State<AnimatedSwitcherCounterRoute> {int _count = 0;@overrideWidget build(BuildContext context) {return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[AnimatedSwitcher(duration: const Duration(milliseconds: 500),transitionBuilder: (Widget child, Animation<double> animation) {//执行缩放动画return ScaleTransition(child: child, scale: animation);},child: Text('$_count',//显示指定key,不同的key会被认为是不同的Text,这样才能执行动画key: ValueKey<int>(_count),style: Theme.of(context).textTheme.headline4,),),ElevatedButton(child: const Text('+1',),onPressed: () {setState(() {_count += 1;});},),],),);}}

Flutter SDK中还提供了一个AnimatedCrossFade组件,它也可以切换两个子元素,切换过程执行渐隐渐显的动画,和AnimatedSwitcher不同的是AnimatedCrossFade是针对两个子元素,而AnimatedSwitcher是在一个子元素的新旧值之间切换
示例:实现各种“滑动出入动画”便非常容易,只需给direction传递不同的方向值即可
class SlideTransitionX extends AnimatedWidget {SlideTransitionX({Key? key,required Animation<double> position,this.transformHitTests = true,this.direction = AxisDirection.down,required this.child,}) : super(key: key, listenable: position) {switch (direction) {case AxisDirection.up:_tween = Tween(begin: const Offset(0, 1), end: const Offset(0, 0));break;case AxisDirection.right:_tween = Tween(begin: const Offset(-1, 0), end: const Offset(0, 0));break;case AxisDirection.down:_tween = Tween(begin: const Offset(0, -1), end: const Offset(0, 0));break;case AxisDirection.left:_tween = Tween(begin: const Offset(1, 0), end: const Offset(0, 0));break;}}final bool transformHitTests;final Widget child;final AxisDirection direction;late final Tween<Offset> _tween;@overrideWidget build(BuildContext context) {final position = listenable as Animation<double>;Offset offset = _tween.evaluate(position);if (position.status == AnimationStatus.reverse) {switch (direction) {case AxisDirection.up:offset = Offset(offset.dx, -offset.dy);break;case AxisDirection.right:offset = Offset(-offset.dx, offset.dy);break;case AxisDirection.down:offset = Offset(offset.dx, -offset.dy);break;case AxisDirection.left:offset = Offset(-offset.dx, offset.dy);break;}}return FractionalTranslation(translation: offset,transformHitTests: transformHitTests,child: child,);}
}
AnimatedSwitcher(duration: Duration(milliseconds: 200),transitionBuilder: (Widget child, Animation<double> animation) {var tween=Tween<Offset>(begin: Offset(1, 0), end: Offset(0, 0))return SlideTransitionX(child: child,direction: AxisDirection.down, //上入下出position: animation,);},...//省略其余代码
)

7.Flutter预置的动画过渡组件
AnimatedPadding 在padding发生变化时会执行过渡动画到新状态
AnimatedPositioned 配合Stack一起使用,当定位状态发生变化时会执行过渡动画到新的状态。
AnimatedOpacity 在透明度opacity发生变化时执行过渡动画到新状态
AnimatedAlign 当alignment发生变化时会执行过渡动画到新的状态。
AnimatedContainer 当Container属性发生变化时会执行过渡动画到新的状态。
AnimatedDefaultTextStyle 当字体样式发生变化时,子组件中继承了该样式的文本组件会动态过渡到新样式。
import 'package:flutter/material.dart';class AnimatedWidgetsTest extends StatefulWidget {const AnimatedWidgetsTest({Key? key}) : super(key: key);@override_AnimatedWidgetsTestState createState() => _AnimatedWidgetsTestState();
}class _AnimatedWidgetsTestState extends State<AnimatedWidgetsTest> {double _padding = 10;var _align = Alignment.topRight;double _height = 100;double _left = 0;Color _color = Colors.red;TextStyle _style = const TextStyle(color: Colors.black);Color _decorationColor = Colors.blue;double _opacity = 1;@overrideWidget build(BuildContext context) {var duration = const Duration(milliseconds: 400);return SingleChildScrollView(child: Column(children: <Widget>[ElevatedButton(onPressed: () {setState(() {_padding = 20;});},child: AnimatedPadding(duration: duration,padding: EdgeInsets.all(_padding),child: const Text("AnimatedPadding"),),),SizedBox(height: 50,child: Stack(children: <Widget>[AnimatedPositioned(duration: duration,left: _left,child: ElevatedButton(onPressed: () {setState(() {_left = 100;});},child: const Text("AnimatedPositioned"),),)],),),Container(height: 100,color: Colors.grey,child: AnimatedAlign(duration: duration,alignment: _align,child: ElevatedButton(onPressed: () {setState(() {_align = Alignment.center;});},child: const Text("AnimatedAlign"),),),),AnimatedContainer(duration: duration,height: _height,color: _color,child: TextButton(onPressed: () {setState(() {_height = 150;_color = Colors.blue;});},child: const Text("AnimatedContainer",style: TextStyle(color: Colors.white),),),),AnimatedDefaultTextStyle(child: GestureDetector(child: const Text("hello world"),onTap: () {setState(() {_style = const TextStyle(color: Colors.blue,decorationStyle: TextDecorationStyle.solid,decorationColor: Colors.blue,);});},),style: _style,duration: duration,),AnimatedOpacity(opacity: _opacity,duration: duration,child: TextButton(style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.blue)),onPressed: () {setState(() {_opacity = 0.2;});},child: const Text("AnimatedOpacity",style: TextStyle(color: Colors.white),),),),AnimatedDecoratedBox1(duration: Duration(milliseconds: _decorationColor == Colors.red ? 400 : 2000),decoration: BoxDecoration(color: _decorationColor),child: Builder(builder: (context) {return TextButton(onPressed: () {setState(() {_decorationColor = _decorationColor == Colors.blue? Colors.red: Colors.blue;});},child: const Text("AnimatedDecoratedBox toggle",style: TextStyle(color: Colors.white),),);}),)].map((e) {return Padding(padding: const EdgeInsets.symmetric(vertical: 16),child: e,);}).toList(),),);}
}

自定义组件
1.简介
“组合”是自定义组件最简单的方法,在任何需要自定义组件的场景下,都应该优先考虑是否能够通过组合来实现。
而通过CustomPaint和RenderObject自绘的方式本质上是一样的,都需要开发者调用Canvas API手动去绘制UI
2.组合组件
- 自定义渐变背景按钮
DecoratedBox可以支持背景色渐变和圆角,InkWell在手指按下有涟漪效果,所以我们可以通过组合DecoratedBox和InkWell来实现GradientButton
import 'package:flutter/material.dart';class GradientButton extends StatelessWidget {const GradientButton({Key? key, this.colors,this.width,this.height,this.onPressed,this.borderRadius,required this.child,}) : super(key: key);// 渐变色数组final List<Color>? colors;// 按钮宽高final double? width;final double? height;final BorderRadius? borderRadius;//点击回调final GestureTapCallback? onPressed;final Widget child;@overrideWidget build(BuildContext context) {ThemeData theme = Theme.of(context);//确保colors数组不空List<Color> _colors =colors ?? [theme.primaryColor, theme.primaryColorDark];return DecoratedBox(decoration: BoxDecoration(gradient: LinearGradient(colors: _colors),borderRadius: borderRadius,//border: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),),child: Material(type: MaterialType.transparency,child: InkWell(splashColor: _colors.last,highlightColor: Colors.transparent,borderRadius: borderRadius,onTap: onPressed,child: ConstrainedBox(constraints: BoxConstraints.tightFor(height: height, width: width),child: Center(child: Padding(padding: const EdgeInsets.all(8.0),child: DefaultTextStyle(style: const TextStyle(fontWeight: FontWeight.bold),child: child,),),),),),),);}
}
GradientButton是由DecoratedBox、Padding、Center、InkWell等组件组合而成,
flukit组件库已收录GradientButton
使用:
children: <Widget>[GradientButton(colors: const [Colors.orange, Colors.red],height: 50.0,child: const Text("Submit"),onPressed: onTap,),
3.CustomPaint 和 RenderObject
painter: 背景画笔,会显示在子节点后面;
foregroundPainter: 前景画笔,会显示在子节点前面
size:当child为null时,代表默认绘制区域大小,如果有child则忽略此参数,画布尺寸则为child尺寸。如果有child但是想指定画布为特定大小,可以使用SizeBox包裹CustomPaint实现。
isComplex:是否复杂的绘制,如果是,Flutter会应用一些缓存策略来减少重复渲染的开销。
willChange:和isComplex配合使用,当启用缓存时,该属性代表在下一帧中绘制是否会改变CustomPaint({Key key,this.painter, this.foregroundPainter,this.size = Size.zero, this.isComplex = false, this.willChange = false, Widget child, //子节点,可以为空
})
//自定义
class MyPainter extends CustomPainter class CustomCheckbox extends LeafRenderObjectWidget
Canvas常用:
drawLine 画线
drawPoint 画点
drawPath 画路径
drawImage 画图像
drawRect 画矩形
drawCircle 画圆
drawOval 画椭圆
drawArc 画圆弧
相关文章:
Flutter(九)Flutter动画和自定义组件
目录 1.动画简介2.动画实现和监听3. 自定义路由切换动画4. Hero动画5.交织动画6.动画切换7.Flutter预置的动画过渡组件自定义组件1.简介2.组合组件3.CustomPaint 和 RenderObject 1.动画简介 Animation、Curve、Controller、Tween这四个角色,它们一起配合来完成一个…...
【python】可视化
柱状图 matplotlib之pyplot模块之柱状图(bar():基础参数、外观参数)_plt.bar_mighty13的博客-CSDN博客 bar()的基础参数如下: x:柱子在x轴上的坐标。浮点数或类数组结构。注意x可以为字符串数组! height&…...
C++继承多接口,调用虚函数跳转到错误接口的虚函数的奇怪问题
问题重现 定义了两个接口IA IB class IA{public:virtual void funA() = 0; }; class IB{public:virtual void funB() = 0; }...
C++:日期类
学习目标: 加深对四个默认构造函数的理解: 1.构造函数 2.析构函数 3.拷贝构造 4.运算符重载 实现功能 1.比较日期的大小 2.日期-天数 3.前/后置,-- 这里基本会使用运算符重载 定义一个日期类 class Date { public://1.全缺省参数的构造函数Da…...
c++ 学习之 构造函数的使用
上代码 class person { public:person(){cout << " person 的无参默认构造函数 " << endl;}person(int age){cout << " person 的有参默认构造函数 " << endl;m_age age;}person(const person& other){cout << "…...
算法通关村15关 | 超大规模数据场景常见问题
1.用4KB内存寻找重复元素 题目:给定一个数组,包含从1到N的整数,N最大为32000,数组可能还有重复值,且N的取值不定,若只有4KB的内存可用,该如何打印数组中所有重复元素。 分析: 本身是…...
qemu编译与使用
文章目录 1、安装依赖2、下载qemu源码3、编译4、运行5、qemu参数 qemu 是一个硬件虚拟化程序(hypervisor that performs hardware virtualization),与传统的 VMware / VirtualBox 之类的虚拟机不同,它可以通过 binary translation…...
bazel远程构建(Remote Execution)
原理 既然 ActionResult 可以被不同的 Bazel 任务共享,说明 ActionResult 和 Action 在哪里执行并没有关系。因此,Bazel 在构建时,可以把 Action 发送给另一台服务器执行,对方执行完,向 CAS 上传 ActionResult&#x…...
uniapp 微信小程序仿抖音评论区功能,支持展开收起
最近需要写一个评论区功能,所以打算仿照抖音做一个评论功能,支持展开和收起, 首先我们需要对功能做一个拆解,评论区功能,两个模块,一个是发表评论模块,一个是评论展示区。接下来对这两个模块进行…...
js:创建一个基于vite 的React项目
相关文档 Vite 官方中文文档React 中文文档React RouterRedux 中文文档Ant Design 5.0Awesome React 创建vite react项目 pnpm create vite react-app --template react# 根据提示,执行命令 cd react-app pnpm install pnpm run dev项目结构 $ tree -L 1 . ├─…...
论文阅读_医疗知识图谱_GraphCare
英文名称: GraphCare: Enhancing Healthcare Predictions with Open-World Personalized Knowledge Graphs 中文名称: GraphCare:通过开放世界的个性化知识图增强医疗保健预测 文章: http://arxiv.org/abs/2305.12788 代码: https://github.com/pat-jj/GraphCare 作…...
Android 蓝牙开发( 四 )
前言 上一篇文章给大家分享了Kotlin版的Android蓝牙的基础知识和基础用法,不过上一篇都是一些零散碎片化的程序,,这一篇给大家分享Android蓝牙开发实战项目KotlinCompose的初步使用 效果演示 : Android Compose 蓝牙开发 Android蓝牙实战开发…...
涂鸦智能携手亚马逊云科技 共建“联合安全实验室” 为IoT发展护航
2023年8月31日,全球化IoT开发者平台涂鸦智能(NYSE: TUYA,HKEX: 2391)在“2023亚马逊云科技re:Inforce中国站”大会宣布与全球领先的云计算公司亚马逊云科技共同成立“联合安全实验室”,旨在加强IoT行业的安全合规能力与…...
Oracle21C--Windows卸载与安装
卸载方法: (1)WinR,输入services.msc,打开服务,把Oracle相关的服务全部停止运行(重要) (2)WinR,输入regedit,打开注册表,删除Oracle开…...
关于 MySQL、PostgresSQL、Mariadb 数据库2038千年虫问题
MySQL 测试时间:2023-8 启动MySQL服务后,将系统时间调制2038年01月19日03时14分07秒之后的日期,发现MySQL服务自动停止。 根据最新的MySQL源码(mysql-8.1.0)分析,sql/sql_parse.cc中依然存在2038年千年虫…...
Linux - Docker 安装使用 常用命令 教程
Docker 官方文档地址: Get Started | Docker 中文参考手册: https://docker_practice.gitee.io/zh-cn/ 1.什么是 Docker 1.1 官方定义 最新官网首页 # 1.官方介绍 - We have a complete container solution for you - no matter who you are and where you are on your contain…...
AtCoder Beginner Contest 318 G - Typical Path Problem 题解
G - Typical Path Problem 题目大意 给定一张 N N N 个点、 M M M 条边的简单无向图 G G G 和三个整数 A , B , C A,B,C A,B,C。 是否存在一条从顶点 A A A 到 C C C,且经过 B B B 的简单路径? 数据范围: 3 ≤ N ≤ 2 1 0 5 3\le …...
21.4 CSS 盒子模型
1. 边框样式 border-style属性: 指定元素的边框样式.常用属性值: - none: 无边框(默认值). - solid: 实线边框. - dotted: 点状边框. - dashed: 虚线边框. - double: 双线边框. - groove: 凹槽状边框. - ridge: 脊状边框. - inset: 内阴影边框. - outset: 外阴影边框.这些值可…...
MybatisPlus入门
MybatisPlus入门 1.MyBatis-Plus1.1 ORM介绍1.2 MyBatis-Plus介绍 2.代码链接数据库2.1 创建项目2.2 添加依赖2.3 链接数据库2.3.1 准备数据库2.3.2 链接数据库2.3.3 创建实体类 2.4 创建Mapper层2.5 创建Controller层2.6 浏览器访问测试 MybatisPlus官方网站: 官网…...
飞腾平台芯片测试固件(SFW)和开机启动log
一、说两句 最近公司飞腾产品越来越多了,FT-2000/4的D2000的X100的,最近又新出了E2000。越来越多新来的小孩儿开始加入到飞腾的调测试中,那么在他们实际的调试中会遇到很多的问题。在固件启动阶段有的板卡会有一些异常,有时我们需…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...
MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
深入理解 C++ 左值右值、std::move 与函数重载中的参数传递
在 C 编程中,左值和右值的概念以及std::move的使用,常常让开发者感到困惑。特别是在函数重载场景下,如何合理利用这些特性来优化代码性能、确保语义正确,更是一个值得深入探讨的话题。 在开始之前,先提出几个问题&…...
