How to add a mark as fabourtie icon in my flutter app? - flutter

I am developing a Quotes app as a beginner in flutter.I have multiple page in my app.Right now i want to create an icon button which will perform as a bookmark(Mark as fabourite) for the user.So i added the flutter fabourite button in my app.Initially it stays white and when i touch it ,it becomes red,which i wants.But when i move to another page and get back to the previous one(Where the fabourite icon was added) the button become white...I want it to stay red unles the user touch it again.I just want it to be used as an marked as fabourite icon...What can i do now?
class p1 extends StatefulWidget {
#override
_p1State createState() => _p1State();
}
class _p1State extends State<p1> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body:Stack(
children:<Widget>[
Image(
image:AssetImage("Image/Chowsun1.jpg"),
fit:BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
Align(alignment: Alignment.center,
child: Text(' Hello world '
,style: TextStyle(fontSize: 35.0,
color: Colors.white,
fontFamily: "Explora",
fontWeight: FontWeight.w900 ) )
),
Align(
alignment: Alignment.bottomLeft,
child: const Text(' 1 ',
style: TextStyle(
fontSize: 25.0,
fontFamily: "MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w900),
),
),
Align(
alignment: Alignment.bottomCenter,
child: FavoriteButton(
isFavorite: true,
iconSize: 40,
iconDisabledColor: Colors.red,
iconColor: Colors.white,
// iconDisabledColor: Colors.white,
valueChanged: (_isFavorite) {},
)
)])
),
);
}
}

