how to write maintainable UI Screen? - performance

I want to write a readable and beautiful code so that anyone could understand it, as well as the code can be maintainable and scalable.
my code is that is it good or no?

Create stateless widgets for smaller UI Components and compose bigger widgets or pages using these reusable UI widgets. for example :
Widgets Folder:
custom_text.dart (a widget that gives me simple centered text).
custom_button.dart (a custom reusable component).
Pages Folder:
home_page.dart(a widget that includes a scaffold with custom_card
inside)
login_page.dart
here's an example
void main() => runApp(HomePage ());
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: SimpleTextWidget(),
),
);
}
}
this is a small reusable component to be used in your other parent widget.
class SimpleTextWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Text('Hello'),);
}
}

You can maintain different files for keeping widgets and use the import statements for using them in any file. This will also make your code re-usable.
For writing a beautiful code, you must follow the indentation properly and you can also add useful comments to the code which will increase the readability of your code.

Related

Change title bar color in flutter windows desktop

I am developing a windows desktop application and would like to change the title bar color if possible. for example I would like to go from something like this:
to something like this:
Is it possible using flutter and how to do it? Thanks.
for this kind of customization, you will need to use the bitsdojo_windows community package, that allows you to customize the appearance of the window
A bit late to the party but you can use window_manager to achieve what you want.
In order to hide the title bar, you should use setTitleBarStyle() method before your runApp call, so the user will not see a lag or delay in UI.
Here's a minimal example:
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); //Must be called
await windowManager.ensureInitialized(); //Must be called
//waitUntilReadyToShow ==> Optional method to use, requires modification of native runner - Read docs of the package.
await windowManager.waitUntilReadyToShow().then((_) async {
await windowManager.setTitleBarStyle(TitleBarStyle.hidden); //Hiding the titlebar
await windowManager.setTitle("I don't have a titlebar!"); //We don't have a titlebar, this title appears in Task Manager for example.
await windowManager.show(); //Finally show app window.
});
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('My Titlebar-less app!'),
),
),
);
}
}

How can I improve the performance of Wrap Widget with multiple child?

When I move from tabs in the UI it's takes too long to load the chips under the tabs.
I've used the AutomaticKeepAliveClientMixin<> but it broke my Scrollbar and still takes time to load large Chips children from the Wrap Widget. What I would need is a Wrap.builder() but doesn't exist. Is there something I can do to optimize the code to load smoothly?
I have an interactive sample code of the current problem:
https://dartpad.dev/009e9ccae07175074cb77d7792c3692b
Try moving the tabs left to right in the sample to see the performance issue.
If it can't be fixed, I wonder if I can detect when the widget is rendering to show a circular progress indicator while switching tabs.
Any Ideas?
Thanks
Technically the idea of Wrap.builder wouldn't be a solution here because the issue persists even when all the items are in the displayed (nothing to display on demand)
You can make the swiping experience better by delaying the rendering of the tab content until after the swiping animation is done
class _ChipsContentState extends State<ChipsContent> {
bool visible = false;
final List<String> _filters = <String>[];
#override
void initState() {
super.initState();
Future.delayed(kTabScrollDuration).then((value) {
if (mounted) {
setState(() => visible = true);
}
});
}
#override
Widget build(BuildContext context) {
if (!visible) {
return Center(child: CircularProgressIndicator());
}
return ListView(
children: [
if (visible)
Wrap(
spacing: 8.0,
children: widget.chipData.map((chipName) => ChipFilter(chipName: chipName, filter: _filters)).toList(),
),
],
);
}
}
A Wrap.builder() is indeed missing from Flutter. A GitHub issue was opened about this but then closed without a satisfying solution.
I can think of a few workarounds, like using a swiper/carousel, a GridView.builder(), or a List.builder() with Rows inside it. Of course, they're far from being as convenient as a Wrap in this case.
Try Changing your filterChips and "build" methods as follows,
List<Widget> get filterChips {
List<Widget> widgets = [];
for (final chipName in widget.chipData) {
widgets.add(ChipFilter(chipName: chipName, filter: _filters));
}
return widgets;
}
#override
Widget build(BuildContext context) {
// super.build(context);
return Scrollbar(
child: SingleChildScrollView(
child: Wrap(//IS THERE A Wrap.builder()? OR ALTERNATIVE TO DESIRED LAYOUT?
spacing: 8.0,
children: filterChips,
),),
);
}

How can I memoize a gradient mask in Flutter?

I made an Android app long time ago where the main focus were a bunch of differently colored icon buttons representing psychological emotions. I realized that a few people I had it tested with were slightly confused about the icons, as they unconsciously associated different colors to these emotions than the ones I had chosen.
So, now I'm rewriting the app with Flutter, and I've decided that these icon buttons will have gentle gradients instead of solid colors, as it seems that specific color relationships, rather than colors, are more consistently associated with the emotions, plus it encourages association by learning instead of usage of innate ideas, since it makes the appearance of each icon harder to completely describe but easier to distinguish from the others.
Anyway, I'm using a ShaderMask with a LinearGradient, and an IconButton as child. Obviously it eats up GPU and rendering time is slightly above 16 ms. I thought of memoizing the rendered icon with the gradient, by pre-rendering it to an image then using it in the buttons. I've seen a good increase in performance, but the resulting code felt so hackish and buggy that I just reverted everything.
Is there a way to do this without feeling like I'm fighting the framework? Like, an official way to pre-render widgets, or at least to tell Flutter when something can be re-used without changes (performance is terrible even when updating a widget that doesn't have anything to do with these buttons).
Edit: memoizing these gradient icons would also allow me to use them elsewhere, increasing overall consistency whenever these emotions must be represented. Doing this right now would simply nuke performance.
Edit: code:
class MyButton extends StatelessWidget {
MyButton({this.index, this.constraints});
final int index;
final BoxConstraints constraints;
#override
Widget build(BuildContext context) {
return GradientMask(
child: IconButton(
onPressed: () {},
iconSize: constraints.maxWidth,
padding: EdgeInsets.all(0.0),
color: Colors.white,
icon: iconList[index],
),
index: index,
);
}
}
class GradientMask extends StatelessWidget {
GradientMask({this.index, this.child});
final int index;
final Widget child;
#override
Widget build(BuildContext context) {
return ShaderMask(
shaderCallback: (Rect bounds) => LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: gradientList[index],
tileMode: TileMode.repeated,
).createShader(Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)),
child: child,
);
}
}

