Flutter - Custom Timer avoid moving numbers? - flutter

I'm struggling to fix the following issue shown in the gif. I'm using this package for the timer. And I can't figure it out how to avoid the moving of the countdown timer while counting down. It’s moving because of different widths of each number.
Gif:via GIPHY
Code:
Consumer<RunSettingsModel>(
builder: (context, settings, _) => CustomTimer(
from: Duration(seconds: settings.runDuration),
to: Duration(seconds: 0),
controller: _runController,
builder: (CustomTimerRemainingTime remaining) {
final double percent = 1 -
remaining.duration.inSeconds.toDouble() /
settings.runDuration;
settings.remainingTime = remaining.duration.inSeconds;
return Column(
children: [
Container(
child: Text(
"${remaining.hours}:${remaining.minutes}:${remaining.seconds}",
style: Theme.of(context).textTheme.headline3,
),
),

you can import 'dart:ui';
and then in your Text Widget use a TextStyle of
fontFeatures: [FontFeature.tabularFigures()],
like so:
Text("${remaining.hours}:${remaining.minutes}:${remaining.seconds}",
style: TextStyle(fontSize: 30.0, fontFeatures: [FontFeature.tabularFigures()]),
);

Try to remove the Container wrapping your Text as shown in the custom_timer package.
As you can see, in the package example there is no Container, the Container might be changing it's size because it doesn't have a fixed width and height.
This is the package simple example:
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text("CustomTimer example"),
),
body: Center(
child: CustomTimer(
from: Duration(hours: 12),
to: Duration(hours: 0),
onBuildAction: CustomTimerAction.auto_start,
builder: (CustomTimerRemainingTime remaining) {
return Text(
"${remaining.hours}:${remaining.minutes}:${remaining.seconds}",
style: TextStyle(fontSize: 30.0),
);
},
),
),
),
);
}

You should try to separate each digit(hours, minutes and seconds) in its own Text widget and wrap them with a Container to keep them always at the center. I am creating a new widget for the digits because most of the widgets used would repeat themselves.
class DigitsContainer extends StatelessWidget {
const DigitsContainer(
this.text, {
required this.style,
});
final String text;
final TextStyle style;
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
child: Center(
child: Text("", style: style),
),
),
);
}
}
Then in your main widget.
...
return Column(children: [
DigitsContainer(remaining.hours.toString(), style: style),
Text(":", style: style),
DigitsContainer(remaining.minutes.toString(), style: style),
Text(":", style: style),
DigitsContainer(remaining.minutes.toString(), style: style),
]),
...
Also make sure to wrap this Column in a Container with fixed with so that you dont have problem with the Expanded widget inside the DigitsContainer one. I hope this works.

Related

Custom Font Size : Increase and Decrease in Flutter

In my flutter application, I have to provide an option to change the font size of the application Text contents.
So, normally, I know that for different screen sizes, We can manage but this is not that case.
I have just gone through this plugin:
https://pub.dev/packages/sizer
But, It's not the case which I am looking for.
The case is to choose particular font size option and according to selected option the font height should be change.
How can I achieve this? Thanks.
If you want the user to be able to change fontsize in your application you could do something like this.
class _MyHomePageState extends State<MyHomePage> {
double? _fontSize = 14;
void _changeFontSize(double fontSize) {
setState(() {
_fontSize = fontSize;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'FontSize is now: $_fontSize',
style: TextStyle(fontSize: _fontSize),
),
ElevatedButton(onPressed: () => _changeFontSize(22), child: const Text("22")),
ElevatedButton(onPressed: () => _changeFontSize(24), child: const Text("24")),
ElevatedButton(onPressed: () => _changeFontSize(26), child: const Text("26")),
],
),
),
);}}

Flutter text overflow at beginning of sentence

I need to have overflow property of a text at the beginning of the sentence, so instead of
A very looooooooooong senten...
I want the result of the ellipsis to be
...ery looooooooooong sentence.
Can this be set somehow?
According to this github issue, there currently isn't a way to do this with the Material Text Widget's overflow property.
However you can use the ExtendedText() Widget from extended_text package.
#override
Widget build(BuildContext context) {
return const Scaffold(
body: SafeArea(
child: ExtendedText(
'A very looooooooooong sentence.',
maxLines: 1,
overflowWidget: TextOverflowWidget(
position: TextOverflowPosition.start,
child: Text(
"...",
style: TextStyle(fontSize: 23),
),
),
style: TextStyle(fontSize: 27),
),
),
);
}

