onTap: only static members can be accessed in initializers error - dart

Help, when i call myMethod in the onTap attribute of either a GestureDetector Widget or an InkWell widget, i get an only static members can be accessed in initializers error
static String seat1Source = 'images/carSeatBlack.png';
_stater(){
setState(() {
if(seat1Source == 'images/carSeatBlack.png'){
seat1Source = 'images/carSeatGreen.png';
}else{
seat1Source = 'images/carSeatBlack.png';
}
});
}
var seat1 = new InkWell(
onTap: () => _stater(),
child: new Image.asset(
seat1Source,
height: 30,
width: 60,
)
);

replace your InkWell variable by a function like this
_buildButton(){return new InkWell(
onTap: () => _stater(),
child: new Image.asset(
seat1Source,
height: 30,
width: 60,
)
);}

Another way around than the already mentioned is that you put that variable "seat1"
into the "Widget build(BuildContext context){}" function, as I think you're trying to initialize it into the constructor.

Related

How can I apply the onSaved method on my dropdownlist

I'm new on flutter, and would like to know how can I apply the onSaved method on my drpdownList.
Please Help!
Row(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width*.3,
child: Text('Départ:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
),
),
Container(
width: MediaQuery.of(context).size.width*.5,
child: _fieldDropDown(_citiesdept, 0, 'depart'),
// onSaved: (value) => _citiesdept = value,
)
],
),
Will this solve your question?
if you want a callback to your widget you need to:
change
_fieldDropDown(List theList, int resultPosition, var dbField) {
// to
_fieldDropDown(List theList, int resultPosition, var dbField, void Function(dynamic newValue) callback) {
make the call when required in the dropDown...
setState(() {
this.resultsList[resultPosition] = newValue;
// HERE is the callback:
callback(newValue);
state.didChange(newValue);
print(
'The List result = ' + this.resultsList[resultPosition]);
//write newValue to a database field, which can be used in the override init to set the field originally
});
and use it as you wish, for example ...
Container(
width: MediaQuery.of(context).size.width*.5,
child: _fieldDropDown(_citiesdept, 0, 'depart'),
callback: (value) => print(value),

How to prevent multiple touch on Flutter Inkwell

I new to flutter and i have a counter button that i want to prevent it from multiple touch.
The Tap Function is defined under Inkwell component (onTap: () => counterBloc.doCount(context)).
if i run this apps and doing multi touch, counter will go up quickly, but i dont want it happen. any idea ?
below are my code :
Expanded(
child: Container(
padding: EdgeInsets.only(right: 16),
alignment: Alignment.centerRight,
child: InkWell(
onTap: () => counterBloc.doCount(context),
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Image.asset("assets/images/home/tap.png", scale: 11,),
StreamBuilder(
initialData: 0,
stream: counterBloc.counterStream,
builder: (BuildContext ctx, AsyncSnapshot<int> snapshot){
return Text("${snapshot.data}",style: TextStyle(color: Colors.white, fontSize: 120),);
},
),
],
)
)
)
)
you can use an AbsorbPointer
AbsorbPointer(
absorbing: !enabled,
child: InkWell(
onTap: (){
print('buttonClicked');
setState(() {
enabled = false;
});
},
child: Container(
width: 50.0,
height: 50.0,
color: Colors.red,
),
),
),
and when you want to enable the button again, set the enabled to true, don't forget to wrap it with a setState
Try this? It should solve your problem.
class SafeOnTap extends StatefulWidget {
SafeOnTap({
Key? key,
required this.child,
required this.onSafeTap,
this.intervalMs = 500,
}) : super(key: key);
final Widget child;
final GestureTapCallback onSafeTap;
final int intervalMs;
#override
_SafeOnTapState createState() => _SafeOnTapState();
}
class _SafeOnTapState extends State<SafeOnTap> {
int lastTimeClicked = 0;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
final now = DateTime.now().millisecondsSinceEpoch;
if (now - lastTimeClicked < widget.intervalMs) {
return;
}
lastTimeClicked = now;
widget.onSafeTap();
},
child: widget.child,
);
}
}
You can wrap any kind of widget if you want.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
// every click need to wait for 500ms
SafeOnTap(
onSafeTap: () => log('500ms'),
child: Container(
width: double.infinity,
height: 200,
child: Center(child: Text('500ms click me')),
),
),
// every click need to wait for 2000ms
SafeOnTap(
intervalMs: 2000,
onSafeTap: () => log('2000ms'),
child: Container(
width: double.infinity,
height: 200,
child: Center(child: Text('2000ms click me')),
),
),
],
),
),
),
);
}
}
Another option is to use debouncing to prevent this kind of behaviour ie with easy_debounce, or implementing your own debounce.
You can also use IgnorePointer
IgnorePointer(
ignoring: !isEnabled
child: yourChildWidget
)
And when you disable the component, it starts ignoring the touches within the boundary of the widget.
I personally wouldn't rely on setState, I'd go with a simple solution like this:
Widget createMultiClickPreventedButton(String text, VoidCallback clickHandler) {
var clicked = false;
return ElevatedButton(
child: Text(text),
onPressed: () {
if (!clicked) {
clicked = true;
clickHandler.call();
}
});
}
You can also use a Stream to make counter to count only on debounced taps.
final BehaviourSubject onTapStream = BehaviourSubject()
#override
void initState() {
super.initState();
// Debounce your taps here
onTapStream.debounceTime(const Duration(milliseconds: 300)).listen((_) {
// Do something on tap
print(1);
});
}

