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

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这四个角色&#xff0c;它们一起配合来完成一个…...

【python】可视化

柱状图 matplotlib之pyplot模块之柱状图&#xff08;bar()&#xff1a;基础参数、外观参数&#xff09;_plt.bar_mighty13的博客-CSDN博客 bar()的基础参数如下&#xff1a; x&#xff1a;柱子在x轴上的坐标。浮点数或类数组结构。注意x可以为字符串数组&#xff01; height&…...

C++继承多接口,调用虚函数跳转到错误接口的虚函数的奇怪问题

问题重现 定义了两个接口IA IB class IA{public:virtual void funA() = 0; }; class IB{public:virtual void funB() = 0; }...

C++:日期类

学习目标&#xff1a; 加深对四个默认构造函数的理解&#xff1a; 1.构造函数 2.析构函数 3.拷贝构造 4.运算符重载 实现功能 1.比较日期的大小 2.日期-天数 3.前/后置&#xff0c;-- 这里基本会使用运算符重载 定义一个日期类 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内存寻找重复元素 题目&#xff1a;给定一个数组&#xff0c;包含从1到N的整数&#xff0c;N最大为32000&#xff0c;数组可能还有重复值&#xff0c;且N的取值不定&#xff0c;若只有4KB的内存可用&#xff0c;该如何打印数组中所有重复元素。 分析&#xff1a; 本身是…...

qemu编译与使用

文章目录 1、安装依赖2、下载qemu源码3、编译4、运行5、qemu参数 qemu 是一个硬件虚拟化程序&#xff08;hypervisor that performs hardware virtualization&#xff09;&#xff0c;与传统的 VMware / VirtualBox 之类的虚拟机不同&#xff0c;它可以通过 binary translation…...

bazel远程构建(Remote Execution)

原理 既然 ActionResult 可以被不同的 Bazel 任务共享&#xff0c;说明 ActionResult 和 Action 在哪里执行并没有关系。因此&#xff0c;Bazel 在构建时&#xff0c;可以把 Action 发送给另一台服务器执行&#xff0c;对方执行完&#xff0c;向 CAS 上传 ActionResult&#x…...

uniapp 微信小程序仿抖音评论区功能,支持展开收起

最近需要写一个评论区功能&#xff0c;所以打算仿照抖音做一个评论功能&#xff0c;支持展开和收起&#xff0c; 首先我们需要对功能做一个拆解&#xff0c;评论区功能&#xff0c;两个模块&#xff0c;一个是发表评论模块&#xff0c;一个是评论展示区。接下来对这两个模块进行…...

js:创建一个基于vite 的React项目

相关文档 Vite 官方中文文档React 中文文档React RouterRedux 中文文档Ant Design 5.0Awesome React 创建vite react项目 pnpm create vite react-app --template react# 根据提示&#xff0c;执行命令 cd react-app pnpm install pnpm run dev项目结构 $ tree -L 1 . ├─…...

论文阅读_医疗知识图谱_GraphCare

英文名称: GraphCare: Enhancing Healthcare Predictions with Open-World Personalized Knowledge Graphs 中文名称: GraphCare&#xff1a;通过开放世界的个性化知识图增强医疗保健预测 文章: http://arxiv.org/abs/2305.12788 代码: https://github.com/pat-jj/GraphCare 作…...

Android 蓝牙开发( 四 )

前言 上一篇文章给大家分享了Kotlin版的Android蓝牙的基础知识和基础用法&#xff0c;不过上一篇都是一些零散碎片化的程序&#xff0c;&#xff0c;这一篇给大家分享Android蓝牙开发实战项目KotlinCompose的初步使用 效果演示 : Android Compose 蓝牙开发 Android蓝牙实战开发…...

涂鸦智能携手亚马逊云科技 共建“联合安全实验室” 为IoT发展护航

2023年8月31日&#xff0c;全球化IoT开发者平台涂鸦智能&#xff08;NYSE: TUYA&#xff0c;HKEX: 2391&#xff09;在“2023亚马逊云科技re:Inforce中国站”大会宣布与全球领先的云计算公司亚马逊云科技共同成立“联合安全实验室”&#xff0c;旨在加强IoT行业的安全合规能力与…...

Oracle21C--Windows卸载与安装

卸载方法&#xff1a; &#xff08;1&#xff09;WinR&#xff0c;输入services.msc,打开服务&#xff0c;把Oracle相关的服务全部停止运行&#xff08;重要&#xff09; &#xff08;2&#xff09;WinR&#xff0c;输入regedit&#xff0c;打开注册表&#xff0c;删除Oracle开…...

关于 MySQL、PostgresSQL、Mariadb 数据库2038千年虫问题

