is there anyway that we can bring the widget front of the screen and let other widget behind the screen?, tried Stack widget but not working, I'm implementing a Google Maps using flutter google_maps_flutter library, see code below:
import 'dart:ui' as ui;
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter/material.dart';
final size = MediaQueryData.fromWindow(ui.window).size;
final GoogleMapOverlayController controller =
GoogleMapOverlayController.fromSize(
width: size.width,
height: size.height,
);
class GoogleMapView extends StatefulWidget {
_GoogleMapViewState createState() => _GoogleMapViewState();
}
class _GoogleMapViewState extends State<GoogleMapView> {
final mapController = controller.mapController;
final Widget mapWidget = GoogleMapOverlay(controller: controller);
#override
void initState() {
super.initState();
GoogleMapController.init();
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Container(
alignment: Alignment.center,
height: size.height,
width: size.width,
child: new Stack(
children: <Widget>[
mapWidget,
new Container(
height: 100.0,
alignment: Alignment.topCenter,
child: new Text('Hey there!'),
)
],
),
),
navigatorObservers: <NavigatorObserver>[controller.overlayController],
);
}
}
See the screenshot which it should have a red color on top of the google map aligned in the top corner of the screen. How to implement this using flutter Stack widget, I'm having problem with this since yesterday and couldn't find any solution, can anyone help me with this? thanks!
Stack works fine for that purpose, it's just that the Google Maps plugin is rendering a native view that can't yet be overlayed by something else.
You might want to follow https://github.com/flutter/flutter/issues/73
See especially this comment https://github.com/flutter/flutter/issues/73#issuecomment-417040742
Related
I am using an HtmlElementView in my flutter web project for showing a web image/pdf etc.
I am not able to figure out a way to align the element within the frame. As shown by the below sample code example, if the image size is smaller than parent widget size, it is shown in top left alignment. I have a feeling this has to do with some iframe style setting but not able to figure out.
import 'dart:html';
import 'dart:ui' as ui;
import 'package:flutter/cupertino.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
theme: ThemeData.dark(),
home: Home(),
);
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Material App Bar'),
),
body: InteractiveViewer(
child: Container(
alignment: Alignment.center,
width: 3000,
height: 3000,
child: EmbedWebView(
src:
'https://picsum.photos/id/1/200/300', //'https://www.youtube.com/embed/3fB1mxOsqJE',
width: 500,
height: 550))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {},
),
);
}
}
class EmbedWebView extends StatefulWidget {
final Key? key;
final String src;
final double height, width;
EmbedWebView(
{this.key, required this.src, required this.height, required this.width});
#override
State<StatefulWidget> createState() {
return EmbedWebViewState();
}
}
class EmbedWebViewState extends State<EmbedWebView>
with AutomaticKeepAliveClientMixin {
#override
void initState() {
super.initState();
final IFrameElement _iframeElement = IFrameElement()
..height = '100%'
..width = '100%'
..src = widget.src
..style.border = 'none'
..style.overflow = "hidden"
..allow = "autoplay"
..allowFullscreen = true;
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
widget.src,
(int viewId) => _iframeElement,
);
}
#override
void dispose() {
super.dispose();
}
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Center(
child: Container(
color: Colors.white,
width: widget.width,
height: widget.height,
child: HtmlElementView(
// key: UniqueKey(),
viewType: widget.src,
),
),
);
}
}
When the above code is run using flutter run -d chrome, this is what I get. It can be seen that the image in not centred.
sample code output
Try wrapping the EmvedWebView with an Expanded. Probably the EmvedWebView is not occupying the whole Container, implying that even if the Container is centered his child is not
I have a basic stateful app, with a GoogleMap base, which opens a BottomSheet on FloatingActionButton press. This is used as a settings tab to change/filter some lists which are then used by the map. My Provider is setup and values can be read/saved from both the GoogleMap dart file, and the BottomSheet dart file.
My main problem is how to provide context to the Provider.of() when not in the Widget Tree. For example, the GoogleMap runs onMapCreated: _onMapCreated, when finished loading. From within that function I want to pull a value from the Provider.of() a String, which tells me which list to use (which then populates the markers).
Things I'm trying to do:
onMapCreated() pull value from the Provider (which is later used in a DB sqflite query)
The bottomsheet needs to callback and updateMarkers() somehow, providing correct context
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
GoogleMapController mapController;
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
print(Provider.of<MyAppStateContainer>(context, listen:false).getSomeValue); <---- Doesn't work
...
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<MyAppStateContainer>(
create: (contextooo) => MyAppStateContainer(),
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My Map'),
backgroundColor: Colors.green[700],
),
//Put in a stack widget so can layer other widgets on top of map widget
body: Stack(
children: <Widget>[
//Builder so we can get a CTX made, and then Provider.of() finds the Provider
Builder(
builder: (context) => GoogleMap(
mapType: Provider.of<MyAppStateContainer>(context).getMapType, <--- Works fine
markers: _markers,
onMapCreated: _onMapCreated,
...
}
Provider:
class MyAppStateContainer extends ChangeNotifier {
MyAppStateContainer();
MapType _mapType = MapType.terrain;
String _someValue;
MapType get getMapType => _mapType;
String get getSomeValue => _someValue;
}
I've tried all sorts of combinations of passing back BuildContext context but sadly I'm forever getting this error about the Widget Tree:
Unhandled Exception: Error: Could not find the correct Provider<MyAppStateContainer> above this MyApp Widget
The problem is that within _onMapCreated, you are trying to access the Provider using the context of MyApp, which is higher up the hierarchy of widgets than the Provider itself.
Convert your home widget (the Scaffold and everything below it) into a separate StatefulWidget and everything should start working, as you'll be using the context of the new widget, which is lower down the hierarchy of widgets than the Provider.
the flutter_html package is supposed to enable displaying html elements properly. But when I try to render a simple example, (or the example provided on github) the sub and sup elements aren't displayed.
(Not just shown incorrectly but rather not displayed at all). Neither does
Android Studio throw any warning/error
I'm running the latest version of Android Studio on Ubuntu 18.4.
The problem appears when installing the example app and an emulated Pixel 2 with Android 9.0, as well as on an Samsung Galaxy A5 (2017).
I opened an issue in the flutter_html github repo, but after asking for additional information the author remained silent.
the main.dart file in the flutter project looks like:
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: SingleChildScrollView(
child: Html(
data: """
<body>
<div>x<sup>2</sup></div>
</body>
""",
),
),
),
);
}
}
and in the pubspec.yaml I wrote:
flutter_html: ^0.10.4
the main.dart results in:
x
instead of:
x^2
Because the "HtmlRichTextParser" doesn't seems to support "<sup>" and "<sub>", but is enabled by default. By setting
Html(
useRichText = false,
...
in the c'tor of the Html widget, the example is displayed correctly.
I am using Google Maps for Flutter widget.
In my app map is displayed via one of the tabs of BottomNavigationBar.
And I have the following problem:
user is on Map's tab
user changes tab (by tapping on another one)
[PROBLEM] when user returns on Map's tab map redraws.
I would like to keep map as it is when user leaves Map's tab, so he can continue to work with it when he returns to it later on.
Tried to:
use PageStorage - without success.
make something like Singletone of Map's state - without success.
use AutomaticKeepAliveClientMixin (saw here), which looked promising, but still without success.
(I admit that I could have done something wrong)
Code of last attempt:
class MapScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => MapScreenState();
}
class MapScreenState extends State<MapScreen> with AutomaticKeepAliveClientMixin {
GoogleMapController mapController;
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
appBar: AppBar(
title: const Text("Map"),
),
body: GoogleMap(
onMapCreated: _onMapCreated,
)
);
}
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
updateKeepAlive();
}
}
So, I just need a way to either keep MapScreen alive and unchanged, or to store its state somehow and restore it when user returns to MapScreen. Or something else which will solve the problem.
Use IndexedStack
For example:
Class _ExamplePageState extends State<ExamplePage> {
int _bottomNavIndex = 0;
final List<Widget> _children = [
WidgetOne(),
WidgetTwo(),
GoogleMap(),
]
#override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _bottomNavIndex,
children: _children,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _bottomNavIndex,
onTap: (index) {
if (_bottomNavIndex == index) return;
setState(() {
_bottomNavIndex = index;
});
}
items: [ ... ]
),
);
}
}
Widget always rebuild after you change from page to page, so, try this , use a variable for GoogleMap and reuse if it's different from null.
GoogleMap _map;
#override
Widget build(BuildContext context) {
if (_map == null){
_map = GoogleMap(
onMapCreated: _onMapCreated,
);
}
return Scaffold(
appBar: AppBar(
title: const Text("Map"),
),
body:_map,
);
}
I was just having this same problem and the mixin solved it. I think you've just missed enter the type of mixin at the end of its declaration.
class MapScreenState extends State<MapScreen> with AutomaticKeepAliveClientMixin<MapScreenState>
see this thread if anything.
AutomaticKeepAliveClientMixin
To
AutomaticKeepAliveClientMixin<MapScreenState>
I'm trying to do what I think is a very simple Flutter app, but I can't figure out what's going wrong with my code.
I have a Flutter app with a Drawer widget. I'm using this widget to make a Navigation drawer, the Drawer has a ListView as a child and the ListView contains the View options (A, B and C) which the user can select.
Since the main page of the app (MyHomePage) extends from StatefulWidget the only thing that I do to load a new view is to call the setState method to assign the new value of my "control variable" (viewName), then I expect that Flutter executes the Widget build(BuildContext context) method of MyHomePage but with the new value of viewName this time.
All of the above works as expected, the problem with this is that in the body field of the Scaffold I have a TabBarView widget, since I want to show to the user a view with two tabs (Tab 1 and Tab 2) per each view (A, B and C).
The TabBarView children are:
-A StatefulTab object for Tab 1
-A simple Center widget for Tab 2
What I want to demonstrate here is that when you tap an option of the Drawer (Load the B view for example) the Tab 2 changes as a expected it's value, but the Tab 1 (that contains a stateful widget) not changes it's value when you tap any other option of the Drawer
Note: I must use the same StatefulTab widget for the 3 views in order to reuse the code, since the only value which changes for the 3 views is the viewName variable.
Here is the code:
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/StatefulTab.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(viewName: 'A'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.viewName}) : super(key: key);
final String viewName;
#override
_MyHomePageState createState() => new _MyHomePageState(viewName: viewName);
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
String viewName;
_MyHomePageState({Key key, this.viewName});
TabController controller;
#override
void initState() {
super.initState();
controller = new TabController(
length: 2,
vsync: this,
);
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var tabs = <Tab>[
new Tab(icon: new Icon(Icons.home), text: 'Tab 1'),
new Tab(icon: new Icon(Icons.account_box), text: 'Tab 2')
];
return new Scaffold(
appBar: new AppBar(
title: new Text(viewName),
),
body: new TabBarView(controller: controller, children: <Widget>[
new StatefulTab(viewName: viewName),
new Center(child: new Text('This is the Tab 2 for view $viewName'))
]),
bottomNavigationBar: new Material(
color: Colors.blue,
child: new TabBar(controller: controller, tabs: tabs),
),
drawer: new Drawer(
child: new ListView(
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(top: 50.0),
),
new ClipRect(
child: new Column(
children: <Widget>[
new ListTile(
title: new Text('Tap to load view: A'),
onTap: () => _loadView('A', context),
),
new ListTile(
title: new Text('Tap to load view: B'),
onTap: () => _loadView('B', context),
),
new ListTile(
title: new Text('Tap to load view: C'),
onTap: () => _loadView('C', context),
),
],
),
),
],
),
),
);
}
_loadView(String view, BuildContext context) {
Navigator.of(context).pop();
setState(() {
if (view == 'A') {
viewName = 'A';
} else if (view == 'B') {
viewName = 'B';
} else if (view == 'C') {
viewName = 'C';
}
});
}
}
StatefulTab.dart
import 'package:flutter/material.dart';
class StatefulTab extends StatefulWidget {
String viewName;
StatefulTab({Key key, this.viewName}) : super(key: key);
#override
StatefulTabState createState() => new StatefulTabState(viewName: viewName);
}
class StatefulTabState extends State<StatefulTab> {
String viewName;
StatefulTabState({Key key, this.viewName});
#override
Widget build(BuildContext context) {
return new Center(
child: new Text('This is the Tab 1 for View $viewName'),
);
}
}
How can I tell Flutter that takes the new value for the stateful wdiget of the Tab 1?
Is there a better way to implement a Navigation drawer with dynamic views?
Thanks in advance!
I think I found your problem. You keep the viewName as State in your Homepage and additionally in the StatefulTab. This can't really work, because for the StatefulTab the state doesn't change only because the state of the HomePage changes. I came to that conclusion by inserting print statements in the two build methods. The build method of the HomePage acts according to your desired behavior (as you already saw in the header of the scaffold), but the build method of the StatefulTab kept its state.
Further investigating and various print statements in various places led me to the conclusion, that the constructor of the StatefulTabState is not called after one of the drawer buttons is clicked. Here is a working example of your StatefulTab:
class StatefulTab extends StatefulWidget {
String viewName;
StatefulTab({Key key, this.viewName}) : super(key: key);
#override
StatefulTabState createState() => new StatefulTabState();
}
class StatefulTabState extends State<StatefulTab> {
#override
Widget build(BuildContext context) {
return new Center(
child: new Text('This is the Tab 1 for View ${widget.viewName}'),
);
}
}
Don't hesitate to comment, if you have any questions. It may be beneficial for you to have a look at this tutorial/documentation.
For implement TabBar and drawer flutter provide us following widget.
1. TabController
2. TabBar
3. Drawer
I found a simple demo of TabBar and drawer.