Dart supports Map information type. You can copy a Map into another one utilizing different strategies. There are two sorts of copy, shallow copy, and Deep copy. Understanding the distinction between those two is important before you pick how to copy a map.
Thisarticle will explore the Shallow & Deep Copy a Map In Dart. We will execute a demo program and I might want to tell you how to copy a Map in Dart and explain the difference between shallow copy and deep copy in your applications.
A shallow copy means the main object which is the Map is copied, however, the internal objects (the components) are not. An object can be mutable or changeless.
If the component is immutable and you change the value, Dart can not adjust it and another object with an alternate memory area will be made.
Subsequently, utilizing shallow copy ought to be protected if the component sort of the Map is immutable, like String, bool, int, or bool. The following are instances of shallow copy utilizing Dart’s strategies.
Using Map.of:
The Map.of factory technique can be utilized to copy a Map into a another one.
factory Map.of(Map<K, V> other)
Demo:
var values = <int, String>{ 1: 'red', 2: 'green', 3: 'blue', }; var newValues = Map.of(values);
Using Map.from:
This technique is likeMap.of, however, you can utilize it to produce another Map whose key as well as component type is a subtype of the source key or component type.
factory Map.from(Map other)
Making another Map with additional exact types is utilized. You need to ensure that all the keys and values have the more exact types.
While shallow copy works for a Map with immutable components, you might have to involve a deep copy for a Map with mutable components. Utilizing the models above, assuming that the component is mutable, Dart will just copy the reference to the object.
The actual object isn’t copied. Consequently, assuming that you alter a component of the source, it additionally influences the element of the new Map. On the off chance that you don’t need that way of behaving, you need to clone every component by making another object.
For demo, we have a Map whose component type is Item. To make another Item object from a current one, we can make a factory technique clone.
From that point forward, use map the technique to map every component. You want to return a MapEntry and utilize the cloning strategy above to copy the mutable object.
var item1 = Item(name: 'red'); var item2 = Item(name: 'green'); Map<int, Item> source = {1: item1, 2: item2}; var clone = source.map((key, value) => MapEntry(key, Item.clone(value))); item1.name = 'green'; print(source[1]?.name); // Green print(clone[1]?.name); // Red
Conclusion:
In the article, I have explained the Shallow & Deep Copy a Map In Dart; you can modify this code according to your choice. This was a small introduction to the Shallow & Deep Copy a Map In Dart User Interaction from my side, and it’s working using Flutter.
That is how to copy a Map in Dart. If the Map just holds back immutable key and component values, shallow values ought to be sufficient. If either the key or value has mutable components, you might need to perform a deep copy.
I hope this blog will provide you with sufficient information on Trying the Shallow & Deep Copy a Map In Dart of your projects. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
Wewelcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
The loader is utilized when the application is loading while information is coming from the Application programming interface or DataBase. The loader helps show loading when the application is in a loading state.
This article will Explore an Animated Loader In Flutter.We will perceive how to execute a demo program and we are going to learn about how we can create an animated loader using the loading_animation_widget package in your Flutter applications.
This demo video shows how to create an animated loader in Flutter and how an animated loader will work using the loading_animation_widget package in your Flutter applications. We will show users different types of loaders. Users can choose one of the loaders for our projects. It will be shown on your device.
Demo Module::
Implementation:
Step 1: Add the dependencies
Add dependencies to pubspec — yaml file.
dependencies: flutter: sdk: flutter loading_animation_widget: ^latest version
In the article, I have explained the Animated Loader in a flutter; you can modify this code according to your choice. This was a small introduction toAnimated Loader On User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying the Animated Loader in your Flutter projects. We will show you what the Introduction is. Make a demo program for working on Animated Loader Using the loading_animation_widget package in your Flutter applications. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
Wewelcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
This article will explore the Sorting List of Objects/Maps By Date In Flutter.We will perceive how to execute a demo program and we are going to learn about how we can use it in your applications.
The point is to utilize the sort() technique for the List class and pass a custom correlation capability that utilizes the compareTo() strategy for the DateTime class:
myList.sort ((a, b) { // for ascending order return a.date.compareTo (b.date);
// for descending order // return b.date.compareTo (a.date); });
Sorting a List of Objects by Date:
Suppose you have a list of users. The data of every user is stored away in an object, and your supervisor requests that you reorder these users by their join date. The model underneath will show you to tackle this:
The code:
class User { final String name; final String email; final DateTime joinDate;
In this model, the data about a user is stored away on a map rather than an object. Other than that, the join date of a user is a string, not a DateTime object. Hence, we should parse it into a DateTime object first utilizing the DateTime.parse() or DateTime.tryParse() strategy before playing out the comparison.
In the article, I have explained the sorting list of Objects/Maps By Date In Flutter; you can modify this code according to your choice. This was a small introduction to Sorting a List of Objects/Maps By Date In Flutter User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on how to try the Sorting List of Objects/Maps by the date of your flutter projects. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
Wewelcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
In Flutter, Speed Dial is a well-known floating action button (FAB) variation generally used to give users admittance to different actions or choices from a single button. At the point when the FAB is tapped, it extends to rapidly uncover a list of extra more modest buttons or actions, empowering users to perform related errands.
This article will Explore Speed Dial In Flutter. We will implement a demo program and I would like to show how to use speed dial in Flutter using the flutter_speed_dial package in your Flutter applications.
A Speed Dial in Flutter is a proficient and easy-to-use method for dealing with various actions in a single Floating Action Button. It works on UI/UX plan while further developing availability to key elements.
This demo video shows how to use speed dial in Flutter and how a speed dial will work using the flutter_speed_dial package in your Flutter applications. We will show a user a fab button on a screen when the user presses the button it expands to reveal a list of additional smaller buttons or actions by using the flutter_speed_dial package. It will be shown on your device.
Step 3: Run flutter packages get in the root directory of your app.
Code Implement:
You need to implement it in your code respectively:
Create a new dart file called main.dart inside the lib folder.
In the main.dart file, we will create a new class was SpeedDialDemo(). In this new class, we will add the body. In the body we will add the center widget. Inside the widget, we will add an Image with height and width and text is ‘PLease tap the FAB button’.
Then, now we will add the floatingActionButton. In this button we will add SpeedDial() function. Inside this function, we will add animatedIcon, backgroundColor, foregroundColor, overlayColor, overlayOpacity, etc.
Its children, we will add three SpeedDialChild() function. In this function, we will three icons on the child, label and onTap(). When user tap the the button is expands and show icons.
When we run the application, we ought to get the screen’s output like the underneath screen capture.
In the article, I have explained the spead dial in a flutter; you can modify this code according to your choice. This was a small introduction tospeed dial On User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying the Speed Dial in your flutter projects. We will show you what the Introduction is. Make a demo program for working on speed dial Using the flutter_speed_dial package in your flutter applications. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, Twitter, and LinkedIn for any flutter-related queries.
Wewelcome feedback and hope you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
Flutter has quickly become one of the most popular frameworks for building cross-platform mobile apps. With its rich widget ecosystem, beautiful UIs, and seamless performance across iOS and Android, Flutter is an attractive choice for developers. However, behind the scenes, Flutter’s architecture is based on a highly optimized and custom rendering pipeline that ensures it runs efficiently and provides developers with great flexibility.
In this post, we will examine Flutter’s internal architecture, focusing on its engine, rendering pipeline, and widget drawing on the screen. We will also discuss how Dart interacts with Skia, Flutter’s graphics library, and the custom rendering system that powers its high performance.
Overview of Flutter’s Architecture
Flutter’s architecture comprises several layers that work together to provide an efficient, high-performance development experience. Let’s start with a quick overview of the key components:
Dart App: It composes widgets into the desired user interface (UI) and implements the business logic necessary for the application. This involves arranging the widgets in a way that meets the design requirements and ensuring the app’s functionality is driven by the appropriate business rules and processes.
Flutter Framework (Dart-based): This is the top layer of Flutter where developers work directly. It includes all the widgets, libraries, and tools to create the app’s UI and business logic. The framework itself is written in Dart, which provides an expressive, easy-to-learn programming environment.
Flutter Engine: This is the core engine written in C++ that powers Flutter’s rendering capabilities. It handles low-level operations such as rendering, input handling, text layout, and more. The engine communicates with the underlying platform (iOS/Android) through platform channels to access native features.
Platform Layer: This layer provides access to the device’s platform-specific features such as sensors, cameras, geolocation, etc. Flutter communicates with this layer using platform channels, which allow the Dart code to interact with native code (Java/Kotlin for Android and Swift/Objective-C for iOS).
Embedder: The system coordinates with the underlying operating system to gain access to essential services, such as rendering surfaces, accessibility, and input management. It also takes responsibility for managing the event loop, ensuring that events are processed efficiently. Additionally, the system exposes a platform-specific API that allows the Embedder to be integrated seamlessly into applications, enabling smooth interaction with the operating system’s services and resources.
Runner: It composes the components exposed by the platform-specific API of the Embedder into an app package that is runnable on the target platform. This process is an integral part of the app template generated by the flutter create command, ensuring that the necessary resources and configurations are in place for the app to function properly on the specified platform.
Flutter Engine: The Heart of Rendering
The Flutter Engine is the core of Flutter’s performance and rendering. It is written in C++ and is responsible for managing the entire lifecycle of a Flutter app. The engine provides several essential components, including:
Dart VM: Flutter runs Dart code using the Dart Virtual Machine (VM). This VM is highly optimized for Flutter and enables efficient execution of business logic. During development, Flutter uses Just-In-Time (JIT) compilation to speed up the development cycle. In production, Ahead-Of-Time (AOT) compilation is used for optimized performance.
Skia Graphics Library: Skia is a 2D graphics library used by Flutter to draw everything from simple shapes, text, and images to complex animations. Skia provides hardware-accelerated rendering, making it ideal for Flutter’s performance-oriented needs.
Text Layout: Flutter uses Skia’s text layout engine to render text across various fonts, languages, and styles. It includes features such as font rasterization and text shaping.
Platform Channels: Flutter’s engine also manages communication with native platform code through platform channels, allowing Flutter apps to access native features like camera, geolocation, and more.
The Flutter Rendering Pipeline: How the UI is Drawn
One of the most interesting aspects of Flutter’s architecture is its custom rendering pipeline. Unlike many mobile UI frameworks, Flutter does not rely on the native platform’s rendering system. Instead, it builds its UI using its own set of widgets, which it then renders via Skia. Let’s walk through the rendering pipeline step by step:
1. Widget Creation
In Flutter, everything is a widget. Widgets are the building blocks of the UI, and they describe what should appear on the screen. However, widgets themselves do not draw anything. They are immutable and declarative, meaning that when a widget is updated, it results in a new widget tree being created.
This widget does not actually paint anything on the screen. It simply describes that there should be text with the specified style. Flutter uses a widget tree to manage the app’s UI, where each widget represents a part of the UI (like text, images, buttons, etc.).
2. Element Tree
Widgets are lightweight and immutable. When a widget changes, it doesn’t modify the existing widget directly; instead, it creates a new widget. The Flutter framework converts this widget tree into an Element tree.
An Element is a runtime representation of a widget and holds references to the widget’s state. This allows Flutter to keep track of the UI and the state of each widget efficiently.
3. RenderObject Tree
Once the element tree is established, Flutter transforms it into a RenderObject tree. RenderObjects are the low-level objects responsible for laying out and painting widgets on the screen. They handle the layout of widgets in terms of size and position.
The RenderObject tree can be thought of as a more detailed version of the widget tree, where each object has the responsibility for rendering itself. For instance, a Container widget might be represented as a RenderBox object.
In this example, the Container widget would have a corresponding RenderBox that handles the layout and painting of the text and the padding inside.
4. Layout Phase
The layout phase is responsible for determining the size and position of every widget. It starts at the root of the RenderObject tree and moves downward, recursively calculating the layout of each widget.
In the layout phase, each RenderObject must decide its size (width and height) and its position relative to its parent and children. Flutter’s layout system is highly flexible, allowing widgets to behave in a variety of ways (e.g., wrapping, expanding, or aligning).
Here’s an example of a Column widget containing two children
During the layout phase, the Column will calculate the size and position of the two Text widgets, aligning them vertically.
5. Paint Phase
Once the layout phase is completed, Flutter enters the paint phase. This is when the actual drawing happens. In this phase, each RenderObject will paint itself onto the screen using the Canvas API.
For example, the Text widget will use Skia’s text rendering capabilities to draw the text, while a Container might use a rectangle to render its background.
renderBox.paint(canvas, offset);
In this code, renderBox is the RenderObject associated with the widget, and paint() is responsible for drawing the widget onto the screen.
6. Compositing
Once the widgets are painted, Flutter may need to combine the rendered layers into a single image that can be displayed on the screen. This process is called compositing.
Flutter uses a layered compositing system to combine multiple layers of UI elements. This allows Flutter to optimize the rendering process, ensuring that only the parts of the screen that have changed need to be redrawn.
For example, if a Container widget changes, only that widget’s layer will be re-rendered, not the entire screen.
Layers
Layers are an important concept of the Flutter framework, which are grouped into multiple categories in terms of complexity and arranged in the top-down approach. The topmost layer is the UI of the application, which is specific to the Android and iOS platforms. The second topmost layer contains all the Flutter native widgets. The next layer is the rendering layer, which renders everything in the Flutter app. Then, the layers go down to Gestures, foundation library, engine, and finally, core platform-specific code. The following diagram specifies the layers in Flutter app development.
Skia: The Graphics Engine Behind Flutter
One of the central pillars of Flutter’s performance and rendering capabilities is Skia, an open-source 2D graphics library that powers much of Flutter’s graphical rendering. Skia provides an efficient and flexible framework for drawing complex visual elements such as text, images, shapes, and animations on the screen. It is a low-level graphics engine used by both Android and Chrome, but Flutter leverages it as its primary means of rendering UI content. Skia’s high-performance rendering system is one of the main reasons Flutter apps can run so smoothly across platforms.
Key Features of Skia in Flutter
Here are the most crucial features of Skia, which are leveraged by Flutter to render high-performance graphics:
Cross-Platform Rendering: Skia is platform-agnostic, meaning it can be used across various platforms, including Android, iOS, macOS, Linux, and Windows. Since Flutter relies on Skia for rendering, it can ensure consistent visual fidelity across all platforms.
Low-Level Graphics API: Skia provides a low-level API to interact with 2D drawing primitives like paths, text, and bitmaps. Flutter interacts with Skia using this API to render widgets and layouts to the screen efficiently.
GPU Acceleration: One of the most important aspects of Skia’s performance is its ability to leverage GPU acceleration for rendering tasks. Skia uses OpenGL, Vulkan, Metal, and other platform-specific graphics APIs to offload rendering to the GPU, which makes rendering smoother and more efficient, particularly when dealing with animations and complex visual effects.
Vector Graphics: Skia supports vector graphics, which means that the visual elements drawn on the screen can be scaled up or down without losing quality. This is particularly important for Flutter apps, as it ensures that the UI looks crisp on devices with varying screen sizes and resolutions.
High-Performance Text Rendering: Skia comes with a robust text rendering engine capable of high-performance text layout, including the ability to handle complex scripts, kerning, text alignment, and font rasterization. Flutter uses Skia’s text rendering capabilities for all its text-based widgets, ensuring that text is drawn accurately and efficiently.
Image Rendering: Skia is responsible for rendering images in Flutter as well. Whether it’s raster images (like PNGs, JPEGs) or vector images (like SVGs), Skia is used to efficiently display these images with high performance. It also supports hardware-accelerated image manipulation, which makes operations like image scaling and transformations fast and efficient.
Skia handles the low-level drawing operations, while Flutter’s engine controls the rendering pipeline, managing the communication between the Dart code and Skia.
Dart and Skia: How They Communicate
Flutter’s use of Dart for the business logic of the application and Skia for rendering might seem like a disconnect, but thanks to the Flutter engine, these two layers work together seamlessly. The engine acts as a bridge between the high-level Dart code and the low-level Skia rendering commands.
When you write your Flutter app using Dart, you’re primarily working with Widgets that describe the structure and behavior of your UI. However, once the widget tree is constructed, the Flutter engine translates these high-level descriptions into low-level rendering commands that Skia can process.
The Dart VM and Skia work together to make sure Flutter’s rendering pipeline runs smoothly. The Dart code, running in the Dart VM, is responsible for creating the widget tree and managing the app’s state. When a widget needs to be drawn, the Dart code interacts with the Flutter engine, which then communicates with Skia to render the widget to the screen.
Dart communicates with Skia through the Flutter engine, which acts as a bridge. The engine converts the high-level widget description in Dart into low-level drawing commands that Skia can understand. Skia, in turn, takes care of the actual drawing operations, using GPU resources when available to speed up rendering.
This separation allows Flutter to remain efficient while providing developers with a high-level declarative API to build UIs. By abstracting away the details of low-level rendering, Flutter enables developers to focus on building beautiful and performant apps without needing to worry about graphics rendering details.
How Dart and Skia Communicate:
Dart VM: When you write Dart code, it’s compiled by the Dart VM. During development, Just-In-Time (JIT) compilation is used, which makes hot-reloading possible. In production, Ahead-Of-Time (AOT) compilation ensures faster startup times and better performance.
Flutter Engine: The engine contains a C++ layer that acts as an intermediary between Dart and Skia. It translates the layout and painting instructions from Dart into commands that Skia can process.
Skia: Skia is where the actual drawing happens. It interacts with the hardware through GPU APIs (like OpenGL, Vulkan, and Metal) to render the graphics and text to the screen. The Canvas API in Flutter acts as a wrapper around Skia’s lower-level functions, allowing you to draw shapes, images, and text.
For instance, when you call a setState() method in your Flutter app, which causes the widget tree to rebuild, Flutter’s engine will rebuild the RenderObject tree, and any changes to the layout or appearance of the UI will be communicated to Skia to be redrawn.
For example, consider the following Flutter widget that draws a circle:
Consider a scenario where you want to draw a custom shape (say, a custom circle) using Flutter’s CustomPainter class. The CustomPainter allows you to use Skia’s rendering API to draw shapes directly onto the screen. Here’s an example of how you might do this:
// Drawing a circle using Skia's Canvas API canvas.drawCircle(Offset(size.width / 2, size.height / 2), 50, paint); }
@override bool shouldRepaint(CustomPainter oldDelegate) { return false; // We don't need to repaint unless the custom painter logic changes } }
class MyCustomPaintWidget extends StatelessWidget { @override Widget build(BuildContext context) { return CustomPaint( painter: CirclePainter(), size: Size(200, 200), // Size of the area to paint ); } }
In this example:
CustomPainter extends CustomPainter and overrides the paint() method, which is called to render the widget.
Canvas is used to draw the circle. Internally, the drawCircle method uses Skia’s API to paint the circle onto the screen.
The Paint object specifies the color and the style of the drawing.
Skia is at the heart of this process, enabling Flutter to draw the custom shapes using optimized, low-level rendering routines.
Deep Dive into Flutter’s Rendering Pipeline
Now, let’s go even deeper into understanding how Flutter’s rendering pipeline works and how it helps Flutter achieve its high performance. The rendering pipeline is the series of steps that take place after the widget tree is built and before the app’s UI is displayed on the screen. This process allows Flutter to efficiently transform widget descriptions into pixel-perfect visuals, and it involves key components like Widget Trees, Element Trees, RenderObject Trees, Layout, Painting, and Compositing.
Each of these steps plays a crucial role in ensuring that Flutter apps perform well, even when complex UIs and animations are involved.
Widget Tree to RenderObject Tree: The Transformative Process
The journey from a simple Text widget to a rendered element on the screen starts with the widget tree. Each widget defines part of the UI (e.g., a button, text field, etc.). When a widget is placed inside another widget, Flutter’s framework begins by converting the widget tree into an Element tree and then into a RenderObject tree.
Widget Tree
The widget tree is a hierarchy of Flutter widgets that are declarative descriptions of the UI. Widgets are lightweight and immutable, meaning that when a widget changes, it creates a new widget. For example, if the text in a Text widget changes, the widget tree is recreated with the new text value.
Element Tree
The Element tree is a more efficient representation of the widget tree that exists at runtime. Each Element corresponds to a widget in the widget tree and stores references to its state. Unlike widgets, which are immutable, elements can have state, making them ideal for managing the UI’s changes during execution.
RenderObject Tree
The RenderObject tree is the most crucial part of the rendering pipeline. The RenderObject represents the visual elements that Flutter needs to draw on the screen. Every RenderObject has properties such as size, position, paint, and layout constraints that help it define how the widget should appear and behave. The RenderObject tree is responsible for rendering the app’s UI and handles tasks such as layout and painting.
Layout Phase: Determining Size and Position
The layout phase of the Flutter rendering pipeline determines the size and position of each widget on the screen. During this phase, each RenderObject must figure out its size based on its parent’s constraints and the available space in the layout.
The layout phase is hierarchical. It starts from the root of the tree and recursively processes each child. Here’s how the layout process works:
Parent Constraints: The parent widget gives constraints to its child. For example, if you have a Row widget with two Text widgets inside, the Row widget determines how much space the child widgets can occupy.
Size Determination: Each child widget (RenderObject) will calculate its size based on these constraints. For example, if the parent widget is a Column, it might impose constraints that tell its children to expand vertically, or if the parent is a Row, the children might be constrained to expand horizontally.
Positioning: After each child widget determines its size, Flutter positions the widgets in the layout tree by calculating their offsets (x and y positions). This ensures that each widget is placed correctly on the screen relative to its parent.
In a typical Column widget, for example, each child is positioned vertically, with padding and spacing taken into account during the layout phase.
Here, during the layout phase, the Column widget will position each child vertically, taking into account the padding for the first Text widget and the space needed for the RaisedButton.
Paint Phase: Rendering Visuals to the Screen
The paint phase is when the actual drawing happens. After the layout phase has calculated where each widget should be positioned, it’s time to paint the widgets. This phase utilizes the Canvas API, which is where Skia comes into play.
The Canvas is a central component of Flutter’s rendering system, and it provides methods to draw shapes, text, images, and more. Each RenderObject can paint itself on the canvas by calling specific methods.
For example, a simple Container widget might use a RenderBox to draw a rectangle, while a Text widget might use a text drawing method.
Example: Custom Painter for Drawing Shapes
Let’s look at a basic example where we use a CustomPainter to draw a shape (circle) on the screen.
In this example, the CirclePainter class extends CustomPainter. The paint method is where the actual drawing happens. Here, we are using Skia’s canvas.drawCircle method to draw a blue circle at the center of the given size. This is an example of how Flutter uses the Canvas API to interact with Skia to render graphics on the screen.
Compositing: Combining Layers for Efficient Rendering
Once the widgets are painted, Flutter enters the compositing phase, where it combines different layers of the UI into a single image to be displayed on the screen. Flutter’s compositing system ensures that only the parts of the screen that need to be updated are redrawn.
In this phase, Flutter uses a layered compositing model, where each widget’s painted output is stored in a layer. These layers are then composited into a single image that will be displayed on the screen. The advantage of this approach is that Flutter only re-renders the portions of the screen that have changed, rather than redrawing the entire screen.
For instance, if a button changes color on tap, only the button’s layer needs to be updated, not the entire screen. This results in significant performance gains, especially in complex applications with many UI elements.
Here’s an example of how layers can be used for custom painting with CustomPaint:
CustomPaint( painter: CirclePainter(), )
When Flutter draws the CirclePainter, the painted content is stored in a layer. If this layer needs to be updated (for instance, if the circle’s position or color changes), only this layer is recomposited. This makes Flutter apps extremely efficient when updating the UI.
Conclusion
Understanding the internals of Flutter’s architecture, its custom rendering pipeline, and the relationship between Dart and Skia is crucial for developers aiming to fully leverage Flutter’s capabilities. Flutter’s approach to UI rendering, with a custom pipeline based on Skia, enables it to deliver high performance and consistent results across platforms. This architecture not only makes Flutter fast and flexible but also empowers developers to create sophisticated UIs with full control over rendering.
By learning about the engine, the rendering process, and how Flutter draws widgets on screen, you can optimize your Flutter apps further, troubleshoot performance issues, and even build custom rendering solutions when needed.
At What the Flutter, we love working with Flutter apps to make them high-performing that delight users. Contact us today to discuss how we can optimize your Flutter app performance.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project hourly or full-time as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
Wewelcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
This article will explore the Show/Hide Password Using Riverpod In Flutter. We will implement a demo program and I would like to show how to show/hide password in TextFormField by usingtheRiverpod state management in your flutter applications.
This demo video shows how to show/hide passwords in textformfield in flutter and how a show/hide password will work using the hooks_riverpod package in your flutter applications. We will show a user show/hide password on a textformfield by using riverpod and also use will once we click outside of the TextFormField keyboard will close. It will be shown on your device.
Demo Module ::
Implementation:
Step 1: Add the dependencies
Add dependencies to pubspec — yaml file.
dependencies: flutter: sdk: flutter hooks_riverpod: ^latest version
This is the provider we will use for show and hide.
final showPassProvider = StateProvider<bool>((ref) => true);
Now we will create a new class HomeScreen with extended ConsumerWidget. We will return the GestureDetector widget. In this widget, we will add a Column widget. And ad two textformfield.
Since obscureText is true in the beginning. We will set showPassState in obscureText.
TextFormField( // hide the password. when it is true. obscureText: showPassState, ...
Then, at that point, we ought to update our state for symbol click. To do that We involved IconButton in our suffixIcon. That’s what to do, we ought to read and afterward call the update function on the notifier, and we need to change our Icon concerning our state.
In the article, I have explained the Show/Hide Password Using Riverpod in a flutter; you can modify this code according to your choice. This was a small introduction toShow/Hide Password Using Riverpod On User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying the Show/Hide Password Using Riverpod in your flutter projects. We will show you what the Introduction is. Make a demo program for working on show/hide password in TextFormField Using the hooks_riverpod package in your flutter applications. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, Twitter, and LinkedIn for any flutter-related queries.
Wewelcome feedback and hope you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
In this article, we will Explore Memory Leaks In Flutter. We perceive how to execute a demo program. We will show you what is the reason, detect, and prevent memory leaks in your Flutter applications.
Memory leaks in Flutter applications can happen when a program holds memory that is not generally required, making the application consume more memory than needed. One common reason is the presence of unused objects that stay in memory due to caching, improper disposal, or failure to remove listeners. This can prompt slower execution, crashes, and eventually, an unsuitable user experience.
Abusing streams, which are utilized to deal with asynchronous events in Flutter, can likewise prompt memory leaks on the off chance that stream subscriptions are not as expected dropped, making the stream keep running behind the background and consuming memory. Besides, stacking enormous pictures and videos without delivering them properly can add to memory leaks in Flutter applications.
What Reasons For Memory Leaks In Flutter?
Memory Leaks might happen for some reasons. Here are the absolute most normal reasons.
>Unused Objects — For thisreason, unused objects that are unclosed streams are the circumstances when we make the stream yet neglect to close it. Streams can keep references to objects in memory even after they are not generally utilized causing memory leaks.
Other, unused objects that are not taken out from memory can cause memory leaks. This is because the items consume space in memory, even though they are not generally needed. Unused objects can be made for different reasons, for example, caching, not appropriately disposing of objects, and not eliminating listeners when they are not generally required.
>Improper Use of Streams — For this reason, streams are utilized in Flutter to deal with asynchronous events, and improper utilization of streams can cause memory leaks. For instance, not appropriately canceling a stream subscription can make the stream keep running behind the background, consuming memory.
> Global Variables — For this reason, the garbage collector doesn’t work while putting away references to objects or widgets as global variables. So we need to deallocate that memory as it can likewise cause memory leaks.
> Large Images and Videos — For this reason, loading enormous images and videos can likewise cause memory leaks in Flutter. At the point when huge files are stacked, they take up a lot of memory, and on the off chance that they are not as expected delivered when they are not generally required, they can cause memory leaks.
>Widget Trees — For this reason, mistakenly putting the widgets on the widget tree, particularly while utilizing the stateful widget can likewise cause memory leaks in Flutter.
How To Detect Memory Leak In Flutter?
Recognizing memory leaks in your Flutter application can be a bit challenging yet it is conceivable. The following are a few strategies and tools that can distinguish and fix memory leaks in the Flutter Application.
> Flutter DevTools — Flutter DevTools is a performance and debugging tool for Dart programs and Flutter Applications. You can utilize Flutter DevTools to look at your application’s memory usage. You can get to the Flutter DevTools by running the following command:
flutter pub global run devtools
> Heap Snapshots — You can likewise take heap snapshots to look at the memory utilization and breaks at a particular point in time. Heap Snapshots can assist you with recognizing objects that are not being garbage collected as expected.
> Analyze Your Code — You should review your code and give close consideration to objects. Now check assuming that the objects are appropriately disposed of when they are not generally required. You should likewise check for the controller as they are one of the most well-known reasons for memory leaks in Flutter.
How To Prevent Memory Leaks In Flutter?
> Dispose of Objects — One of the best ways of forestalling memory spills in Ripple is to discard objects when they are not generally required. Discarding objects eliminates them from memory and opens up assets for different pieces of the application. To discard objects, utilize the arrange technique in the Stateful Gadget.
> Use Streams Properly — To prevent memory leaks caused by streams, consistently cancel the subscription when it is not generally required. This guarantees that the stream is done running behind the background, consuming memory.
> Use Images and Videos Efficiently — To prevent memory leaks influenced by enormous images and videos, utilize efficient techniques to load them. One such strategy is to utilize the flutter_cache_manager package, which assists with caching images and videos, reducing the amount of memory they consume.
Use Profiling Tools — Profiling tools, like the Flutter DevTools, can assist with recognizing memory leaks in your application. By analyzing the memory utilization of your application, you can pinpoint the areas that are causing memory leaks and do whatever it takes to fix them.
> Avoid Saving Flutter Object References in Background Threads — To prevent memory leaks, refrain from putting Flutter object references in background threads. All things being equal, utilize weak references or isolate communication mechanisms like message passing. Weak references enable objects to be garbage collected when they are no longer strongly referenced, preventing memory leaks. Isolate communication ensures that Flutter objects can be safely passed between isolates without retaining strong references, further guarding against memory leaks.
Conclusion:
In the article, I have explained the Memory Leaks In Flutter; you can modify this code according to your choice. This was a small introduction to the Memory Leaks In Flutter User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying the Memory Leaks In Flutter in your Flutter projects. Memory leaks are a typical issue in Flutter, however, they can be prevented by following best practices and utilizing the appropriate tools. By disposing of objects, utilizing streams appropriately, and efficiently loading images and videos, developers can prevent memory leaks and make high-performing applications that provide an ideal user experience.
Remember to use profiling tools to recognize memory leaks in your application, and do whatever it may take to fix them. With these tips, you can build Flutter applications that are quick, efficient, and reliable.
❤ ❤ Thanks for reading this article ❤❤
If I need to correct something? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
Wewelcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
Themes are a subject group frequently discussed while making applications. The most usually utilized term in regards to this point would be ‘dark theme’. You can frequently see individuals requesting how to deal with a dark theme in your application or any event, similar to requesting how to oversee various symbols for various themes.
Flutter has, however, greatly eased the process of customizing themes and their components. In this article, we will explore how to implement theming usingRiverpod state management in your Flutter applications.
In this tutorial, I only show you how to change the theme according to system mode using the Switch button.
This demo video shows how to implement theming theme in Flutter and shows how a theming will work using the hooks_riverpod package in your Flutter applications. We will show a user switches the button then the theme will be changed from light mode to dark mode/vice versa. It will be shown on your device.
Demo Module::
Implementation:
Step 1: Add the dependencies
Add dependencies to pubspec — yaml file.
dependencies: flutter: sdk: flutter hooks_riverpod: ^latest version
final themesProvider = StateNotifierProvider<ThemesProvider, ThemeMode?>((_) { return ThemesProvider(); });
class ThemesProvider extends StateNotifier<ThemeMode?> { ThemesProvider() : super(ThemeMode.system); void changeTheme(bool isOn) { state = isOn ? ThemeMode.dark : ThemeMode.light; } }
Create a new dart file called main.dart inside the lib folder.
Now, time to create our main. dart file. We should extend ConsumerWidget instead of StatelessWidget to use WidgetRef. Also, ensure you add the root of our app ProviderScope as shown below. Otherwise, you are not going to be able to use providers.
Presently, time to make our main. dart file. We ought to extend ConsumerWidget rather than StatelessWidget to utilize WidgetRef. Likewise, ensure you add the root of our application ProviderScope as displayed underneath. If not, you won’t have the option to utilize providers.
Create a new dart file called home_screen.dart inside the lib folder.
Lastly, we need to create our HomeScreen().To do that we create a home_screen.dartfile. And as I said before you can create everything into main. dart. We use Switch Widget to change
When we run the application, we ought to get the screen’s output like the underneath screen capture.
Final Output
Conclusion:
In the article, I have explained the Implement Theming Using Riverpod in a flutter; you can modify this code according to your choice. This was a small introduction toImplementing Theming Using Riverpord On User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying the Implement Theming Using Riverpod in your Flutter projects. We will show you what the Introduction is. Make a demo program for working on implementing Theming Using the hooks_riverpod package in your Flutter applications. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, Twitter, and LinkedIn for any flutter-related queries.
Wewelcome feedback and hope you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
Routing or navigating starting with one page and then onto the next page is fundamental for any application. All things considered, when it came to Flutter’s in-constructed routing system, it was quite simple to get a handle on, after a long tutorial and numerous uses in projects.
Then, I utilized Fluro at that point, and I was astounded. If you come from a front-end web development background, you would feel comfortable with how Fluro handles its routes.
This blog will explore the Routing With Fluro In Flutter. We perceive how to execute a demo program. We will learn how to route from one page to another page using the fluropackage in your Flutter applications.
The below demo video shows a two-page Home page and a Second page. On the Home page, we will add an elevated button and on the Second page, we will add Floating Action Buttons to navigate to the other page. It will be shown on your devices.
When moving from Home to Second, we require some extra information, such as data, so we pass that as part of the route parameters. So we’ll be learning how to do that through Fluro.
While moving from Home to Second, we require some additional information, like data, so we pass that as a component of the route parameters. So we’ll figure out how to do that through Fluro.
Demo Module::
Implementation:
Step 1: Add the dependencies
Add dependencies to pubspec — yaml file.
dependencies: flutter: sdk: flutter fluro: ^2.0.4
Step 2: Import
import 'package:fluro/fluro.dart';
Step 3: Run flutter packages get in the root directory of your app.
How to implement code in dart file :
You need to implement it in your code respectively:
Create a new dart file called router.dart inside the lib folder.
The first line inside the Routes class initializes a static instance of FluroRouter() from the Fluro library.
static final router = FluroRouter();
Then, we have a handler where we deal with highlighting which widget/part must be loaded while visiting a route. You can consider them controllers on the off chance that you are accompanying information from a past framework.
// Handler for Home Page static var firstScreen = Handler( handlerFunc: (BuildContext? context, Map<String, dynamic> params) { return const HomePage(); }); // Handler for Second Page static var placeHandler = Handler( handlerFunc: (BuildContext? context, Map<String, dynamic> params) { return SecondPage(data: params["data"][0]); });
params[‘data’][0] will return the data sent by the route path and will be sent to the SecondPage as an attribute.
Next, we have a defineRoutes() function, where we will define individual routes and their paths. This is also where we will define any parameters if any. Let’s take a close look at the router.define() function.
Create a new dart file called home_page.dart inside the lib folder.
Navigator.pushReplacementNamed() is a capability that replaces the stack with anything that route you pass to it, so the user can’t return to the past screen by just squeezing the back button.
On the off chance that you would need such usefulness of returning a screen, you can utilize Navigator.pushNamed() with similar attributes.
Create a new dart file called second_page.dart inside the lib folder.
On the Second Page, it’s genuinely straightforward as we need to pass no parameters accordingly, so we simply need to call pushReplacementNamed() once more.
When we run the application, we ought to get the screen’s output like the underneath screen capture.
Conclusion:
In the article, I have explained Routing With Fluro’s basic structure in a flutter; you can modify this code according to your choice. This was a small introduction to Routing With Fluro On User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying the Routing With Fluro in your Flutter projects. We will show you what the Introduction is. Make a demo program for working Routing With Fluro and you’ve learned how to route from one page to another page using the fluropackage in your Flutter applications. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
Wewelcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
Flutter has become one of the most popular frameworks for building cross-platform applications, while AWS Amplify provides an easy and powerful way to add cloud capabilities to your applications. Among Amplify’s many features, Storage with S3 bucket is crucial for managing files like images, videos, and documents.
AWS Amplify storage module provides a simple mechanism for managing user content for your app in public, protected or private storage buckets. The storage category comes with built-in support for Amazon S3 (Simple Storage Service). In this blog, we’ll cover everything you need to integrate AWS Amplify Storage with S3 buckets into your Flutter app, step by step.
What is AWS Amplify Storage?
AWS Amplify is a cloud-based development framework by Amazon Web Services that simplifies building scalable, full-stack applications. The Amplify Storage category integrates with Amazon S3, allowing you to store and retrieve objects like images, audio, videos, and documents securely.
S3 Core Concepts
Amazon S3 stores data as objects within container buckets. An object consists of a file and optionally any metadata that describes that file. To store an object in Amazon S3, you upload the file you want to store to a bucket. When you upload a file, you can set permissions on the object and any metadata.
Buckets are the containers for objects. You can have one or more buckets. For each bucket, you can control access to it (who can create, delete, and list objects in the bucket), view access logs for it and its objects, and choose the geographical region where Amazon S3 will store the bucket and its contents.
Prerequisites
Before diving in, ensure you have the following ready:
AWS Account: Sign up and Setup your AWS account
Node.js: Required to install the Amplify CLI.
Flutter Setup: Ensure Flutter and Dart are installed on your machine.
Amplify CLI: Install globally using npm install -g @aws-amplify/cli.
Configuration
Step 1: Initialize AWS Amplify
Install the Amplify CLI
Run the following command in your terminal:
npm install -g @aws-amplify/cli
This installs the Amplify Command Line Interface (CLI) globally.
Initialize the Amplify Project
Navigate to your Flutter project directory and run:
amplify init
Choose Flutter as the framework.
Configure your environment and backend details (e.g., name, environment, region, etc.).
When prompted, provide the details of your application.
This command sets up Amplify for your project and generates the necessary files.
Step 2: Add the Storage Category
Run the following command to add storage:
amplify add storage
Choose “Content (Images, audio, video, etc.)”.
Define the resource name (or accept the default).
? Please select from one of the below mentioned services: > Content (Images, audio, video, etc.) NoSQL Database ? Please provide a friendly name for your resource that will be used to label this category in the project: > mystorage ? Please provide bucket name: > mybucket
Set permissions for authenticated and unauthenticated users.
? Restrict access by? > Auth/Guest Users Individual Groups Both
Enable Auth/Guest access only if necessary (e.g., public-facing apps).
? Who should have access: ❯ Auth users only Auth and guest users
Then you’ll be prompted to set the access scopes for your authenticated and (if selected prior) unauthenticated users.
? What kind of access do you want for Authenticated users? > ◉ create/update ◯ read ◯ delete ? What kind of access do you want for Guest users? ◯ create/update > ◉ read ◯ delete
Push the changes to AWS:
amplify push
This command provisions an S3 bucket and configures it with the necessary policies.
Step 3: Add Dependencies to Your Flutter Project
In your Flutter app’s pubspec.yaml file, add the following dependencies:
To initialize the Amplify Auth and Storage categories, call Amplify.addPlugin() for each plugin or pass all the plugins in Amplify.addPlugins(). To complete initialization, call Amplify.configure().
You can use StoragePath to access, upload to, or download from to any path in your S3 bucket. The Amplify Gen 1 CLI automatically creates the following directories:
public/: Accessible by all users of your application
protected/<identityId>/: Readable by all users (you need to specify the identityID of the user who uploaded the file). Writable only by the creating user
private/<identityId>/: Readable and writable only by the creating user
If you are using Amplify Gen2 or an S3 bucket not created by Amplify, you can use StoragePath to access, upload to, or download from any directory in your bucket.
You can specify the path to your S3 resource by creating a StoragePath directly from a String, or by constructing the path with the user’s Cognito IdentityId.
You may want to construct a StoragePath that contains the Amplify Auth user’s IdentityId. We’ve created a helper function that injects the user’s IdentityId when a Storage API is called, since fetching an IdentityId from the Auth plugin is not synchronous.
// If the user's identityId was "123", // the StoragePath would resolve to "private/123/exampleFile.txt" StoragePath.fromIdentityId( (String identityId) => 'private/$identityId/exampleFile.txt', };
Step 6: Implement Storage Functions
Upload a File to S3
To upload a Imagefile to S3 bucket, specify the file path and s3 bucket path where you want to store.
You can upload imageFile to a local directory using Amplify.Storage.uploadFile
Future<void> uploadImage(File imageFile) async { try { final result = await Amplify.Storage.uploadFile( localFile: AWSFilePlatform.fromFile(imageFile), path: const StoragePath.fromString('public/imagefile.png'), ).result; safePrint('Uploaded imagefile: ${result.uploadedItem.path}'); } on StorageException catch (e) { safePrint(e.message); } }
You can call this method with a selected file from your device.
Download a File from S3
You can download file to a local directory using Amplify.Storage.downloadFile
To download a file:
Future<void> downloadImage(String key, String downloadPath) async { try { final result = await Amplify.Storage.downloadFile( path: StoragePath.fromString('public/'+'your-s3-bucket-imagefile-path'), localFile: AWSFile.fromPath(downloadPath), ).result; AWSFile awsFile = result.localFile; path = awsFile.path!; //use this path to show your imagefile in your UI
You can get a downloadable URL for the image file in storage by its path.
When creating a downloadable URL, you can choose to check if the image file exists by setting validateObjectExistence to true in S3GetUrlPluginOptions. If the file is inaccessible or does not exist, a StorageException is thrown. This allows you to check if an object exists during generating the presigned URL, which you can then use to download that object.
3. Error Handling: Always handle exceptions to improve user experience.
4. Monitor Costs: Keep track of your S3 bucket usage to avoid unexpected costs.
Conclusion
Integrating AWS Amplify Storage with S3 buckets into your Flutter app is straightforward and highly beneficial for managing files. By following this guide, you can upload, download, list, and delete files seamlessly. Amplify also provides robust security and scalability, making it an excellent choice for modern applications.
Explore further to customize storage configurations, add advanced features like presigned URLs, or integrate other Amplify categories to build a comprehensive cloud-enabled app.
At What the Flutter, we love working with Flutter apps to make them high-performing and delight users. Contact us today to discuss how we can optimize your Flutter app performance.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us: And read more articles fromFlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
Wewelcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.