GoogleMap in PageView - flutter

I have a googlemap located on containers in a pageview... When u swipe between the pages that contain these googlemap widgets, the pagesnapping breaks... so inside my code when I do
class Homepage extends StatelessWidget {
#override build(BuildContext context){
return PageView(
children: <Widget>[
Container(color:Colors.red),
Container(color:Colors.green),
Container(color:Colors.blue),
Container(color:Colors.yellow),
Container(color:Colors.pink),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),))
],
);
}
This, it works fine and all the pages snap perfectly.. However when I uncomment the GoogleMap widgets like so:
class Homepage extends StatelessWidget {
#override build(BuildContext context){
return PageView(
children: <Widget>[
// Container(color:Colors.red),
// Container(color:Colors.green),
// Container(color:Colors.blue),
// Container(color:Colors.yellow),
// Container(color:Colors.pink),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),))
],
);
}
}
The PageView works for a while but breaks (on IOS) and this error is (sometimes) shown in the console:
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: 'package:flutter/src/gestures/converter.dart': Failed assertion: line 155 pos 18: '!state.down': is not true.
#0 _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:40:39)
#1 _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:36:5)
#2 PointerEventConverter.expand (package:flutter/src/gestures/converter.dart:155:18)
#3 _SyncIterator.moveNext (dart:core/runtime/libcore_patch.dart:152:12)
#4 ListQueue.addAll (dart:collection/queue.dart:715:25)
#5 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:83:27)
#6 _rootRunUnary (dart:async/zone.dart:1136:13)
#7 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
#8 _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
#9 _invoke1 (dart:ui/hooks.dart:223:10)
#10 _dispatchPointerDataPacket (dart:ui/hooks.dart:144:5
Anyone seen and fixed this?
Thanks for your attention..
John.

I had a similar issue working with google map in pageview but after searching online I got a solution that finally worked
All I did was put the google map in a stateful widget, used the with AutomaticKeepAliveClientMixin and #override bool get wantKeepAlive => true; and called in the required widget
This is the stateful widget containing the google map
class GoogleMapWidget extends StatefulWidget{
const GoogleMapWidget({Key? key}) : super(key: key);
#override
_GoogleMapWidgetState createState() => _GoogleMapWidgetState();
}
class _GoogleMapWidgetState extends State<GoogleMapWidget> with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
return Container(
child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)
);
}
}
Then you can call it from your Homepage like so
class Homepage extends StatelessWidget {
#override
build(BuildContext context){
return PageView(
children: <Widget>[
GoogleMapWidget(),
GoogleMapWidget(),
],
);
}
}
I hope this is the answer you're looking for

don't use Pageview instead use PageView.builder and then create a global list
List latLong = [
// pass all google maps and latLong values here
];
then on itemBuilder pass the latlong according to index and don't forget to turn gestureDetector on your googleMaps else it'll also scroll the map

Related

how to obtain RenderObject of lowest level widget?(RenderObject for SelectableText)

I want to obtain RenderObject of SelectableText because I want obtain RenderBox of the text, which, to my understanding, is obtainable via RenderObject.
So, I try to use GlobalKey to access the RenderObject by using this GlobalKey().currentContext?.findRenderObject()
But what I got is not what I want...
This is the demo program:
class Demo extends StatefulWidget {
const Demo({Key? key}) : super(key: key);
#override
State<Demo> createState() => _DemoState();
}
class _DemoState extends State<Demo> {
final _selectableTextKey = GlobalKey();
#override
Widget build(BuildContext context) {
return SelectableText(
'This is a test',
key: _selectableTextKey,
onTap: () {
print(
'render object == ${_selectableTextKey.currentContext?.findRenderObject()}');
},
);
}
}
This is the output in the console:
flutter: render object == RenderSemanticsAnnotations#52070 relayoutBoundary=up4
As illustrated in the screenshot of the DetailTree
I want the RenderObject of green arrow's, but I got red arrow's instead.
Using GlobalKey to obtain RenderObject then to access the RenderBox is all I know so far, so I don't have other idea to try...

CallBacks error : The method 'call' was called on null

