Set default icon theme to cupertino flutter appbar - flutter

The app that im building requires me to have an AppBar with a leading back button. However I prefer the cupertino back button(iOS-style) for the leading icon instead of the default back button for android. I am aware that I can manually change the leading button of each AppBar by using an iconButton but i was wondering if there is any easy way to do this like a theme. Any help appreciated.

Instead of using MaterialApp as your root widget you can use CupertinoApp to do the same, assuming that the above changing of the AppBar is needed for each screen in your app. This will automatically set the icon as you require
Here is a simple example to help you
Root Widget or starting point of the app
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const CupertinoApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
Then using a CupertinoPageScaffold where you want the CupertinoNavigationBar (I mean your appbar with ios icons) with the chevron icon like ios
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
// Try removing opacity to observe the lack of a blur effect and of sliding content.
automaticallyImplyLeading: true // This will decide if the leading icon comes in by default
backgroundColor: CupertinoColors.systemGrey.withOpacity(0.5),
middle: const Text('Sample Code'),
),
child: Column(
children: <Widget>[
Container(height: 50, color: CupertinoColors.systemRed),
Container(height: 50, color: CupertinoColors.systemGreen),
Container(height: 50, color: CupertinoColors.systemBlue),
Container(height: 50, color: CupertinoColors.systemYellow),
],
),
);

Facing a relatively similar problem I used the builder property, which it should work with any App like :
CupertinoApp(
builder: (_, child) => IconTheme(
data: IconThemeData(
size: 15,
color: const Color(0xffffffff),
),
child: child,
),
)
My problem was with the default icon color and size but you can use AppBarTheme or any similar widget to achieve what you want.
This may help you override default value with majority of the lacking theme delegates when working with the cupertino family (It's not yet mature like the material but I can see the constant and rapid effort and the future of it).

Related

Flutter photo_view package gestures not working properly

Hi I am a flutter mobile developer and I tried to use this package: https://pub.dev/packages/photo_view/versions for an offline map. I tried zoom and drag and other gestures. It seems working properly for zooming most of the time, but when I tried to drag the picture It has a less than 10 percent success to move it. Here is my code, can somebody help me what coul'd I do wrong? In the package example It seems like It's working properly.
class OfflineMapWidget extends StatefulWidget {
final Session session;
final bool connectedToNetwork;
const OfflineMapWidget(
{Key? key, required this.session, required this.connectedToNetwork})
: super(key: key);
#override
_OfflineMapWidgetState createState() => _OfflineMapWidgetState();
}
class _OfflineMapWidgetState extends State<OfflineMapWidget> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.black,
child: SafeArea(
child: Theme(
data: ThemeData(
brightness: Brightness.dark,
appBarTheme: AppBarTheme(
backgroundColor: Color.fromARGB(255, 65, 116, 131))),
child: Scaffold(
appBar: AppBar(
leading: MenuWidget(),
actions: [widget.connectedToNetwork ? QrPaymentButton(session: widget.session) : Container()],
),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.white,
child: PhotoView(
imageProvider: AssetImage('assets/images/offline_map.png'),
),
),
),
),
),
);
}
}
Update: I found the problem. This Widget was in a ZoomDrawer (another pub dev package), and that Widget confused this one, so I need to find another solution. If somebody else uses this 2 package in one the problem is here. The solution is simple, you can disable drag in ZoomDrawer with the disableDragGesture property. If you don't want to disable it on all menu points you can check if you are in the mentioned menu point and disable only when this one is up.I write this one down in the comments as well so it will be more clear.
I found the problem. This Widget was in a ZoomDrawer (another pub dev package), and that Widget confused this one, so I need to find another solution. If somebody else uses this 2 package in one the problem is here. The solution is simple, you can disable drag in ZoomDrawer with the disableDragGesture property. If you don't want to disable it on all menu points you can check if you are in the mentioned menu point and disable only when this one is up.

Structure of a flutter project

How to structure a flutter project like this one:
Example restaurant pos image
Do you find this beginning of the tree structure correct:
class HomePageState extends State<HomePage>{
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Row(
children: [
Container( // menu
width:60,
color: Colors.white,
),
Expanded( // body
child: Container(
color: Colors.red,
),
),
Container( // ListProducts
width:300,
color: Colors.green,
),
],
),
backgroundColor: Color.fromARGB(255 , 244 , 246, 250),
)
);
}
}
code preview
You might want to place that MaterialApp into a separate parent widget (I think it will cause issues when using MediaQuery and Theme inside the same build method). It also might be cleaner down the line to extract every part (menu, body, ListProducts) into separate widgets.
Also, I would advise you to take a look at the LayoutBuilder widget,
and the ressources on this page if the app is meant to work on narrower screens.
Oh and if you don't know about state management, definitely check this out.

Make Flutter Status Bar Solid