Animated Switcher in combination with case conditioned Streambuilder

Following question:
I managed to get a lot further with my dosage calculator app and the state management procedure and now I'm trying to scale things up visually speaking.
So I wanted to change the built widget based on a dropdown menu which actually worked out fine but I'm trying to implement an AnimatedSwitcher so every time the user changes the dropdown menu, the old widget fades out and the new one in instead of just switching. Searched for solutions, found one but I don't know if I implemented it the right way, since I'm not getting any animation, but no error message neither.
I'm supposing I either used the wrong child or something like a unique key is missing (which I don't know how to implement)
Here are the necessary parts of my code:
DropdownMenu:
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child:DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: selectedItem,
onChanged: (String string) => setState(() {
streamController.sink.add(string);
return selectedItem = string;
}),
selectedItemBuilder: (BuildContext context) {
return items.map<Widget>((String item) {
return Text(item,
//style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.right,
);
}).toList();
},
items: items.map((String item) {
return DropdownMenuItem<String>(
child: Text('$item',
//style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.right,
),
value: item,
);
}).toList(),
),
),
);
}
}
StreamBuilder and AnimatedSwitcher:
StreamBuilder(
stream: streamController.stream,
builder: (context, snapshot) {
return AnimatedSwitcher(
duration: Duration(seconds: 1),
child: updateBestandteile(snapshot.data),
);
},
),
Example of condition:
Padding updateBestandteile(String i) {
switch (i) {
case "MMF":
{
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 200,
decoration: BoxDecoration(
color: b,
borderRadius: BorderRadius.circular(10.0)
),
child: Align(
alignment: Alignment.center,
child: Row(
children: [
Column(
children: [
Text('Zu verwendende Präparate:',
style: TextStyle(fontWeight: FontWeight.bold)),
Text('Medetomidin 1mg/ml'),
Text('Midazolam 5mg/ml'),
Text('Fentanyl 0.5mg/ml'),
Text('NaCl 0,9%'),
],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
Column(
children: [
Text('Anzumischende Menge:',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text((MedetomidindosierungmgprokgKGW*selectedamount*selectedweight/(1000*Medetomidinmgproml)).toString()+"ml"),
Text((MidazolamdosierungmgprokgKGW*selectedamount*selectedweight/(1000*Midazolammgproml)).toString()+"ml"),
Text((FentanyldosierungmgprokgKGW*selectedamount*selectedweight/(1000*Fentanylmgproml)).toString()+"ml"),
Text((((MedetomidindosierungmgprokgKGW*selectedamount*selectedweight/(1000*Medetomidinmgproml))+(MidazolamdosierungmgprokgKGW*selectedamount*selectedweight/(1000*Midazolammgproml))+(FentanyldosierungmgprokgKGW*selectedamount*selectedweight/(1000*Fentanylmgproml)))*4).toString()+"ml"),
],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
),
),
);
}
break;
Hope you might be able to help as you did last time :) Thanks in advance!
Cheers,
P
The issue might be that you are not setting a key. If the new child widget is of the same type as the old widget type then AnimatedSwitcher will NOT animate between them since as as far as the framework is concerned, they are the same widget. Set a unique ValueKey on each child child widget that you wish to animate.
Please refer to Flutter Docs for AnimatedSwitcher and check out the AnimatedSwitcher Widget of the Week video by Flutter Team.
If the "new" child is the same widget type and key as the "old" child,
but with different parameters, then AnimatedSwitcher will not do a
transition between them, since as far as the framework is concerned,
they are the same widget and the existing widget can be updated with
the new parameters. To force the transition to occur, set a Key on
each child widget that you wish to be considered unique (typically a
ValueKey on the widget data that distinguishes this child from the
others).

TextOverFlow Flutter

I have a certain Text widget , when it overflows I have 3 options. Either fade ,visible, ellipsis or clip. But I don't want to choose between them . I want if a text has overflow then don't show the text.
Edit :
I'm working on a code clone to this design
Assuming that the textStyle is unknown.
How could I achieve that?
Code:
class SwipeNavigationBar extends StatefulWidget {
final Widget child;
SwipeNavigationBar({this.child});
#override
_SwipeNavigationBarState createState() => _SwipeNavigationBarState();
}
class _SwipeNavigationBarState extends State<SwipeNavigationBar> {
#override
Widget build(BuildContext context) {
return Consumer<Controller>(
builder: (_, _bloc, __) {
return SafeArea(
child: AnimatedContainer(
duration: Duration(seconds: 01),
color: Colors.white,
curve: Curves.easeIn,
height: !_bloc.x ? 50 : 200,
child: Row(
children: [
Column(
verticalDirection: VerticalDirection.up,
children: [
Expanded(child: Icon(Icons.dashboard)),
Expanded(
child: RotatedBox(
quarterTurns: -45,
child: Text(
'data',
softWrap: false,
style: TextStyle(
textBaseline: TextBaseline.alphabetic
),
),
),
),
],
)
],
),
),
);
},
);
}
}
To mimic the design you might want to look into using the Stack widget. However, to answer your question, you'd want to set softWrap to false.
Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: 100,
child: Text(
'Some text we want to overflow',
softWrap: false,
),
),
)
softWrap is really the key here. Although, I added the Align and SizedBox widgets to allow this to be used anywhere, regardless of what parent widget you are using (since some widgets set tight constraints on their children and will override their children's size preference).
CodePen Example
Edit: 5/6/2020
With the release of Flutter v1.17 you now have access to a new Widget called NavigationRail which may help you with the design you're looking for.
Use ternary operator to check the length of the text that you are passing to the Text widget and based on that pass the text itself or an empty string.
String yourText;
int desiredLengthToShow = 10; //Change this according to you.
...
Text(
child: yourText.length > desiredLengthToShow ? "" : yourText,
);

How to update a custom Stateful Widget using Floating Action Button

I've recently started using Flutter just for fun, and I'm stuck on adding actual functionality to the code without having everything inside one class.
Essentially, I'm trying to use a FloatingActionButton to increment the value of a Text Widget which stores the value of the user's level as an integer, but I don't want to have the whole app as a StatefulWidget because only the level is going to be updated. When the button is pressed, the value should increment by 1 and then show the new value on the screen.
I have the Level Text Widget inside a StatefulWidget class along with a function to update the level by one and set the state; the MaterialApp inside a StatelessWidget class; and the main body code inside another StatelessWidget class.
If this isn't the best way to do it please do let me know so I can improve for future projects, thanks.
main.dart
import 'package:flutter/material.dart';
main() => runApp(Start());
/// The Material App
class Start extends StatelessWidget{
#override
Widget build(BuildContext context){
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.grey[800],
appBar: AppBar(
title: Text("Home Page"),
backgroundColor: Colors.cyan,
centerTitle: true,
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.orange,
child: Icon(Icons.add, color: Colors.black,),
),
body: HomePage(),
),
);
}
}
/// Main Content for the page (body)
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// removed other children so there's less code to scan through for you :)
Padding(
padding: EdgeInsets.fromLTRB(30, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Text that just says "Level"
Text(
"Level",
style: TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
fontSize: 32,
),
),
// space between text and actual level value
SizedBox(height: 10),
// Create new level widget
Level(),
],
),
),
],
),
);
}
}
/// Updating level using a Stateful Widget
class Level extends StatefulWidget{
#override
State<StatefulWidget> createState(){
return _LevelState();
}
}
class _LevelState extends State<Level>{
int level = 0;
void incrementLevel(){
setState(() {
level += 1;
});
}
#override
Widget build(BuildContext context){
return Text(
"$level",
style: TextStyle(
color: Colors.grey[900],
fontWeight: FontWeight.normal,
fontSize: 28,
),
);
}
}
It actually is a weird way of doing it. However, there is various ways of achieving this
To give an example:
You can use KEYs to remotely redraw the child state
If you want an advanced solution that can assist you in bigger projects. You can use state management tecniques. You can find a lot of tutorials in the internet but these are some of them. BLOC, Provider, InheritedWidget.
Basicaly all of them does the same thing. Lifts up the state data so the place of the redrawn widget on the widget tree will not be important.
I strongly encourage you to watch some tutorials starting with the Provider. I hope this helps