I am currently working on this tutorial in which transfers a variable to an external file to another (with a callback)
but i have this error :
======== Exception caught by gesture ===============================================================
The following NoSuchMethodError was thrown while handling a gesture:
The method 'call' was called on null.
Receiver: null
Tried calling: call(3)
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 Son.build.<anonymous closure> (package:montest/son.dart:24:21)
#2 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
#3 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:607:11)
#4 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:296:5)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#cf4d9
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(178.3, 84.9)
button: 1
sent tap down
====================================================================================================
son.dart
///
/// Inside the Child Widget
///
import 'package:flutter/material.dart';
// Step 1: Define a Callback.
typedef void IntCallback(int id);
class Son extends StatelessWidget {
// Step 2: Configre the child to expect a callback in the constructor(next 2 lines):
final IntCallback onSonChanged;
Son({ #required this.onSonChanged });
int elementId = 3;
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
// Step 3: On specific action(e.g onPressed/
// onTap/onLoad.. onWhatEver) trigger the callback
// with the data you want to pass to the parent.
// Data will be passed as parameter(see elementId):
onSonChanged(elementId);
// Done in the child.
},
child: Text('Click me to call the callback!'),
);
}
}
///
///////////////
parent.dart
import 'son.dart';
///
/// Inside the Parent Widget
///
import 'package:flutter/material.dart';
class Father extends StatefulWidget {
#override
_FatherState createState() => _FatherState();
}
class _FatherState extends State<Father> {
// Step 1 (optional): Define a Global variable
// to store the data comming back from the child.
int id;
// Step 2: Define a function with the same signature
// as the callback, so the callback will point to it,
// this new function will get the data from the child,
// set it to the global variable (from step 1)
// in the parent, and then update the UI by setState((){});
void updateId(int newId) {
setState(() {
id = newId;
});
}
#override
Widget build(BuildContext context) {
return Container(
// Step 3: Construct a child widget and pass the
child: Son(
// Many options to make onSonChanged points to
// an executable code(function) within memory
// called 'updateId':
//
// 1st option:
onSonChanged: (int newId) {
updateId(newId);
},
// 2nd option: onSonChanged: updateId,
// 3rd option: onSonChanged: (int newId) => updateId(newId)
// So each time the 'onSonChanged' called by the action
// we defined inside the child, a new data will be
// passed to this parent.
)
);
}
}
Thanks for your help
make id nullable and check it.
try this
import 'package:flutter/material.dart';
typedef void IntCallback(int id);
class Son extends StatelessWidget {
final IntCallback onSonChanged;
Son({required this.onSonChanged});
int elementId = 3;
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
onSonChanged(elementId);
},
child: Text('Click me to call the callback!'),
);
}
}
class Father extends StatefulWidget {
#override
_FatherState createState() => _FatherState();
}
class _FatherState extends State<Father> {
int? id;
void updateId(int newId) {
setState(() {
id = newId;
});
}
#override
Widget build(BuildContext context) {
return Column(
children: [
id == null ? Text(" son value: null") : Text("son value: $id"),
Container(
child: Son(
onSonChanged: (int newId) {
updateId(newId);
},
),
),
],
);
}
}

Screen's build method triggered when I use the navigator with rootNavigator

There is an interesting problem. I'm using Flutter 2.0 in my app. It has a bottom navigation bar. When I push to the new screen using "Navigator.of(context, rootNavigator: true)" along with the new screen, the screen that provides navigation is also rebuilding.
CategoriesView build() method
#override
Widget build(BuildContext context) {
print("Building: CategoryView");
return mobileBody;
}
ProductDetailView build() method
#override
Widget build(BuildContext context) {
print("Building: ProductDetailView");
return mobileBody;
}
When i use the "context.rootNavigator.pushNamed(ProductDetailView.route);" in CategoryView output is:
I/flutter (21910): Building: ProductDetailView
I/flutter (21910): Building: CategoryView
Without rootNavigator output is (context.navigator.pushNamed(ProductDetailView.route);):
I/flutter (21910): Building: ProductDetailView
Navigator extensions:
extension NavigationExtension on BuildContext {
NavigatorState get rootNavigator => Navigator.of(this, rootNavigator: true);
NavigatorState get navigator => Navigator.of(this);
}
Why is this happening? How can I prevent this?
I have met the same issue too, currently use a StatefulWidget wrapper for it.
class WrapperStateless extends StatefulWidget {
const WrapperStateless({Key key}) : super(key: key);
#override
_WrapperStatelessState createState() => _WrapperStatelessState();
}
class _WrapperStatelessState extends State<WrapperStateless> {
TabA tabA;
#override
void initState() {
super.initState();
tabA = TabA();
}
#override
Widget build(BuildContext context) {
// return tabA;
return tabA;
}
#override
void didUpdateWidget(WrapperStateless oldWidget) {
super.didUpdateWidget(oldWidget);
// setState(() {});
}
}

Double nested UI layout causing StackOverflow on null call()