Flutter - How to use a FadeTransition inside a StreamBuilder?

I am trying to make a colour transition animation inside a StreamBuilder which is inside a stateless widget. I have no idea how to perform that since all the examples and tutorials about this subject use a Stateful Widget.
I thought about using FadeTransition Widget but and maybe store the state in my Bloc that controls that view.
Please give me any suggestions if you have, Thank you.
To perform a fade in transition in a streambuilder, it's easy, simply use a widget called AnimatedSwitcher :
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
return AnimatedSwitcher(
duration: Duration(seconds: 1),
child: _getMainWidget(snapshot, context),
);
},
);
}
Here we use an AnimatedSwitcher to animate a transition when the child of the AnimatedSwitcher change's, the default animation is a fade animation, but you could add your custom animation by passing the widget a TransitionBuilder as an argument

Create very custom animations in flutter

I've followed the various animation tutorials on flutter.io, (tween, stagger, transitions, etc.) and its all great.
What I would like to explore is how to actually make custom animations based on the composition of a UI object.
Lets take a simple example, a Pause -> Play animation.
At first we have a Pause icon, two vertical bars.
Let's say I would like to
Grow the right bar into a triangle by adding an extra corner on the center of the rightmost vertical side, and moving it to the right.
After that moving that triangle from step 1 slightly to the left, so it now sticks to the leftmost vertical bar, into a bigger "triangle" (that'd be a pentagon actually).
That would look like a play button, and not a pause button anymore.
How would I achieve that kind of custom animation ? I'm assuming I can't work with the icons class. And I'm pretty sure I shouldn't do that with Widgets and just move them around.
Where would I go to start exploring that kind of precision in animations?
The answer from #Alaric points you at a couple of packages but doesn't really give any justification for why you'd use them.
The issue at hand is that the animation you're talking about is moderately complicated in terms of how it actually works. There are multiple items which change over time and possibly even become one bigger item.
There are two approaches you could take to solving this problem. The first is to use an external animation tool to create this animation, using whichever features the animation tool has to do item changing and merging. Then once you have an animation which runs to your satisfaction, you have to import it into your project somehow. That's where the fluttie and flare_flutter plugins come in - if you used Aftereffects, you use Lottie to export the file and then the fluttie plugin to show it. Flare is slightly simpler as it's meant for flutter, but you still create the animation externally and then add the file to your assets to be rendered.
The other approach is to do the animation yourself. That entails three things:
Creating a widget to contain the animation.
Creating a CustomPainter to actually draw the result.
Optionally, another class which acts as controller to start/stop/etc the animation.
The widget containing the animation could probably also be the controller if you use a GlobalKey to access it and expose start/stop methods, but that's a bit messy. It's better to have an external object that is the controller - and you could probably even use an AnimationController as-is although it would be less 'clean'.
If you don't pass it in, you'd probably have an AnimationController in your widget that you start and stop from your controller or class. It would essentially just go from 0 to 1 and back, and would be responsible for rebuilding the CustomPainter (probably using an AnimatedBuilder).
This is a very basic example that doesn't need an external controller as the gesture detection happens within the widget. Note that I'm not calling setState every time the 'started' member is set, because I don't actually want it to rebuild when it changes.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: StartStop(),
),
),
);
}
}
class StartStop extends StatefulWidget {
#override
StartStopState createState() {
return new StartStopState();
}
}
class StartStopState extends State<StartStop> with TickerProviderStateMixin<StartStop> {
bool started = false;
AnimationController animationController;
#override
void initState() {
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 300));
super.initState();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
started ? animationController.forward() : animationController.reverse();
started = !started;
},
child: SizedBox(
width: 100,
height: 100,
child: AnimatedBuilder(
animation: animationController,
builder: (context, child) {
return CustomPaint(
painter: StartStopPainter(animationController.value),
size: Size.infinite,
child: child,
);
},
),
),
);
}
}
class StartStopPainter extends CustomPainter {
final double percentAnimated;
StartStopPainter(this.percentAnimated) : assert(percentAnimated >= 0 && percentAnimated <= 1);
#override
void paint(Canvas canvas, Size size) {
var pausePaint = Paint()..color = Colors.black.withOpacity(1 - percentAnimated);
canvas.drawRect(Rect.fromLTRB(20, 10, 40, 90), pausePaint);
canvas.drawRect(Rect.fromLTRB(60, 10, 80, 90), pausePaint);
var playPaint = Paint()..color = Colors.black.withOpacity(percentAnimated);
canvas.drawPath(Path()..addPolygon([Offset(20, 10), Offset(20, 90), Offset(80, 50)], true), playPaint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
I'll leave the actual custom part of the animation (where you make the rectangle change to a triangle etc) to you. Instead of using opacity and a few different paint calls, you'd simply be using the input percentAnimated to decide which path or polygon to draw.

Resources