The issue is that you are not storing the state of the _isFavorite anywhere, that's what we use StatefulWidget for, is to keep track of state (and changes to it)
At the start of your class, declare a bool to track this value in:
class _p1State extends State<p1> {
bool _isFavorite = false;
then later in your build method:
FavoriteButton(
isFavorite: _isFavorite,
Finally, once you tap the button, you'll need to inform your class that the value has changed:
valueChanged: (isFav) {setState(() { _isFavorite = isFav; })},
Note that I changed the argument in your valueChanged, because we are now tracking the value in _isFavorite (the leading underscore indicates it's a privately scoped variable, on the class. And isFav is scoped only to the valueChanged method, so it doesn't actually need the leading underscore.

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

How to use Flutter hive for creating a mark as fabourite button?

I am developing a Quotes app as a beginner Practice project in flutter. I have multiple pages in my app. Right now I want to create an icon button which will perform as a bookmark (Mark as favourite) for the user.And in the app bar there will be a favourite option where the user can find those marked page number.Local databse seems too confusing to me.How can i use Hive for that problem.
class p1 extends StatefulWidget {
#override
_p1State createState() => _p1State();
}
class _p1State extends State<p1> {
bool _isFavorite = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body:Stack(
children:<Widget>[
Image(
image:AssetImage("Image/Chowsun1.jpg"),
fit:BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
Align(alignment: Alignment.center,
child: Text(' Hello world '
,style: TextStyle(fontSize: 35.0,
color: Colors.white,
fontFamily: "Explora",
fontWeight: FontWeight.w900 ) )
),
Align(
alignment: Alignment.bottomLeft,
child: const Text(' 1 ',
style: TextStyle(
fontSize: 25.0,
fontFamily: "MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w900),
),
),
Align(
alignment: Alignment.bottomCenter,
child: FavoriteButton(
isFavorite: _isFavorite,
iconSize: 40,
iconDisabledColor: Colors.red,
iconColor: Colors.white,
valueChanged: (isFav) {setState(() { _isFavorite = isFav; });},
)
)])
),
);
}
}
To bookmark or add favorites you need to persist the quotes. For that, you need to add these two packages https://pub.dev/packages/hive and https://pub.dev/packages/hive_flutter. What you are asking is for the whole code so I suggest you go through this easy documentation for hive implementation. https://docs.hivedb.dev/#/README
For a quick overview refer to this code.
After initializing await Hive.initFlutter(); and opening a box await Hive.openBox('testBox'); in main().
Make a box reference in your respective class then add the value box.put('key', 'Value'); Hive stores data in key-value pairs.

Why does my widget rebuild when I use keyboard

I have this issue of rebuilding widget when The keyboards shows up. I tried to use the sizer package but never could figure out how to get it to work
when I go back from this screen everything in the previous screen will rebuild, Please note: If I don't click on the typeaheadwidget such that the keyboard doesn't show up the state is preserved in the previous screen but as soon as the keyboard pops up the widgets get rebuilt
Could you please check ?
class SearchScreen extends StatefulWidget {
#override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
TextEditingController pickUpTextEditingController = TextEditingController();
TextEditingController dropOffTextEditingController = TextEditingController();
#override
void initState() {
super.initState();
}
#override
#mustCallSuper
Widget build(BuildContext context) {
String placeAddress =
Provider.of<AppData>(context).pickUpLocation.placeName ?? "";
pickUpTextEditingController.text = placeAddress;
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
Container(
height: 250.0,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 6.0,
spreadRadius: 0.5,
offset: Offset(0.7, 0.7),
)
],
),
child: Padding(
padding: EdgeInsets.only(
left: 25.0, top: 30.0, right: 25.0, bottom: 20.0),
child: Column(
children: [
SizedBox(height: 5.0),
Stack(
children: [
GestureDetector(
onTap: () {
Navigator.pop(
//send back data
context,
dropOffTextEditingController.text);
},
child: Icon(Icons.arrow_back)),
Center(
child: Text(
"Set Drop Off",
style: TextStyle(
fontSize: 18.0, fontFamily: "Brand-Bold"),
),
)
],
),
SizedBox(height: 16.0),
Row(
children: [
Image.asset("images/images/pickicon.png",
height: 16.0, width: 16.0),
SizedBox(width: 18.0),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(5.0),
),
child: Padding(
padding: EdgeInsets.all(3.0),
child: TextField(
controller: pickUpTextEditingController,
decoration: InputDecoration(
hintText: "PickUp Location",
fillColor: Colors.grey[400],
filled: true,
border: InputBorder.none,
isDense: true,
contentPadding: EdgeInsets.only(
left: 11.0, top: 8.0, bottom: 8.0),
),
),
),
))
],
),
SizedBox(height: 10.0),
Row(
children: [
Image.asset("images/images/desticon.png",
height: 16.0, width: 16.0),
SizedBox(width: 18.0),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(5.0),
),
child: Padding(
padding: EdgeInsets.all(3.0),
child: TypeAheadField(
itemBuilder: null,
onSuggestionSelected: null,
suggestionsCallback: null,
),
),
),
),
],
),
],
),
),
),
],
),
);
}
}
You should not try to control when the build method is called. Flutter will call build when it decides it needs to (e.g. keyboard appears, device rotated, parent rebuilds, etc).
Instead, you should make sure that your build method is a "pure" function. In Flutter specifically, this means that you should not perform any action with "side-effects" (basically anything which modifies the state of the app).
For example:
Widget build(BuildContext context) {
final x = 2 + 3; // fine, nothing else is modified
final state = context.watch<MyModel>(); // also fine, only reading data
controller.text = "hello"; // BAD, modifies the state of the app
return ...;
}
Instead, you should move your logic with side effects into other lifecycle methods (e.g. initState(), didChangeDepencencies(), etc).
For example, if you want to set your text field to a particular string when it first appears, you can use initState:
class _SearchScreenState extends State<SearchScreen> {
#override
void initState() {
super.initState();
final data = context.read<AppData>();
controller.text = data.pickUpLocation.placeName ?? "";
}
Widget build(BuildContext context) {
// ...
}
}
Now build() can be called whenever it has to be, without resetting the state of your text field.
Note that, even if there was some way to prevent your widget from being rebuilt, this is also likely not what you want, since the UI would not update to accommodate the keyboard.
the only reason why your widgets got rebuilds after keyboard pop up.
is that one or more of your widgets size depends on MediaQuery.
you can try to ge your screen size from LayoutBuilder as an alternative for MediaQuery.
Give the textfield an initial value like this:
initvalue:Provider.of<AppData>(context).pickUpLocation.placeName ?? ""
and use onchange method in text field instead of text editing controller like this:
onchange(value){
Provider.of<AppData>(context).pickUpLocation.placeName=value;}
I am also facing the same issue, My blocBuidler is getting rebuilt every time when click on textfield or keyboard is appear.
In my case, I was calling the event in parent BlocBuilder so whenever I pressed on textfields the parent BlocBuilder is called the event, so it builds state of child BlocBuilder
Make sure you are also doing the same thing. If you are doing the same thing please check the state whether it is already built or not.
(BlocProvider.of<YourBlocName>(context).state is YouBlocState) ? Print('do nothing'): BlocProvider.of<YourBlocName>(context).add(youBlocEvent);
When you tap the TextField widget, it makes the keyboard show up. And when the keyboard shows up, your screen size changes. This causes the rebuild

Flutter web Instance of 'minified:eU<void>'

