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:(){}
);
}
Related
Say we have the following, simple CustomScrollView:
A SliverAppBar
Widget 1
Widget 2
Widget 3
The previous example must be able to meet the following requirements:
The SliverAppBar must have floating: true, so it appears when we scroll up again. Easy enough;
Widget 1 and Widget 2 should behave something like the SliverAppBar. Let me elaborate this:
These two widgets aren't an AppBar, which means that no drawer should be painted on them, no insets or anything else should be reserved. They're plain widgets, I want to use my own implementations there;
When I scroll down, I expect those two widget to just scroll and disappear... Again, easy enough;
When I scroll up again, though, these two widgets should appear one after the other on the screen like so: SliverAppBar -> Widget 1 -> Widget 2, without needing to scroll to the top, i.e. behave just like the SliverAppBar with the floating:true option, but they must respect the aforementioned scroll order.
Widget 1 and Widget 2 are hideable: see example below;
Widget 3 is just the actual content, and behaves like a normal scrollable widget.
Here's the code of what I have right now. I tried to implement Widget 1 and Widget 2 with different approaches:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var showGreen = false;
var showRed = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
drawer: const Drawer(),
body: Center(
child: CustomScrollView(
slivers: [
SliverAppBar(
title: const Text('My app bar'),
floating: true,
actions: [
IconButton(
icon: const Icon(Icons.grade_outlined),
tooltip: 'Add',
onPressed: () {
setState(() {
showGreen = !showGreen;
});
},
),
IconButton(
icon: const Icon(Icons.grade),
tooltip: 'Remove',
onPressed: () {
setState(() {
showRed = !showRed;
});
},
),
],
),
if (showGreen)
SliverAppBar(
toolbarHeight:
200, // I don't want hard-coded values in here!!
leadingWidth: 0,
titleSpacing: 0,
floating: true,
title: Container(
height: 200, // I don't want hard-coded values in here!!
color: Colors.green,
child: const Placeholder(),
),
),
SliverPersistentHeader(
floating: true,
delegate: MyDelegate(showRed),
),
SliverToBoxAdapter(
child: Container(
color: Colors.blue,
height: 2500,
child: const Placeholder(),
),
),
],
),
),
),
);
}
}
class MyDelegate extends SliverPersistentHeaderDelegate {
final bool showContents;
const MyDelegate(this.showContents) : super();
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return showContents
? Container(
color: Colors.red,
child: const Text(
"my contents",
style: TextStyle(fontSize: 36),
),
)
: const SizedBox.shrink();
}
#override
// But this is not what I want! I want the maxExtent to be as much as the build() method needs!
// I DO NOT want to hard code heights here!
double get maxExtent => 200;
#override
// For some reason... the content isn't disappearing right away and instead I get an overflow error?
double get minExtent => 0;
#override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}
Here's what I tried so far, with no luck:
I tried to implement Widget 1 and Widget 2 as two SliverAppBars, but:
Removing the Drawer is hacky (see example: you have to force the title to expand): is it actually there and just not shown, or did the framework remove that button entirely?
I want to leave these Widgets' height unbounded (no, I don't want anything fixed, I need their height to fit the content in a Flexible way); inserting anything besides a Placeholder breaks the AppBar as I'm not able to tell how much is needed in my contents beforehand!
This still feels like a hacky solution. I don't want to have three SliverAppBars semantically speaking (!)
This seems to be the "as-close-as-I-can-get" behavior, tho
I tried SliverLists, SliverGrids... the behavior is impossible to reproduce with the "out-of-the-box" Widgets;
I tried using a SliverPersistentHeader and its SliverPersistentHeaderDelegate, but I had no luck. I can't seem to understand how to consistently reproduce what I want with the maxExtent and minExtent parameters: I couldn't care less for fixed values (and as you see in the example, it just won't work well). Also, the floating behavior is just not there.
I am so lost with this one. Is anyone able to answer this?
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
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: ...........
...........
),
),
I'm trying to create a master-detail type container starting with a column of ListTiles on the left side of the screen. When a user taps on an item, a preset URL will then be displayed on the rest of the screen. Tapping a different item displays a different preset URL.
I've looked at the Flutter WebView Plugin and and webview_flutter packages, but either I don't understand them well enough (quite possible!) or they can't yet do everything I want them to to do.
Beside what I just mentioned, if possible I'd also like the web pages to open zoomed to fit the space they're in, but still be pinchable to other sizes.
p.s. I'm new to Flutter and am also confused about widget construction and memory management. If I try using something like a WebView widget, I don't know whether I just code a WebView widget every time I want to open a page, or if I somehow create a single WebView widget, add a controller, and code .loadFromUrl() methods.
You can create a Row with two children. First children will be ListView that will be consisted of ListTiles. Second children will be the WebView. When a user taps on the list tile, load the url with the controller. There is no need to rebuild the WebView every time in your case
Example by using webview_flutter:
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WebViewController _controller;
List pages = ["https://google.com", "https://apple.com"];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
Container(
width: 300,
child: ListView.builder(
itemCount: pages.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(pages[index]),
onTap: () {
if (_controller != null) {
_controller.loadUrl(pages[index]);
}
},
);
},
),
),
Expanded(
child: WebView(
onWebViewCreated: (WebViewController c) {
_controller = c;
},
initialUrl: 'https://stackoverflow.com',
),
),
],
));
}
}
Just wrap the webview inside a SizedBox
SizedBox(
height: 300,
child: WebView()
)
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