I want to create a responsive appbar without need to setState to the entire scaffold when there are changes. The problem is I can set a BottomNavigationBar widget to the scaffold's bottomNavigationBar but I can't do the same with an AppBar to set to it's appBar. I get this error
The argument type 'TopBar' can't be assigned to the parameter type 'PreferredSizeWidget'
I've simplified the code with the States only part.
class StateLayoutNav extends State<LayoutNav>{
#override
Widget build(BuildContext context) => Scaffold(
bottomNavigationBar : BottomBar(), appBar : TopBar()
);
}
class StateTopBar extends State<TopBar>{
#override
Widget build(BuildContext context) => AppBar();
}
class StateBottomBar extends State<BottomBar>{
#override
Widget build(BuildContext context) => BottomNavigationBar();
}
My solution would be implementing your Appbar widget with PreferredSizeWidget as Appbar need to be of preferredSize
class TopBar extends StatefulWidget with PreferredSizeWidget {
TopBar({Key key}) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key);
#override
final Size preferredSize;
#override
StateTopBar createState() => StateTopBar();
}
class StateTopBar extends State<TopBar>{
#override
Widget build(BuildContext context) => AppBar();
}
Try appBar: TopBar() as PreferredSizeWidget
Try this. It will give you a custom app bar with any customisable widget. You can add fixed Container. Solution is implementing app bar with PreferredSizeWidget.
class TopBar extends StatefulWidget implements PreferredSizeWidget {
TopBar({Key? key}) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key);
#override
final Size preferredSize; // default is 56.0
#override
_TopBarState createState() => _TopBarState();
}
class _TopBarState extends State<TopBar>{
#override
Widget build(BuildContext context) {
return Container( child: Text("Sample App Bar") );
}
}
Related
For the code below, on the press of the icon of the first class, I want to send data to the second class. First-class just contains the data that needs to pass to the second class. There is no way or not allowed to navigate from first to second class. The only option to navigate to the second class is from the third class. I tried creating a constructor in the second class and implemented
second page(data:_getData.text). But there is no way i am getting the value. I am just getting null.
**First class**
onPressed: () { setState(() => _getData.text);
**SecondPage(data:_getData.text);**
}
**Second class**
class SecondPage extends StatefulWidget {
String? data;
SecondPage({this.data});
#override
_SecondPageState createState() => _SecondPageState(data);
}
class _SecondPageState extends State<SecondPage> {
String? data;
_SecondPageState(this.data);
**Third class**
Get.to(SecondPage)
if you change a lot of states, you would use bloc or any state management. because it is good for the app. if you want only this thing, you use the below code.
First Screen
class FirstScreen extends StatefulWidget {
const FirstScreen({Key? key}) : super(key: key);
#override
State<FirstScreen> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
String title = "no value_f";
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
title = "value";
});
},
child: Text("Press")),
SecondScreen(title: title),
],
),
);
}
}
Second Screen
class SecondScreen extends StatefulWidget {
String title;
SecondScreen({Key? key, required this.title}) : super(key: key);
#override
State<SecondScreen> createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
void initState() {
widget.title = "no value";
super.initState();
}
#override
Widget build(BuildContext context) {
return Text(widget.title);
}
}
I am trying to create an app. I want to change an attribute in a parent class (so it can display a Visibility item, SlidingUpPanel) after submitting a query in the child class (which is a search bar).
I have tried using a callback function and followed How can I pass the callback to another StatefulWidget? but it doesn't seem to do anything when I submit my query in the search bar. Previously, I have also tried to use Navigator.push to call SlidingUpPanel directly but it resulted in a black screen with only SlidingUpPanel.
Parent class (Map):
class MapPage extends StatefulWidget {
const MapPage({Key? key}) : super(key: key);
#override
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
bool IsVisible = false;
void callbackFunction() {
setState(() {
IsVisible = true;
});
}
...
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
...
Visibility(
visible: IsVisible,
child: SlidingUpPanel()),
SearchPage(callbackFunction),
]),
);
}
}
Child class (Search Bar):
class SearchPage extends StatefulWidget {
final Function callback;
SearchPage(this.callback);
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
...
#override
Widget build(BuildContext context) {
return FloatingSearchBar(
...
onSubmitted: (query) {
// callback here, but doesn't seem to do anything
widget.callback;
controller.close();
},
...
);
}
}
To actually call a function (execute it) you must use ().
Try calling the callback function like this:
onSubmitted: (query) {
// use () to actually call the function
widget.callback();
controller.close();
},
In my app tree hierarchy, I have a Stateful widget that represents the elements of a list. Let's call this class Item. This Widget contains an Image, some text, and a remove button that should remove the element when it's pressed. Later in the code, I have another Stateful class that holds the ListView and a List of Item which the ListView is created based on it.
My problem is that the onPressed() attribute of every Item is placed inside the item's class and not the upper class (the ListView) in which the remove operation should be handled. How can I fix this? How can I send a signal whenever the button is pressed to the parent widget in order to initiate removing the item?
import 'package:flutter/material.dart';
class Item extends StatefulWidget {
const Item({ Key? key }) : super(key: key);
#override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
#override
Widget build(BuildContext context) {
return Container(
child: Row(children: [
Image(),
Text('abc'),
Text('abc'),
Text('abc'),
ElevatedButton(onPressed: ????? , child: Text('RemoveButton'))
],),
);
}
}
class ListOfItems extends StatefulWidget {
const ListOfItems({ Key? key }) : super(key: key);
#override
_ListOfItemsState createState() => _ListOfItemsState();
}
class _ListOfItemsState extends State<ListOfItems> {
List<Item> ls = [];
int numOfItems = 0;
#override
Widget build(BuildContext context) {
return ListView(children: ls,)
}
}
Try like this
import 'package:flutter/material.dart';
class Item extends StatefulWidget {
final void Function(dynamic data) onPressedHandler;
const Item({ #required this.onPressedHandler, Key? key }) : super(key: key);
#override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
#override
Widget build(BuildContext context) {
return Container(
child: Row(children: [
Image(),
Text('abc'),
Text('abc'),
Text('abc'),
ElevatedButton(onPressed: () {
final data = 'Any additional data you want to paas';
widget.onPressedHandler(data);
} , child: Text('RemoveButton'))
],),
);
}
}
class ListOfItems extends StatefulWidget {
const ListOfItems({ Key? key }) : super(key: key);
#override
_ListOfItemsState createState() => _ListOfItemsState();
}
class _ListOfItemsState extends State<ListOfItems> {
List<Item> ls = [];
int numOfItems = 0;
onPressedHandler(data) {
}
#override
Widget build(BuildContext context) {
return ListView(children: [
Item(onPressedHandler: onPressedHandler),
],);
}
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
OrientationSingleton.left = true;
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft])
.then((_) {
runApp(new MyApp());
});
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
Here's my app. I've found some tutorials on how to remove it: flutter remove back button on appbar but it's for an AppBar. I tried making my app work on an AppBar but I get
MediaQuery.of() called with a context that does not contain a MediaQuery.
Because I rely on MediaQuery.of() inside my app.
So, how do I remove the Android back, home and square buttons on Flutter for a MaterialApp?
As stated in the error message, SystemChrome requires context - a place to call it could be the initState() method of the Widget:
class MyApp extends StatefulWidget {
const MyApp({ Key key }) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
OrientationSingleton.left = true;
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
}
#override
Widget build(BuildContext context) {
return MaterialApp(); // your MaterialApp class
}
}
To hide the system bottom bar on Android, one option could be to call the setEnabledSystemUIOverlays() function with an empty list:
SystemChrome.setEnabledSystemUIOverlays([]);
However, this function is not globally supported on all Android devices.
class ListItem extends StatefulWidget {
final Product product;
ListItem(this.bloc, this.product);
#override
_ListItemState createState() => _ListItemState(product);
}
class _ListItemState extends State<ListItem> {
Product product;
_ListItemState(this.product);
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(product.title),
trailing: LikeIcon(
id: product.id,
isFavourite: product.isFavorite,
likeStatusHandler: toggleLikeStatus,
),
);
}
}
class LikeIcon extends StatefulWidget {
final int id;
final bool isFavourite;
final Function(int) likeStatusHandler;
LikeIcon({
#required this.id,
#required this.isFavourite,
#required this.likeStatusHandler,
});
#override
_LikeIconState createState() => _LikeIconState(isFavourite);
}
class _LikeIconState extends State<LikeIcon> {
bool isFavourite;
_LikeIconState(isFavourite) {
this.isFavourite = isFavourite;
}
#override
Widget build(BuildContext context) {
return _favouriteWidget();
}
}
Initially I had made the ListItem widget as a StatelessWidget with LikeIcon widget as StatefulWidget which controls the enabled/disabled state of the Like icon within itself. The problem I faced there was, when I scrolled the list, the state of the like was lost.
Later I made the ListItem itself as a StatefulWidget and it solved the problem. But seeing the logs I noticed that the ListItem is rebuilt (build method is being called) every time I scroll.
If the ListItem is a StatelessWidget then the build method is not getting called on scroll. Rebuilding the entire ListItem on every scroll is something that I'm concerned with especially with large datasets with images involved in it.
Any explanation on a deeper level is appreciated.