My app uses a hierachy of UI designs and extended designs for the correct layout (naturally).
One of my hierachies is a simple 3 layer approach:
HomePage (content) ->
UiBaseMain (structure for content) ->
UiBase (scaffolding)
Details: (and an MVCE) - I have tried narrowing down to the simplest form to get repeatedly throw this error.
Tested on both physical devices and AVD, both give a Stack Overflow error.
UiBase (ui_component_base.dart) (which all layouts are based on)
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class UiBase extends StatelessWidget {
final Widget widget;
const UiBase({Key key, this.widget})
: super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
width: double.infinity,
child: widget),
);
}
}
UiBaseMain (ui_main_navbar_appbar.dart) (where all Main UI content is shown with i.e. Dashboard, settings, etc which ideally alsop contains a small logo ontop, a BottomNavigationBar, etc)
import 'package:mytestapp/ui/design/ui_component_base.dart';
import 'package:flutter/widgets.dart';
class UiBaseMain extends StatefulWidget {
final Widget widget;
const UiBaseMain({Key key, this.widget}) : super(key: key);
#override
_UiBaseMain createState() => _UiBaseMain();
}
class _UiBaseMain extends State<UiBaseMain> {
#override
Widget build(BuildContext context) {
return UiBase(
widget: widget,
);
}
}
Finally, HomePage (ui_homepage.dart) (which is a content page, should show user content, etc)
import 'package:mytestapp/ui/design/ui_main_navbar_appbar.dart';
import 'package:flutter/widgets.dart';
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
#override
_HomePage createState() => _HomePage();
}
class _HomePage extends State<HomePage> {
#override
Widget build(BuildContext context) {
return UiBaseMain(
widget: Text("test"),
);
}
}
Problem
Using the above structure, I consistently get the following Stack Overflow error
======== Exception caught by widgets library =======================================================
The following StackOverflowError was thrown building Material(type: canvas, color: Color(0xfffafafa), dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#1c4c4], _EffectiveTickerMode], state: _MaterialState#b2ccd):
Stack Overflow
The relevant error-causing widget was:
Scaffold file:///C:/Users/CybeX/mytestapp/mytestapp-mobile-flutter/lib/ui/design/ui_component_base.dart:14:12
When the exception was thrown, this was the stack:
#0 _WordWrapParseMode.values (package:flutter/src/foundation/diagnostics.dart:776:6)
#1 _SyncIterator.moveNext (dart:core-patch/core_patch.dart:165:25)
#2 Iterable.length (dart:core/iterable.dart:429:15)
#3 _PrefixedStringBuilder._finalizeLine (package:flutter/src/foundation/diagnostics.dart:856:30)
#4 _PrefixedStringBuilder.write (package:flutter/src/foundation/diagnostics.dart:973:9)
...
====================================================================================================
======== Exception caught by widgets library =======================================================
The method 'call' was called on null.
Receiver: null
Tried calling: call()
The relevant error-causing widget was:
Scaffold file:///C:/Users/CybeX/mytestapp/mytestapp-mobile-flutter/lib/ui/design/ui_component_base.dart:14:12
====================================================================================================
======== Exception caught by widgets library =======================================================
The method 'call' was called on null.
Receiver: null
Tried calling: call()
The relevant error-causing widget was:
Scaffold file:///C:/Users/CybeX/mytestapp/mytestapp-mobile-flutter/lib/ui/design/ui_component_base.dart:14:12
====================================================================================================
Question
Is this an issue my side or is this an issue others can confirm and infact a bug in the Flutter framework?
You have to pass here widget.widget because it is a stateful widget, no? : return UiBase(
widget: widget,
);
Sorry not convenient to write from phone.

Flutter: Provider shows Exception but app run fine while using default listen:true

I'm Using provider in initState() to call the api but if I use listen:false then it does not update UI and it always shows me loader but if I use listen:true then app works fine but in the terminal it shows me exception and tells me write listen:false.
My UI,
class ChopperNewsCard extends StatefulWidget {
#override
_ChopperNewsCardState createState() => _ChopperNewsCardState();
}
class _ChopperNewsCardState extends State<ChopperNewsCard> {
ScrollController scrollController = ScrollController();
int currentPage = 5;
ChopperApiStore _apiStore = ChopperApiStore();
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_apiStore = Provider.of<ChopperApiStore>(context,);//<--- here it tells me to write listen:false
});
_apiStore.getResponse(currentPage);
scrollController.addListener(() {
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
if (currentPage < 20) {
currentPage = currentPage + 5;
_apiStore.getResponse(currentPage);
}
}
});
}
#override
void dispose() {
scrollController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Observer(builder: (context) {
return Container(
height: height * 0.37,
width: double.infinity,
child: _apiStore.res.articles == null
? CircularProgressIndicator()
: ListView.builder(...),
);
});
}
}
api calling class,
class ChopperApiStore extends _ChopperApiStore with _$ChopperApiStore{}
abstract class _ChopperApiStore with Store{
ApiCall apiCall = ApiCall();
#observable
ChopperNews res = ChopperNews();
#action
Future<void> getResponse(int page) async {
var data = await apiCall.getNews(page);
res = data;
}
}
the error I'm getting,
======== Exception caught by scheduler library =====================================================
The following assertion was thrown during a scheduler callback:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
To fix, write:
Provider.of<ChopperApiStore>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: ChopperNewsCard(dependencies: [MediaQuery], state: _ChopperNewsCardState#8f6cd)
'package:provider/src/provider.dart':
Failed assertion: line 262 pos 7: 'context.owner.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate'
When the exception was thrown, this was the stack:
#2 Provider.of (package:provider/src/provider.dart:262:7)
#3 _ChopperNewsCardState.initState.<anonymous closure> (package:fruitley/week-5/bonus/chopper/widgets/chopper_news_card.dart:32:28)
#4 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
#5 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1063:9)
#6 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:971:5)
...
I think if you want to use listen:true to have the build method called you are suppose to override didChangeDependencies rather then initState Checkout this article it might help https://medium.com/swlh/flutter-provider-and-didchangedependencies-15678f502262
ok I'm dumb. I didn't even need to use addPostFrameCallback.
I just removed it and if I want to use provider outside of widget tree that I must use listen:false as it was showing in the exception so now everything makes sense.