My app doesn't use AppBar, and the content is overlapping with status bar when scrolled. I tried using AnnotatedRegion<SystemUiOverlayStyle>, however it doesn't change anything.
Overlapped
My best try is using SafeArea, however it turned Status Bar to grey.
Grey Safe Area
Is there a way to maintain the automatic color of status bar, without it overlapping with the content?
Additional Note:
Flutter 1.17.5
My Tree
SafeArea
|_ SingleChildScrollView
|_ Column
|_ Container
|_ Container
|_ Container
EDIT: I just realized the automatic color (status bar follow the first container's color) was because it was transparent. I was thinking of making it solid on runtime, and read it from the first colored widget.
import 'package:flutter/services.dart';
#override
Widget build(BuildContext context){
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.blue, //or the color you prefer
),
child: SafeArea(child: Scaffold(...)),
);
}
You need to wrap your SafeArea widget with Container widget to change the color of the SafeArea widget
SAMPLE CODE
Scaffold(
backgroundColor: Colors.white,
body: Container(
color: Colors.red, /* Set your status bar color here */
child: SafeArea(
child: Container(
/* Add your Widget here */
)),
),
);
Another way You can use AppBar
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.0,
backgroundColor: Colors.red,
),
body: Container(
child: //widget
)
);
}

Flutter - System bar colors with SafeArea

I am trying to add SafeArea widget for the flutter app with colorized system bars but somehow they are always turning black.
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.light.copyWith(
systemNavigationBarIconBrightness: Brightness.dark,
systemNavigationBarColor: kSurfaceColor,
statusBarIconBrightness: Brightness.dark,
statusBarColor: Colors.red, // Note RED here
),
);
return SafeArea(
child: Scaffold(
backgroundColor: kWhiteColor,
appBar: _buildAppBar(context), // Title and Avatar are built here
body: _buildBody(), // This function just returns blank Container for now
floatingActionButton: _buildFAB(context),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
),
);
}
This is what I see
If I wrap SafeArea inside a Container with color property set to white, it works but system bar icons also turn white
Building on #david-carrilho's answer, I created this simple widget
import 'package:flutter/material.dart';
class ColoredSafeArea extends StatelessWidget {
final Widget child;
final Color color;
const ColoredSafeArea({Key key, #required this.child, this.color})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
color: color ?? Theme.of(context).colorScheme.primaryVariant,
child: SafeArea(
child: child,
),
);
}
}
Then wherever I would use a SafeArea, I use my little wrapper widget ColoredSafeArea.
class MyExampleView extends StatelessWidget {
const MyExampleView({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ColoredSafeArea(
child: Center(
child: Text('Nice color bar'),
),
);
}
}
The reason why this works is because it creates a container behind your content with the specified color, then SafeArea simply adds the necessary padding based on the device.
Container(
color ...
),
child: SafeArea(
child: Scaffold(
body:
AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: ...
I know this is an old question, but after reading the documentation I came up with a more complete solution.
My answer considers the following:
Don't wrap Scaffolds into SafeAreas;
[iOS] paint your Scaffold the right Color;
[Android] set the System Bars programmatically.
1. Proper use of SafeArea
SafeArea is a widget that performs a MediaQuery to add some proper padding to your application. This should happen inside the body of your Scaffold application. Something like this will lead to code that won't unexpectedly break later on:
return Scaffold(
// ...
body: SafeArea( // your SafeArea should stay here
child: YourWidget(),
),
);
2. iOS Notch
As other answers said already, you just have to paint your Scaffold so that you'll get the color you want. Your Scaffold should include a backgroundColor property (and your AppBar too, if you have one).
return Scaffold(
// ...
backgroundColor: yourColor, // the RED you need
appBar: AppBar( // if any
backgroundColor: yourColor, // maybe RED here, also
// a system overlay option is included here, too, see 3.
// ...
),
body: SafeArea( // your SafeArea should stay here
child: YourWidget(),
),
);
3. Android SystemUI
As OP did, you need SystemChrome.setSystemUIOverlayStyle() to address Android-related system bar paints.
However, the documentation says that this method should be called programmatically whenever a new page / a new route is being popped or pushed, if you have different Route colors.
Suppose you have a 2.0 Router; then, you would write its build method as it follows:
Widget build(BuildContext context) {
Color overlayColor = ... your color ...;
final systemBarColors = SystemUiOverlayStyle(
systemNavigationBarColor: overlayColor,
statusBarColor: overlayColor,
);
SystemChrome.setSystemUIOverlayStyle(systemBarColors);
return AnnotatedRegion<SystemUiOverlayStyle>(
value: systemBarColors,
child: Navigator(
key: navigatorKey,
pages: _stack,
onPopPage: _onPopPage,
),
);
}
This will ensure that every time a new page is popped or pushed, i.e. the build method of our Router is called, the Android system bar and status bar are properly painted.
For your case just wrapping SafeArea() to the top widget that will be DISPLAYED on the screen(example: your 'Today' text widget) should avoid the black color on system bar.
Full example.
Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SafeArea(
child: Text('Today'),
),
Text('Tomorrow')
]
);
This worked for me!
Replace your Overlay style with below code it will work
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.dark.copyWith(statusBarColor: Colors.white));
set only main class
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.light.copyWith(
systemNavigationBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.white,
statusBarIconBrightness: Brightness.light,
statusBarColor: HexColor(HexColor.primarycolor), // Note RED here
),
);
my Example code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'HexColor.dart';
class CityListActiviy extends StatefulWidget {
// Initially password is obscure
#override
State<CityListActiviy> createState() => _CityListActiviyState();
}
class _CityListActiviyState extends State<CityListActiviy> {
TextEditingController userid_Controller = new TextEditingController();
bool userid_validate = false;
final String requiredNumber = '123456';
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.light.copyWith(
systemNavigationBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.white,
statusBarIconBrightness: Brightness.light,
statusBarColor: HexColor(HexColor.primarycolor), // Note RED here
),
);
return MaterialApp(
debugShowCheckedModeBanner: true,
home: LoaderOverlay(
child:SafeArea(
child: Scaffold(
backgroundColor: HexColor(HexColor.gray_activity_background),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Stack(
children: [
Container(
height: 60,
padding: new EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: HexColor(HexColor.white),
),
width: MediaQuery.of(context).size.width,
child: Text("Select Your Location",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.grey,
fontFamily: 'montserrat_medium',
decoration: TextDecoration.none,
))),
],
)
]),
)),
)
),
);
}
}

