Custom Font Size : Increase and Decrease in Flutter - 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")),
],
),
),
);}}

Related

Flutter Semantics Reads button title on both single tap and double tap

I have a tooltip in my UI which has semantics label "Tooltip to know about your number". Below is the code snippet for the same.
Semantics(
label: 'Tooltip to know about your number',
child: InkWell(
child: Image.asset('images/info_selected.png'),
onTap: (){
//some action top show tooltip
},
),
),
When accessibility is ON , and I single tap on info Inkwell, it announce "Tooltip to know about your number" as expected. But my issue here , Its also announcing the same when I double tap.. It should only do the functionality which I wrote inside onTap function when I double tap. What is the best way to make it like , it should not announce when I double tap?
Same code is working fine in android and it announce only when I single tap.. only iOS screen reader is announcing the label on both single tap and double tap..
Same issue when I use Gesture Detector or Button instead of InkWell..
Inkwell have a onTap and onDoubleTap both functions available
Reference - https://api.flutter.dev/flutter/material/InkWell-class.html
Output :-
Code :-
import 'package:flutter/material.dart';
class InkwellExample extends StatefulWidget {
const InkwellExample({Key? key}) : super(key: key);
#override
State<InkwellExample> createState() => _InkwellExampleState();
}
class _InkwellExampleState extends State<InkwellExample> {
String taps = "";
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
body: SizedBox(
width: size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
InkWell(
child: const Icon(Icons.info),
onTap: () => setState(() {
taps = "TAP";
}),
onDoubleTap: () => setState(() {
taps = "Double TAP";
}),
),
Text(
taps == "" ? "" : taps,
style: const TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}
To keep screen readers from reading anything other than what you have in your label parameter, add excludeSemantics: true. So your code would look like this:
Semantics(
label: 'Tooltip to know about your number',
excludeSemantics: true,
child: InkWell(
child: Image.asset('images/info_selected.png'),
onTap: (){
//some action top show tooltip
},
),
),
Another parameter which may be of interest is onTapHint.
One reference I've used:
https://www.woolha.com/tutorials/flutter-using-semantics-mergesemantics-examples

Flutter - Custom Timer avoid moving numbers?

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.

Flutter: Very basic stupid beginner question

I am trying to learn Flutter and so I am following a YouTube tutorial.
Now I have a question I can't really describe, it is working but i don't understand why.
My Program contains two .dart files, you can see them below.
Is the the Question Class in questions.dart executed by pressing Button 1 or 3 (Answer 1, Answer 3)?
If I understand that correctly the buttons will execute "onPressed: _answerQuestions,". But _answerQuestions only changes the State of "questionIndex" and is not calling something else, right? The UI gets rebuild and the Question Text changes.
But Questions Class does change the appearence of the text with the "style", this is its only task right now?
So why do we have a second dart File for that? We could simply change the style within the main.dart?
main.dart:
import 'package:flutter/material.dart';
import './question.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
var questionIndex = 0;
void _answerQuestions() {
setState(() {
questionIndex = questionIndex + 1;
});
print(questionIndex);
}
#override
Widget build(BuildContext context) {
var questions = [
'What\'s your favorite color?',
'What\'s your favorite animal?',
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My First App'),
),
body: Column(
children: [
Question(questions[questionIndex]),
RaisedButton(
child: Text('Answer 1'),
onPressed: _answerQuestions,
),
RaisedButton(
child: Text('Answer 2'),
onPressed: () => print('Answer 2 chosen')),
RaisedButton(
child: Text('Answer 3'),
onPressed: _answerQuestions,
),
],
),
),
);
}
}
And question.dart:
import 'package:flutter/material.dart';
class Question extends StatelessWidget {
final String questionText;
Question(this.questionText);
#override
Widget build(BuildContext context) {
return Text(
questionText,
style: TextStyle(fontSize: 28),
);
}
}
Is the the Question Class in questions.dart executed by pressing
Button 1 or 3 (Answer 1, Answer 3)?
Both. Question is a StatlessWidget holding your question.
When you press any of the buttons(1 & 2) MyAppState gets rebuilt with a new question index and because you pass the question text to the Question Widget using that index, Question(questions[questionIndex]), Question will get a new value and show it, because you called setState, if you had not, behind the scenes it would still change the value but because the widget wouldn't be rebuilt, the visual side would stay the same.
The why you have two separate files? It makes it easier to see what your app is doing, especially for bigger projects. Usually, one file should have one purpose, do not mix functionalities in one file or you'll get a messy code really fast.
In this case, the equivalent for not having the question in a separate file would be:
body: Column(
children: [
// from
// Question(questions[questionIndex]),
// to
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
RaisedButton(
child: Text('Answer 1'),
onPressed: _answerQuestions,
),
RaisedButton(
child: Text('Answer 2'),
onPressed: () => print('Answer 2 chosen')),
RaisedButton(
child: Text('Answer 3'),
onPressed: _answerQuestions,
),
],
),
But what if you need to use that same question in several places?
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
You'll have to write that same code every time you need it, and this is a really simple one, imagine you have a widget with much more code, do you really want to write it all over again every time you need it?
No, you just create a new widget thas has the functionality you need and call it whenever you need it.
Question(questions[questionIndex]),
Question(questions[questionIndex]),
Question(questions[questionIndex]),
Question(questions[questionIndex]),
When i code in flutter, i usually tend to start a file for every new "screen" in the app.
Also, i create one file for I/O (api connections, DB...), and a file for common functions.
It is good to have several files because the moment you want to build a big app you will realise how long it is. My last app was around 10k lines of code. Impossible to mantain with only 1 file.
Also, dividing by file is useful for code reutilisation.
GL
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
var questionIndex = 0;
void _answerQuestions() {
setState(() {
questionIndex = questionIndex + 1;
});
print(questionIndex);
}
#override
Widget build(BuildContext context) {
var questions = [
'What\'s your favorite color?',
'What\'s your favorite animal?',
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My First App'),
),
body: Column(
children: [
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
RaisedButton(
child: Text('Answer 1'),
onPressed: _answerQuestions,
),
RaisedButton(
child: Text('Answer 2'),
onPressed: () => print('Answer 2 chosen')),
RaisedButton(
child: Text('Answer 3'),
onPressed: _answerQuestions,
),
],
),
),
);
}
}
It can be done.. As #Michael Said you'll get a messy code really fast. You should follow BEST PRACTICES While Learning a Language. It is equally IMPORTANT. Will help you in long RUN.