Duplicate GlobalKey detected in widget tree in foreach

I have a map with loop of markers, for each marker i try to show snackbar with location name. I have a code similar to.
static final GlobalKey<ScaffoldState> scaffoldKey =
GlobalKey<ScaffoldState>();
for (int i = 0; i < list.length; i++) {
markers.add(new Marker(
width: 80.0,
height: 80.0,
point: list[1].values.elementAt(i),
builder: (ctx) => new Container(
child: new GestureDetector(
onTap: () {
scaffoldKey.currentState.showSnackBar(new SnackBar(
duration: const Duration(seconds: 5),
content: new Text(coords.keys.elementAt(i)),
action: SnackBarAction(
label: 'Ver',
onPressed: () {
// Some code to undo the change!
},
),
));
},
child: new Icon(Icons.home, color: Colors.red[300])))));
}
return new Scaffold(
key: scaffoldKey,
When i load this page doesn't load anything and console return
Duplicate GlobalKey detected in widget tree.
I figure the error is on the scaffold, for each iteration it's trying to set the same name of globalkey. So i need to identify this key with different name when its does the foreach. Any idea how can i do this?
Just remove the static modifier from your final GlobalKey<ScaffoldState> declaration .
final GlobalKey<ScaffoldState> scaffoldKey =
GlobalKey<ScaffoldState>();

List changed listeners

i have a listview builder in flutter which is used to load a images when i remove a item i want to set listener for my listview that data has changed.
this is complete code this class is used for create a image style.
How can i solve hwn i click iconbutton i want to remove a item from list,
onw this is its removing when i press another button or something else
class Users extends StatefulWidget
{
final List image;
final File imageURL;
const Users ({Key key, this.imageURL,this.image}) : super(key: key);
#override
UserWidgets createState() => UserWidgets();
}
class UserWidgets extends State<Users>
{
#override
Widget build(BuildContext context)
{
VideoPlayerController playerController;
VoidCallback listener;
Widget play=new Icon(Icons.play_arrow);
Widget pause=new Icon(Icons.pause);
return new Container(
height: 200.0,
child: Stack(
children: <Widget>[
widget.imageURL.toString().contains(".jpg") ||widget.imageURL.toString().contains(".png") ||
widget.imageURL.toString().contains(".jpeg") ?
new Container(
child: new Card(
child: new Column(
children: <Widget>[
new GestureDetector(
onTap: ()
{
Navigator.push(context, MaterialPageRoute(builder: (context) => VideoApp(file: widget.imageURL,)
),
);
},
child:
new Image.file(widget.imageURL
,fit: BoxFit.cover,
height: 200.0,
width: 150.0,
),
)
],
)
),
): widget.imageURL.toString().contains(".mp4") ||widget.imageURL.toString().contains(".3gp") ?
new Container(
height: 100.0,
child: AspectRatio(aspectRatio: 10/6,
child: GestureDetector(
onTap: ()
{
Navigator.push(context, MaterialPageRoute(builder: (context) => VideoApp(file: widget.imageURL,)
),
);
},
child:
VideoPlayer(playerController = VideoPlayerController.file (widget.imageURL)
..addListener(listener)
..setVolume(1.0)
..initialize()
,
)
)
)
): new
Container(),
new Positioned(
child:
IconButton(icon: Icon(Icons.remove_circle),
color: Colors.black,
onPressed : ()
{
setState(() {
widget.image.remove(widget.imageURL);
print("helo");
});
}
)
,
top: 0.0,
right: 0.0,
)
],
),
);
}
}
now i need to know that what is equivalent to notifdatasetchanged().

Callback function not working in flutter

Creating an example to learn callbacks in Flutter. It's a simple programme to increase the counter onTap of a GestureDetetor But, the callback method is not working. The count increase on hot reload but not on tap. Below is the code with comments.
class BoxState extends State<ChangeBoxState>{
int _counter = 0;
//Callback method changes the state onTap of GestureDetector widget. It is not calling onTap.
increaseCount(){
setState(() {
++_counter;
print(_counter);
});
}
#override
Widget build(BuildContext context) {
// Passing the callback method,"increaseCount()" to stateless class where GestureDetector is defined.
return BoxWidget(onPressed: increaseCount(), counter: _counter,);
}
}
Stateless class:
class BoxWidget extends StatelessWidget{
BoxWidget({this.onPressed, this.counter});
final VoidCallback onPressed;
final int counter;
#override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
decoration: BoxDecoration(color: Colors.blue[500]),
child: Column(
children: <Widget>[Center(child: Text('Hello, world!')),
GestureDetector(
onTap: onPressed, //Passing onPressed to onTap.
child: Container(
margin: const EdgeInsets.only(left:0.0, top:200.0, right:0.0, bottom:0.0),
height: 200.0,
width: 200.0,
decoration: BoxDecoration(
color: Colors.teal[200],
border: Border.all(color: Colors.yellow, width: 10.0, style: BorderStyle.solid),
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
child: Center(child: Text(counter.toString())),
),
),
],
),
);
}
}
remove the the bracket in increaseCount() because using the bracket you are creating an instance of your VoidCallback and this will run one time only so try this
return BoxWidget(onPressed: increaseCount, counter: _counter,);
You should provide the reference of increaseCount to the onPressed callback.
Here you are assigning increaseCount() (check braces) to the callback which first call increaseCount() function and its return value will be assigned to the onPressed. Thats why it is only incrementing one time on hot reload.
return BoxWidget(onPressed: increaseCount, counter: _counter,);

Resources