Scaffold Status Bar Blocking Button Touch - flutter

Although I am in full screen mode where status bar is hidden but still my menu button on top right corner is not receiving touch. You can see in picture where I have selected the top bar which is receiving the touch.
Half of my menu button is receiving touch and half is not.
I have Also taken picture of Flutter Inspector in Widget Select Mode
I am also adding my custom button code. Just for reference:
class RoundIconButton extends StatelessWidget {
RoundIconButton({
Key key,
#required this.onPressed,
#required this.icon,
this.fillColor = Colors.transparent,
}) : super(key: key);
final Icon icon;
final Function onPressed;
final Color fillColor;
#override
Widget build(BuildContext context) {
return RawMaterialButton(
child: icon,
onPressed: onPressed,
shape: CircleBorder(),
fillColor: fillColor,
constraints: BoxConstraints.tightFor(height: 50.0, width: 50.0),
);
}
}

You have to wrap your Scaffold with SafeArea like,
without SafeArea layout looks like:
with SafeArea layout looks like:

use
Scaffold in body in child SafeArea and SafeArea inside insert all page
safearea has notch and bottom bar avoid
Scaffold(
body: SafeArea(
child: ...........
...........
),
),

Related

SingleChildScrollView + Controller - Page resets to top when resizing window

I am creating a flutter Web application, but have issues when resizing the window with a SingleChildScrollView + ScrollController.
When I resize the browser window, the page "snaps" back up to the very top. Being a web app, most of the page "sections" are made from Columns with responsively coded widgets as children, with such widgets as Flexible or Expanded. From what I have read, the SingleChildScrollView widget doesn't work well with Flexible or Expanded widgets, so I thought that may be my issue.
For testing purposes, I created a new page with a single SizedBox that had a height of 3000, which would allow me to scroll. After scrolling to the bottom and resizing the window, I was still snapped up to the top of the page. Thus, with or without using Expanded or Flexible widgets, I have the same result.
Test with a SizedBox only
#override
Widget build(BuildContext context) {
return Scaffold(
color: Colors.white,
body: SingleChildScrollView(
controller: controller.scrollController,
primary: false,
child: Column(
children: [
SizedBox(
width: 150,
height: 3000,
),
],
),
),
);
}
I am using Getx with this project to try getting a demo app up and running a bit quicker while I am still learning the core concepts. Below is my controller.
Controller
class HomePageScrollControllerX extends GetxController {
late ScrollController scrollController;
#override
void onInit() {
super.onInit();
scrollController = ScrollController(
initialScrollOffset: 0.0,
keepScrollOffset: true,
);
}
}
Thank you in advance for any insight on this subject!
EDIT
I have added a listener on my ScrollController, which is able to print to the console that I am scrolling. However, the listener does not get called when I resize the window (tested in both Chrome and Edge).
Currently, I believe my only option is to use the listener to update an "offset" variable in the controller, and pass the window's width over to the controller when the widget rebuilds. If done properly, I should be able to use the controller to scroll to the saved offset. Something like this:
if (scrollController.hasClients) {
if (offset > scrollController.position.maxScrollExtent) {
scrollController.jumpTo(scrollController.position.maxScrollExtent);
} else if (offset < scrollController.position.minScrollExtent) {
scrollController.jumpTo(scrollController.position.minScrollExtent);
} else {
scrollController.jumpTo(offset);
}
}
However, I feel like this shouldn't be necessary - and I bet this solution would be visually evident to the user.
Edit 2
While I did get this to work with adding the below code just before the return statement, it appears that my initial thoughts were correct. When I grab the edge of the window and move it, it pops up to the top of the window, then will jump to the correct scroll position. It looks absolutely terrible!
#override
Widget build(BuildContext context) {
Future.delayed(Duration.zero, () {
controller.setWindowWithAndScroll(MediaQuery.of(context).size.width);
});
return PreferredScaffold(
color: Colors.white,
body: SingleChildScrollView(
controller: controller.scrollController,
......
I implemented your code without getX by initializing the scrollController as a final variable outside your controller class. I ran it on microsoft edge and did not face the issue you are describing. What's causing your problem is most probably the way you are handling your state management with getX. I'm guessing your onInit function is run multiple times when you are resizing your web page and that's why the page snaps back up. I would recommend logging how many times the onInit function is called.
I found the answer, and it was my scaffold causing the issue - specifically, the scaffold key. But, before that, the Getx usage to get the answer is very easy, so for those of you looking for that particular answer, it is shown below.
Getx Controller
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
class HomePageScrollControllerX extends GetxController {
late ScrollController scrollController;
#override
void onInit() {
super.onInit();
scrollController =
ScrollController(keepScrollOffset: true, initialScrollOffset: 0.0);
}
#override
void onClose() {
super.onClose();
scrollController.dispose();
}
}
Stateless Widget Build Function
class HomePage extends StatelessWidget {
HomePage({
Key? key,
}) : super(key: key);
// All child widgets can use Get.find(); to get instance
final HomePageScrollControllerX controller =
Get.put(HomePageScrollControllerX());
#override
Widget build(BuildContext context) {
return PreferredScaffold(
color: Colors.white,
body: SingleChildScrollView(
controller: controller.scrollController,
primary: false,
... Etc
So, why didn't this work for me? I created a class called "PreferredScaffold" to save myself a few lines of repetitive code.
PreferredScaffold
class PreferredScaffold extends StatelessWidget {
final Widget? body;
final Color? color;
const PreferredScaffold({Key? key, this.body, this.color = Colors.white})
: super(key: key);
#override
Widget build(BuildContext context) {
final GlobalKey<ScaffoldState> scaffoldState = GlobalKey();
return Scaffold(
key: scaffoldState,
backgroundColor: color,
appBar: myNavBar(context, scaffoldState),
drawer: const Drawer(
child: DrawerWidget(),
),
body: body,
);
}
}
The problem with the above is, when the window is adjusted, the build function is called. When the build function is called for the scaffold, the scaffoldKey is being set. When set, it returns the scroll position back to 0, or the top of the screen.
In the end, I had to make another Controller that would basically hand over the same instance of a key to the scaffold, so it wouldn't be reset when the build function was called.
ScaffoldController
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ScaffoldControllerX extends GetxController {
static ScaffoldControllerX instance = Get.find();
final GlobalKey<ScaffoldState> scaffoldState = GlobalKey();
}
This changed my PreferredScaffold to the following
PreferredScaffold (version 2)
import 'package:flutter/material.dart';
import 'drawer/drawer_widget.dart';
import 'nav/my_navigation_bar.dart';
class PreferredScaffold extends StatelessWidget {
final Widget? body;
final Color? color;
PreferredScaffold({Key? key, this.body, this.color = Colors.white})
: super(key: key);
final ScaffoldControllerX scaffoldControllerX = ScaffoldControllerX();
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldControllerX.scaffoldState,
backgroundColor: color,
appBar: NavBar(context, scaffoldControllerX.scaffoldState),
drawer: const Drawer(
child: DrawerWidget(),
),
body: body,
);
}
}
I hope this helps if someone has a similar situation.

How to modify Scaffold widget for the whole app

I have a big app and there's multi files with same scaffold tap action to hide the keyboard.
Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Container(
///Textfields
),
),
),
);
Is there way to edit Scaffold widget for the whole app?
short answer, you can not customize your scaffold for the whole app because each scaffold has its own body, but you can customize the theme of the app such as the text colour or the font for the whole app on the main screen using the materialApp widget.
-If you are willing to make something fixed in the whole app like the same app bar or the navbar for the whole app that's possible and you have to create a separate screen for it.
-or if you are using a customized widget a lot, Flutter let you extract it, give it a name and use it again without rewriting the whole code again but by just writing the name you chose for it
In that case you can create your custom scaffold wrapper.
class ScaffoldWrapper extends StatelessWidget {
const ScaffoldWrapper({Key? key, required this.child}) : super(key: key);
final Widget child;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
child: child,
),
),
);
}
}
Now you can replace all occurrence of your mentioned code block with this..
ScaffoldWrapper(child: Container()); // your widget contents