I am building a Flutter web app, which runs flawlessly in debug mode, but whenever I try to run it in release mode or deploy it to the hosting I see a grey box.
I see this:
Instead of this:
As you may see, this is an alertDialog, here is the code of it:
class TeamDetailsDialog extends StatelessWidget {
final Tournament tournament;
final Team team;
final String matchId;
TeamDetailsDialog(this.team, this.matchId, this.tournament);
#override
Widget build(BuildContext context) {
return Theme(
data: ThemeData(buttonBarTheme: ButtonBarThemeData(alignment: MainAxisAlignment.spaceBetween)),
child: AlertDialog(
backgroundColor: Color(0xFF333D81),
title: Text(
"Csapatnév: ${team.name}",
style: TextStyle(color: Colors.white),
),
content: DefaultTextStyle(
style: TextStyle(color: Colors.white),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Align(alignment: Alignment.centerLeft, child: Text("A csapat tagjai:")),
),
for (Player player in team.players) Text("${player.displayName}(${player.inGameDisplayName})")
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(
"Bezárás",
style: TextStyle(color: Colors.white),
)),
Spacer(),
TextButton(
onPressed: () {
// Retrieving the match object from the Cubit.
final Match matchWithoutWinner =
BlocProvider.of<TournamentCubit>(context).getMatchOfTournamentById(tournament, matchId);
// Creating a new match instance containing the winner team.
if (matchWithoutWinner is DoubleEliminationLoserBranchMatch) {
final DoubleEliminationLoserBranchMatch matchWithWinner = DoubleEliminationLoserBranchMatch(
matchWithoutWinner.id,
matchWithoutWinner.team1,
matchWithoutWinner.team2,
team,
matchWithoutWinner.parent1id,
matchWithoutWinner.parent2id);
BlocProvider.of<TournamentCubit>(context).setWinnerOfMatch(tournament, matchWithWinner);
}
else {
final Match matchWithWinner = Match(matchWithoutWinner.id, matchWithoutWinner.team1,
matchWithoutWinner.team2, team, matchWithoutWinner.parent1id, matchWithoutWinner.parent2id);
BlocProvider.of<TournamentCubit>(context).setWinnerOfMatch(tournament, matchWithWinner);
}
Navigator.pop(context);
},
child: Text(
"Beállítás győztesnek",
style: TextStyle(color: Colors.white),
))
],
),
);
}
}
I've found out that the grey box is the release version of the red screen of death. After that, I checked, none of the injected variables are null. There is only one problem in debug:
What could be the problem? Could this cause the issue and how can I fix it?
The cause of the issue was the Spacer() between the two buttons in the actions list, removing it fixed the problem, without changing the UI.

Not able to import variable from a different class in Flutter

I am going off of a login screen tempalte,a nd am trying to get a widget class for a button to just show the username input as an alert on the screen. The usernameinput widget is defined but when I import it, it does not work.
class _InputEmailState extends State<InputEmail> {
final myController = new TextEditingController();
This is the part where I define the input, and this is where I import the class in the button widget:
import 'package:login_minimalist/widget/inputEmail.dart';
When I try and reference the myController.text value, I get the error
The getter 'myController' isn't defined for the class '_ButtonLoginState'.
import 'package:flutter/material.dart';
import 'package:login_minimalist/widget/inputEmail.dart';
class ButtonLogin extends StatefulWidget {
#override
ButtonLoginState createState() => ButtonLoginState();
}
class ButtonLoginState extends State<ButtonLogin> {
#override
Here is the button widget code:
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 40, right: 50, left: 200),
child: Container(
alignment: Alignment.bottomRight,
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.blue[300],
blurRadius: 10.0, // has the effect of softening the shadow
spreadRadius: 1.0, // has the effect of extending the shadow
offset: Offset(
5.0, // horizontal, move right 10
5.0, // vertical, move down 10
),
),
],
color: Colors.white,
borderRadius: BorderRadius.circular(30),
),
child: FlatButton(
onPressed: () {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
// Retrieve the text the user has entered by using the
// TextEditingController.
content: Text(InputEmailState.getUsername),
);
},
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Sign in',
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
Icon(
Icons.arrow_forward,
color: Colors.lightBlueAccent,
),
],
),
),
),
);
And here is the Input code:
class InputEmailState extends State<InputEmail> {
final myController = new TextEditingController();
getUsername() {
return(myController.text);
}
#override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 50, left: 50, right: 50),
child: Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: TextField(
controller: myController,
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
border: InputBorder.none,
fillColor: Colors.lightBlueAccent,
labelText: 'Student ID',
labelStyle: TextStyle(
color: Colors.white70,
fontSize: 20,
),
),
),
),
);
}
If I understand your question correctly, you're trying to access _ButtonLoginState from another class/file. However, in Dart, classes, members, variables, etc. that begin with an underline ("_") are considered private. You can't access them from a different file (except in some special situations with libraries).
To solve this, you can change the name of the class to ButtonLoginState and it should work.
EDIT: In response to more info:
You don't seem to have fully understood the concepts of State in a StatefulWidget. I would strongly recommend taking a good look through the Flutter guide on the subject.
There are many different ways of managing state and what I am going to explain is almost definitely not the best option most of the time (this was the introductory approach some time ago, but I can't even find the example anymore), however, it does work. For a more general option, I recommend Provider.
In your case, the problem starts with this: Text(InputEmailState.getUsername). You're not calling InputEmailState.getUsername, you're simply passing a reference to it. You need to include parentheses to actually call it - InputEmailState.getUsername().
However, this isn't the whole issue. You're trying to access this function using the name of the class, which means you're trying to use it as a static method. However, its an instance method (ie: you need a specific instance of the class to access it. This is the state I was talking about.
To simply get access to the state object of a specific widget, you can use a Key (generally a GlobalKey). You can define this in a parent widget, for example, and pass it as the key parameter of your InputEmail widget and keep a reference in the parent class. Then, to get the username, you can call <key>.currentState.getUsername() which will return the instance value. The exact implementation varies, and I don't have your code to know how it should be implemented.
As I say, this isn't really the recommended approach anymore. I strongly recommend getting to grips with the state concept, then it should be obvious what the best approach is.