MySQL 测试时间&#xff1a;2023-8 启动MySQL服务后&#xff0c;将系统时间调制2038年01月19日03时14分07秒之后的日期&#xff0c;发现MySQL服务自动停止。 根据最新的MySQL源码&#xff08;mysql-8.1.0&#xff09;分析&#xff0c;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&#xff0c;且经过 B B B 的简单路径&#xff1f; 数据范围&#xff1a; 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官方网站&#xff1a; 官网…...

飞腾平台芯片测试固件(SFW)和开机启动log

一、说两句 最近公司飞腾产品越来越多了&#xff0c;FT-2000/4的D2000的X100的&#xff0c;最近又新出了E2000。越来越多新来的小孩儿开始加入到飞腾的调测试中&#xff0c;那么在他们实际的调试中会遇到很多的问题。在固件启动阶段有的板卡会有一些异常&#xff0c;有时我们需…...

【大数据实训】基于Hive的北京市天气系统分析报告(二)

博主介绍&#xff1a;✌全网粉丝6W,csdn特邀作者、博客专家、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于大数据技术领域和毕业项目实战✌ &#x1f345;文末获取项目联系&#x1f345; 目录 1. 引言 1.1 项目背景 1 1.2 项目意义 1 2.…...

WPF列表样式

WPF的数据绑定系统自动生成列表项对象&#xff0c;为单个项应用所需的样式不是很容易。解决方案是ItemContainerStyle 属性。如果设置了ItemContainerStyle 属性&#xff0c;当创建列表项时&#xff0c;列表控件会将其向下传递给每个项。对于ListBox控件&#xff0c;每个项有Li…...

Android逆向学习(二)vscode进行双开与图标修改

Android逆向学习&#xff08;二&#xff09;vscode进行双开与图标修改 写在前面 这其实应该还是吾爱的第一个作业&#xff0c;但是写完上一个博客的时候已经比较晚了&#xff0c;如果继续敲机械键盘吵到室友&#xff0c;我怕我看不到明天的太阳&#xff0c;所以我决定分成两篇…...

一个基于YAPI接口生产代码的开源工具

前后端分离的开发模式是一种趋势&#xff0c;但如果缺少好的开发工具跟管理模式&#xff0c;会使得前后端开发人员相互等待&#xff0c;扯皮等问题。从而影响项目的交付进度。 通过实践摸索&#xff0c;YAPI是一款很适合前后端分离开发的协助工具。它以项目为维度&#xff0c;可…...

Redis 缓存穿透击穿和雪崩

一、说明 Redis 缓存的使用&#xff0c;极大的提升了应用程序的性能和效率&#xff0c;特别是数据查询方面。但同时&#xff0c;它也带来了一些问题。其中&#xff0c;最要害的问题&#xff0c;就是数据的一致性问题&#xff0c;从严格意义上讲&#xff0c;这个问题无解。如果对…...

在windows上配置ninja环境

ninja使用并行任务来编译工程&#xff0c;比cmake编译快了一个数量级&#xff0c;是谷歌在2010年为了提高cmake的编译速度而开发一款编译工具。下面介绍在windows上配置ninja环境。 1 下载ninja ninja官网地址&#xff1a; https://github.com/ninja-build/ninja/releases   …...

③matlab向量和矩阵

目录 手动输入数组 创建等间距向量 数组创建函数 手动输入数组 1.背景 单个称为标量的数值实际上是一个 11 数组&#xff0c;也即它包含 1 行 1 列。 任务 创建一个名为 x 并且值为 4 的变量。 2.您可以使用方括号创建包含多个元素的数组。 x [3 5] x 3 5 任务 …...

一、了解[mysql]索引底层结构和算法

目录 一、索引1.索引的本质2.mysql的索引结构 二、存储引擎1.MyISAM2.InnoDB3.为什么建议InnoDB表要建立主键并且推荐int类型自增&#xff1f;4.innodb的主键索引和非主键索引&#xff08;二级索引&#xff09;区别5.联合索引 一、索引 1.索引的本质 索引:帮助mysql高效获取数…...

DockerFile常用命令

以下是常见的Dockerfile命令&#xff1a; FROM&#xff1a;FROM命令用于指定基础镜像。基础镜像是构建镜像的起点。例如&#xff0c;FROM ubuntu:latest表示使用最新版本的Ubuntu作为基础镜像。 MAINTAINER&#xff1a;MAINTAINER命令用于指定镜像的维护者信息。一般格式为&am…...

Android 动画之插值器PathInterpolator

Android 的View动画、属性动画都可以设置动画插值器&#xff0c;以此来实现不同的动画效果。 这篇文章 Android View动画整理 有介绍各种插值器的效果&#xff0c;这一篇专访 PathInterpolator 。 参考官网 添加曲线动作 &#xff0c; PathInterpolator 基于 贝塞尔曲线 或 …...