Can I use a whole widget/screen as modal bottom sheet?

I have a login screen, which I want to be accessible at different points throughout the app. Can I use that screen as a modal bottom sheet like this?
example from airbnb
Yes you can, the below code snippet is used to show bottomsheet:-
bottomSheetForSignIn(BuildContext context)
{
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(25),topRight: Radius.circular(25)),
),
isScrollControlled: true,
context: context,
builder: (context){
return SignIn();
}
);
}
and then create a stateful widget signin returning a container with a property height(to control like in how much part of screen you want to show bottom sheet)
Code for it will look like:-
class SignIn extends StatefulWidget {
const SignIn({Key? key}) : super(key: key);
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height*0.9,//to control height of bottom sheet
child: Column( //your design from here onwards
children: [
],
),
);
}
}
And whenever you want to open bottom sheet just make a call to:-
bottomSheetForSignIn(context);

Floating Action Button pinned on every screen

How can i have floating action button pinned on every screen? When i change the screen float action button on home screen gets dissapear. Is there any way for it?
Thanks
honestly i am not sure this is best way or not but ...
you can Define a class like below and use it as parent of your widgets in every screen you want FAB,
class MyParent extends StatelessWidget {
final Widget child;
const MyParent({Key key, this.child}) : super(key: key);
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
child,
Positioned(
bottom: 0,
left: 0,
child: FloatingActionButton(
onPressed: (){},
),
)
],
);
}
}
Here you can define all the floastingAction buttons like this
floatingActionButton:myFloatingActionButton()
And then in a new page create a widget like this
FloatingActionButton myFloatingActionButton({here you can add variables if you want a bit different things on every page}){
return FloatingActionButton(
child:Icon(Icons.add),//You can make any child,
//Any customization like colors and all
onPressed:(){}
);
}