Flutter : How to make the flutter chip grow and shrink to match the label length

I am creating a flutter chip where the label has HTML text is tag (br) . I would like the label to break based on the "br tag and the chip widget size to reflect it.
Here my sample :
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: Text('AB'),
),
label: HtmlWidget('You have pushed the button <br>this many times:'),
),
I am using the "flutter_widget_from_html_core" to render html.
The text wraps but the widget stay the same size
can you please let me know how to fix it or an alternative
example
There seems to be some issue with HtmlWidget improperly calculating the size in case of a line break.
A simple fix should work.
EDIT: This code is responsive as well, just pass responsive:true
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Chip(
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: Text('AB'),
),
label: ResponsiveBrTag(
'You have pushed the button very hard <br> this many times:',
),
);
}
}
class ResponsiveBrTag extends StatelessWidget {
final String htmlText;
final bool responsive;
const ResponsiveBrTag(this.htmlText, {this.responsive = false});
#override
Widget build(BuildContext context) {
var splits = htmlText.split("<br>");
var fixedLayout = Column(
children: splits.map((s) => Text(s)).toList(),
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
);
var respLayout = Wrap(children: splits.map((s) => Text(s)).toList());
return responsive ? respLayout : fixedLayout;
}
}
Note: I have not completely tested it for bugs, it is just an example code.

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