In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces Flutter how to use Canvas simulation to achieve WeChat red packet get the effect of the relevant knowledge, the content is detailed and easy to understand, the operation is simple and fast, with a certain reference value, I believe that after reading this Flutter how to use Canvas simulation to achieve WeChat red packet get the effect of the article will have a harvest, let's take a look.
Effect.
The overall effect achieved is as follows:
After seeing the effect, let's take a look at how the final effect is achieved step by step. Before you start writing the code, do a simple split of the whole effect and divide it into five parts:
Click to pop up the red packet
Overall layout of red packets
The gold coin clicks and rotates
Red packet open animation
The result page pops up
After splitting, it is shown in the following figure:
Then we will do it step by step.
Red packet pops up
Red packet pop-up is mainly divided into two parts: from small to large zoom animation, translucent mask. Naturally thought of using Dialog to achieve, and finally did use Dialog to achieve the corresponding effect, but there was a problem in the final display of the result page, because the opening of the red packet and the result display are carried out at the same time, and the result page is under the red packet. If you use Dialog, there will be the effect of the result page covering the red packet on the Dialog. Finally, you use Overlay to add a Widget at the top level to achieve.
Create a Widget for RedPacket:
Class RedPacket extends StatelessWidget {const RedPacket ({Key? Key}): super (key: key); @ override Widget build (BuildContext context) {return Center (child: Container (width: 0.8.sw, height: 1.2.sw, color: Colors.redAccent,));}}
The content is very simple, that is, a middle width and height of 0.8.sw, 1.2.sw Container, the color is red. Here sw represents the screen width, that is, the width of the red packet is 0.8 times the width of the screen and the height is 1.2 times the width of the screen.
For more information about Flutter screen adaptation, please see: screen adaptation of Flutter Application Framework
Then when you click the button, it is shown through Overlay to create a method of showRedPacket:
Void showRedPacket (BuildContext context) {OverlayEntry entry = OverlayEntry (builder: (context) = > RedPacket (); Overlay.of (context)? .insert (entry);}
The effect is as follows:
The red packet pops up, but because there is no zoom animation, it is very sudden. In order to scale animation, wrap ScaleTransition on Container to scale animation, and change RedPacket to StatefulWidget, because you need to use AnimationController to input SingleTickerProviderStateMixin to use animation. The implementation is as follows:
Class RedPacket extends StatefulWidget {const RedPacket ({Key? Key}): super (key: key); @ override State createState () = > _ RedPacketState ();} class _ RedPacketState extends State with SingleTickerProviderStateMixin {late AnimationController scaleController = AnimationController (vsync: this).. duration = const Duration (milliseconds: 500).. forward () @ override Widget build (BuildContext context) {return Container (color: Color (0x88000000), / semitransparent mask child: Center (child: ScaleTransition (scale: Tween (begin: 0,1.0) .animate (CurvedAnimation (parent: scaleController, curve: Curves.fastOutSlowIn)), child: Container (width: 0.8.sw, height: 1.2.sw Color: Colors.redAccent,) }}
ScaleTransition animates from 0.0 to 1.0, that is, from nothing to the original size, and the animation time is 500ms. At the same time, a layer of Container is wrapped in the outer layer and a translucent color is added to achieve a translucent mask to achieve the final effect:
In this way, the function of the first part is realized.
Red packet layout
The title says it is implemented using Canvas, so the layout of the red packet is mainly implemented using Canvas. Replace the Container of the previous red packet with CustomPaint, and then create a RedPacketPainter that inherits from CustomPainter:
ScaleTransition (scale: Tween (begin: 0.0,1.0) .animate (CurvedAnimation (parent: scaleController, curve: Curves.fastOutSlowIn)), child: CustomPaint (size: Size (1.sw, 1.sh), painter: RedPacketPainter (),)
Taking into account the subsequent animation, the size of the canvas is set to full screen. The core code of the layout of the red packet is in RedPacketPainter. First, the background of the red packet is drawn. The background is divided into two parts, the upper part is composed of a rectangle and an arc, and the lower part is also composed of a rectangle and an arc. The arc of the upper part is protruding, while the lower part is concave. The diagram is as follows:
Initialize:
/ / Brush late final Paint _ paint = Paint (). IsAntiAlias = true;/// path final Path path = Path (); / / height of the red packet: 1.2x screen width late double height = 1.2.swash hand / the end of the upper half of the Bezier curve late double topBezierEnd = (1.sh-height) / 2 + the beginning of the upper half of the Bezier curve late double topBezierStart= topBezierEnd-0.2.sw / / the starting point of the lower part of the Bezier curve late double bottomBezierStart = topBezierEnd-0.4.swPlachap / the center point of the gold coin, then the horizontal center point of Offset goldCenter = Offset.zero;/// is calculated by path, final double centerWidth = 0.5.swinterbank / leftlate double left of the red packet in the whole interface rightlate double right = 0.9.sw of the red packet in the whole interface / the toplate double top = (1.sh-height) / 2 of the red packet in the whole interface / the bottomlate double bottom = (1.sh-height) / 2 + height; in the upper part of the whole interface
The code is implemented as follows:
Void drawTop (ui.Canvas canvas) {path.reset (); path.addRRect (RRect.fromLTRBAndCorners (left, top, right, topBezierStart, topLeft: const Radius.circular (5), topRight: const Radius.circular (5)); var bezierPath = getTopBezierPath (); path.addPath (bezierPath, Offset.zero); path.close (); canvas.drawShadow (path, Colors.redAccent, 2, true); canvas.drawPath (path, _ paint);}
Here, we use Path to draw. First, add a rounded rectangle to the path, that is, the ① part of the diagram, and then obtain the bezierPath of a Bezier curve through getTopBezierPath and add it to the path path. The getTopBezierPath source code is as follows:
Path getTopBezierPath () {Path bezierPath = Path (); bezierPath.moveTo (left, topBezierStart); bezierPath.quadraticBezierTo (centerWidth, topBezierEnd, right, topBezierStart); var pms = bezierPath.computeMetrics (); var pm = pms.first; goldCenter = pm.getTangentForOffset (pm.length / 2)? Offset.zero; return bezierPath;}
GetTopBezierPath source code is divided into two parts, the first part is to create the Bezier curve path, using the initial initialization of the data creation, to achieve the ② part of the diagram; then according to the created Bezier curve path to calculate the coordinates of the middle point in the path, as the gold coin center point coordinates. The schematic diagram is as follows:
The red dot in the picture is the point of the Bezier curve, the middle solid line is the Bezier curve, that is, the Bezier curve path created in the above code, and the point in the middle of the solid line is the central point of the gold coin.
After the Bezier curve is drawn, call drawShadow to draw the shadow. The function is to highlight the effect of the connection between the upper and lower parts. Finally, the effect of the whole upper part is drawn through path, as follows:
The lower half
The code is implemented as follows:
Void drawBottom (ui.Canvas canvas) {path.reset (); path.moveTo (left, bottomBezierStart); path.quadraticBezierTo (centerWidth, topBezierEnd, right, bottomBezierStart); path.lineTo (right, topBezierEnd); path.lineTo (left, topBezierEnd); path.addRRect (RRect.fromLTRBAndCorners (left, topBezierEnd, right, bottom, bottomLeft: const Radius.circular (5), bottomRight: const Radius.circular (5)); path.close (); canvas.drawShadow (path, Colors.redAccent, 2, true) Canvas.drawPath (path, _ paint);}
The implementation of the lower part is also divided into two parts, first draw the Bezier curve, that is, the ③ part of the schematic diagram, then add a rounded rectangle, that is, the ④ part of the schematic diagram, and then draw the shadows and graphics of the lower part, showing the effect of the lower part separately as follows:
Combine the upper and lower parts to achieve the effect of the red packet background, as follows:
Gold coin drawing
After the completion of the background drawing, we will draw the gold coin. The coordinates of the central point of the gold coin have been calculated before. The drawing of the static gold coin is relatively simple, which is a circle. The code is as follows:
Void drawGold (ui.Canvas canvas) {Path path = Path (); canvas.save (); canvas.translate (0.5.sw, goldCenter.dy); _ paint.style = PaintingStyle.fill; path.addOval (Rect.fromLTRB (- 40.w,-40.w, 40.w, 40.w); _ paint.color = const Color (0xFFFCE5BF); canvas.drawPath (path, _ paint); canvas.restore ();}
Here, move the canvas to the center of the gold coin, then add a circle with a radius of 40.w to the Path, and finally draw the path. The effect is as follows:
Gold coin text drawing
After the gold coin is drawn, you also need to draw a traditional "open" character on the gold coin, the code is as follows:
Void drawOpenText (ui.Canvas canvas) {if (controller.showOpenText) {TextPainter textPainter = TextPainter (text: TextSpan (text: "open", style: TextStyle (fontSize: 34.sp, color: Colors.black87, height: 1.0, fontWeight: FontWeight.w400)), textDirection: TextDirection.ltr, maxLines: 1, textWidthBasis: TextWidthBasis.longestLine, textHeightBehavior: const TextHeightBehavior (applyHeightToFirstAscent: false, applyHeightToLastDescent: false).. layout () Canvas.save (); canvas.translate (0.5.sw, goldCenter.dy); textPainter.paint (canvas, Offset (- textPainter.width / 2,-textPainter.height/2)); canvas.restore ();}}
Using TextPainter to draw the text, also move the canvas to the center of the gold coin, and then draw the text, the effect is as follows:
Avatars and words
After the above drawing, the effect has come out, but it is still missing the relevant text of the user profile picture on the cover of the red packet, which can also be realized by using Canvas. However, instead of using Canvas, it is realized by using child of CoustomPaint:
CustomPaint (size: Size (1.sw, 1.sh), painter: RedPacketPainter (controller: controller), child: buildChild (),) Container buildChild () {return Container (padding: EdgeInsets.only (top: 0.3.sh), child: Column (crossAxisAlignment: CrossAxisAlignment.center, children: [Row (mainAxisAlignment: MainAxisAlignment.center) Children: [ClipRRect (borderRadius: BorderRadius.circular (3.w), child: Image.network ("https://p26-passport.byteacctimg.com/img/user-avatar/32f1f514b874554f69fe265644ca84e4~300x300.image", width: 24.w,)), SizedBox (width: 5.w,), Text (" Red packet sent by loongwind ", style: TextStyle (fontSize: 16.sp) Color: Color (0xFFF8E7CB), fontWeight: FontWeight.w500)],), SizedBox (height: 15.w,), Text ("Kung Xi Fat Choi", style: TextStyle (fontSize: 18.sp, color: Color (0xFFF8E7CB))],),)) }
CoustomPaint's child allows you to input an implementation of Widget,Widget that is the profile picture and text to be displayed. The code is as follows:
At this point, the implementation of the whole layout of the red packet is complete.
Gold coin rotates
After completing the static display of the red packet, let's see how to make the red packet move. First, let's see how to make the gold coin rotate.
When it comes to rotation, the first thing that comes to mind is the rotation of the center of the gold coin, which can be achieved through the rotation of the canvas or the transform rotation of path, but through experiments, the gold coin can be rotated in this way, but the three-dimensional effect of rotation is very complex. So in the end, we use two circles to make a certain offset on the x-axis, and then compress the width of the circle to simulate the rotation effect, as shown below:
As shown in the figure, two identical circles are drawn, the two circles are overlapped at the beginning, and then the width of the circle is compressed and the lower circle is offset to the left by a certain unit, resulting in a three-dimensional effect of rotation.
Code:
Void drawGold (ui.Canvas canvas) {Path path = Path (); canvas.save (); canvas.translate (0.5.sw, goldCenter.dy); _ paint.style = PaintingStyle.fill; path.addOval (Rect.fromLTRB (- 40.w,-40.w, 40.w, 40.w); _ paint.color = const Color (0xFFE5CDA8); canvas.drawPath (path, _ paint); _ paint.color = const Color (0xFFFCE5BF); canvas.drawPath (path, _ paint) Canvas.restore ();}
Modify the code above to draw gold coins, set different colors and draw a circle, so that two circles of different colors are drawn in the same place. So how do you get it moving? You can use animation to perform width scaling by scaling the width factor from 1 to 0 and back from 0 to 1. Because CustomPainter inherits from Listenable, and animation is also Listenable, it is more convenient to combine animation with CustomPainter directly.
To facilitate unified control of the animation of red packets, create a RedPacketController, and create an animation and controller to control the rotation of gold coins in it:
Class RedPacketController {final SingleTickerProviderStateMixin tickerProvider; late AnimationController angleController; late Animation angleCtrl; RedPacketController ({required this.tickerProvider}) {initAnimation ();} void initAnimation () {angleController = AnimationController (duration: const Duration (seconds: 3), vsync: tickerProvider).. repeat (reverse: true); angleCtrl = angleController.drive (begin: 1. 0, end: 0);} void dispose () {angleController.dispose () Timer?.cancel ();}}
In order to see the effect of rotation, set the execution time of the animation to 3 seconds and let it repeat, set reverse to true for repeated execution, that is, reverse execution, and then modify _ RedPacketState to mix with SingleTickerProviderStateMixin and create a RedPacketController:
Class _ RedPacketState extends State with SingleTickerProviderStateMixin {late RedPacketController controller = RedPacketController (tickerProvider: this); Widget buildRedPacket () {return GestureDetector (onTapUp: controller.clickGold, child: CustomPaint (size: Size (1.sw, 1.sh), painter: RedPacketPainter (controller: controller), child: buildChild (),);} / /.} class RedPacketPainter extends CustomPainter {RedPacketController controller RedPacketPainter ({required this.controller}): super (repaint:controller.angleController); /...}
The constructor of RedPacketPainter calls super and passes in the repaint parameter, the animation controller that is created.
This allows you to use the animated values when drawing gold coins:
Void drawGold (ui.Canvas canvas) {Path path = Path (); double angle = controller.angleCtrl.value; canvas.save (); canvas.translate (0.5.sw, goldCenter.dy); _ paint.style = PaintingStyle.fill; path.addOval (Rect.fromLTRB (- 40.w * angle,-40.w * angle, 40.w)); _ paint.color = const Color (0xFFE5CDA8); canvas.drawPath (path, _ paint); _ paint.color = const Color (0xFFFCE5BF) Canvas.drawPath (path, _ paint); canvas.restore ();}
Get the value of the current animation through controller.angleCtrl.value, and then multiply this value by the left and right parameters of the circle to see the effect:
The effect is already there, but it is found that it is empty in the middle of the rotation to the minimum, which is not in line with our expectations, so what should we do? Is it not empty to connect the edges of the two circles one by one, as shown in the figure:
Code implementation:
Void drawGoldCenterRect (ui.Path path, ui.Path path3, ui.Canvas canvas) {var pms1 = path.computeMetrics (); var pms2 = path3.computeMetrics (); var pathMetric1 = pms1.first; var pathMetric2 = pms2.first; var length = pathMetric1.length; Path centerPath = Path (); for (int I = 0 I Container (padding: EdgeInsets.only (top: 0.3.sh * (1-controller.translateCtrl.value)), child: Column (...),);}
By dynamically changing the value of paddingTop, the avatar and text are also translated upward. The effect is as follows:
Finally, add a timer to the gold coin click event. After the gold coin rotates for 2 seconds, execute the red packet to open the animation:
Void clickGold (TapUpDetails details) {if (checkClickGold (details.globalPosition)) {if (angleController.isAnimating) {stop ();} else {angleController.repeat (reverse: true); tickerProvider.setState (() {showOpenText = false;}); timer = Timer (const Duration (seconds: 2), () {stop ();}) } void stop () async {if (angleController.isAnimating) {/ stop the gold coin animation to make the animation look more natural if (angleController.status = = AnimationStatus.forward) {await angleController.forward (); angleController.reverse ();} else if (angleController.status = = AnimationStatus.reverse) {angleController.reverse ();} tickerProvider.setState (() {showOpenBtn = false;}); translateController.forward () }}
In this way, after clicking on the gold coin, the gold coin rotates for 2 seconds and then opens the red packet.
Result pop-up
The result page is a new interface, which executes synchronously when the red packet is enabled, and has a gradient animation, which is implemented by adding animation when the route jumps, as follows:
Void onOpen () {Navigator.push (context, PageRouteBuilder (transitionDuration: const Duration (seconds: 1), pageBuilder: (context, animation, secondaryAnimation) = > FadeTransition (opacity: animation, child: const ResultPage (),));}
Add a callback when the red packet is enabled and a callback when the animation of the red packet is completed to RedPacket. The former is used to jump to the result page, and the latter is used to remove Overlay:
OverlayEntry? Entry;void showRedPacket (BuildContext context, Function? OnOpen) {entry = OverlayEntry (builder: (context) = > RedPacket (onFinish: _ removeRedPacket, onOpen: onOpen,)); Overlay.of (context)? .insert (entry!);} void _ removeRedPacket () {entry?.remove (); entry = null;}
Called when the gold coin rotation animation stops:
Void stop () async {if (angleController.isAnimating) {/... TranslateController.forward (); onOpen?.call ();}}
Call onFinish callback when the animation of the red packet is completed, and add listening to the final translation animation of the red packet to achieve:
TranslateController.addStatusListener ((status) {if (status = = AnimationStatus.completed) {onFinish?.call ()}})
OK, it's done, and let's see what happens in the end:
This is the end of the article on "how Flutter uses Canvas simulation to achieve WeChat red packet's receiving effect". Thank you for reading! I believe you all have a certain understanding of "how Flutter uses Canvas simulation to achieve WeChat red packet's effect". If you want to learn more, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.