Flutter create infinite screen

I imagine a new kind of screen, and I would like to do it with Flutter since it's very powerful for rendering fast and smoothly.
I want to achieve a kind of infinite screen with kind of square or zone where you can move into. Actually exactly like a map (in fact not infinite but very large) but where I can:
Drag and translate
Zoom in and out
Click and press on the different component of the screen (square or whatever)
I imagine use GestureDetector on my widget "map" combine with transform on each component insde and refresh the screen after each move, or redrawing each component with draw but I'm not sure it's the best way to follow with this.
Thanks for helping if you have any idea !!
I've implemented part of things you asked for except for the "infinite map".
The code is quite beefy so I've described this stuff in an article on Medium.
It allows:
move map by dragging
place new objects on the map
zoom in/out
click objects
GitHub repo.
Interesting proposal. I don't have the implementation, after all, it's up to you but I have some pointers.
Translation, I imagine, can easily be handled by 2 nested ListViews. One, that scrolls X and one that scrolls in Y direction. ScrollController can be queries for all kinds of info.
Zoom is also fairly easy at first blick: you can wrap the entire screen in a Transform.scale() widget.
You could wrap each tappable widget in a GuestureDetector, query for their RenderBox to get their position on screen in local or global coordinates, get their size.
Note: in games, there is a concept called clipping distance. Figuring out how to implement that in Flutter is going to be a fun challenge. It allows you not to render those Widgets that are too small, you zoomed out a lot eg. Let me know how it goes! Curious.
The InteractiveViewer widget
One solution could be using the InteractiveViewer widget with its constrained property set to false as it will out of the box support:
Drag and translate
Zooming in and out - Simply set minScale and maxScale
Clicking and pressing widgets like normal
InteractiveViewer as featured on Flutter Widget of the Week: https://www.youtube.com/watch?v=zrn7V3bMJvg
Infinite size
Regarding the question's infinite size part, a maximum size for the child widget must be specified, however this can be very large, so large that it is actually hard to re-find widgets in the center of the screen.
Alignment of the child content
By default the child content will start from the top left, and panning will show content outside the screen. However, by providing a TransformationController the default position can be changed by providing a Matrix4 object in the constructor, f.ex. the content can be center aligned if desired this way.
Example code
The code contains an example widget that uses the InteractiveViewer to show an extremely large widget, the example centers the content.
class InteractiveViewerExample extends StatefulWidget {
const InteractiveViewerExample({
Key? key,
required this.viewerSize,
required this.screenHeight,
required this.screenWidth,
}) : super(key: key);
final double viewerSize;
final double screenHeight;
final double screenWidth;
#override
State<InteractiveViewerExample> createState() =>
_InteractiveViewerExampleState();
}
class _InteractiveViewerExampleState extends State<InteractiveViewerExample> {
late TransformationController controller;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: InteractiveViewer.builder(
boundaryMargin: const EdgeInsets.all(40.0),
minScale: 0.001,
maxScale: 50,
transformationController: controller,
builder: (BuildContext context, vector.Quad quad) {
return Center(
child: SizedBox(
width: widget.viewerSize,
height: widget.viewerSize,
child: const InteractiveViewerContent(),
),
);
},
),
),
);
}
#override
void initState() {
super.initState();
// Initiate the transformation controller with a centered position.
// If you want the InteractiveViewer TopLeft aligned remove the
// TransformationController code, as the default controller in
// InteractiveViewer does that.
controller = TransformationController(
Matrix4.translation(
vector.Vector3(
(-widget.viewerSize + widget.screenWidth) / 2,
(-widget.viewerSize + widget.screenHeight) / 2,
0,
),
),
);
}
}
// Example content; some centered and top left aligned widgets,
// and a gradient background.
class InteractiveViewerContent extends StatelessWidget {
const InteractiveViewerContent({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
TextStyle? style = Theme.of(context).textTheme.headline6;
return Container(
padding: const EdgeInsets.all(32.0),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[Colors.orange, Colors.red, Colors.yellowAccent],
),
),
child: Stack(
alignment: Alignment.center,
children: [
Align(
alignment: Alignment.topLeft,
child: SelectableText("Top Left", style: style),
),
SelectableText("Center", style: style),
],
),
);
}
}
Usage
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: InteractiveViewerScreen(),
);
}
}
class InteractiveViewerScreen extends StatelessWidget {
const InteractiveViewerScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: InteractiveViewerExample(
viewerSize: 50000,
screenHeight: MediaQuery.of(context).size.height,
screenWidth: MediaQuery.of(context).size.width,
),
),
);
}
}
What does the code do