Using SafeArea in Flutter

I am trying to understand the SafeArea widget in Flutter.
SafeArea code added to Flutter Gallery app here in github show top:false and bottom:false everywhere. Why do these need to be set false in these cases?
SafeArea is basically a glorified Padding widget. If you wrap another widget with SafeArea, it adds any necessary padding needed to keep your widget from being blocked by the system status bar, notches, holes, rounded corners, and other "creative" features by manufacturers.
If you are using a Scaffold with an AppBar, the appropriate spacing will be calculated at the top of the screen without needing to wrap the Scaffold in a SafeArea and the status bar background will be affected by the AppBar color (Red in this example).
If you wrap the Scaffold in a SafeArea, then the status bar area will have a black background rather than be influenced by the AppBar.
Here is an example without SafeArea set:
Align(
alignment: Alignment.topLeft, // and bottomLeft
child: Text('My Widget: ...'),
)
And again with the widget wrapped in a SafeArea widget:
Align(
alignment: Alignment.topLeft, // and bottomLeft
child: SafeArea(
child: Text('My Widget: ...'),
),
)
You can set a minimum padding for edges not affected by notches and such:
SafeArea(
minimum: const EdgeInsets.all(16.0),
child: Text('My Widget: ...'),
)
You can also turn off the safe area insets for any side:
SafeArea(
left: false,
top: false,
right: false,
bottom: false,
child: Text('My Widget: ...'),
)
Setting them all to false would be the same as not using SafeArea. The default for all sides is true. Most of the time you will not need to use these settings, but I can imagine a situation where you have a widget that fills the whole screen. You want the top to not be blocked by anything, but you don't care about the bottom. In that case, you would just set bottom: false but leave the other sides to their default true values.
SafeArea(
bottom: false,
child: myWidgetThatFillsTheScreen,
)
Supplemental code
In case you want to play around more with this, here is main.dart:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: BodyWidget(),
),
);
}
}
class BodyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topLeft,
child: SafeArea(
left: true,
top: true,
right: true,
bottom: true,
minimum: const EdgeInsets.all(16.0),
child: Text(
'My Widget: This is my widget. It has some content that I don\'t want '
'blocked by certain manufacturers who add notches, holes, and round corners.'),
),
);
}
}
When you wrap a widget A in a safe area, you are asking to the framework "Please, keep my widget A away from the device's UI navigation and notches".
The arguments 'top, bottom, right and left' are used to tell to the framework if you want him to avoid the device's intrusions from that sides specifically.
For example: if you put your widget A inside a safe area in the top of the screen and sets the "top" argument to false, it will be cropped by the iPhone's X and Pixel 3's notches.
SafeArea is a widget that sets its child by enough padding to avoid intrusions by the operating system and improve the user interface.
import 'package:flutter/material.dart';
class SafeArea extends StatefulWidget {
#override
_SafeAreaState createState() => _SafeAreaState();
}
class _SafeAreaState extends State<SafeArea> {
#override
Widget build(BuildContext context) {
MediaQueryData mediaQueryData=MediaQuery.of(context);
double screenWidth = mediaQueryData.size.width;
var bottomPadding=mediaQueryData.padding.bottom;
return Padding(
padding: EdgeInsets.only(bottom: bottomPadding),
child: Scaffold(
body: new Container(
),
),
); }}
Without using SafeArea in iPhone 12 pro max
With using SafeArea
Code snippet using SafeArea
SafeArea(
child: Text('Your Widget'),
)