Basic App to reproduce the error has two widget
Home Widget contains a gesture detector triggering the following function:
GlobalKey<MainMapState> mapKey = GlobalKey<MainMapState>();
void getCurrentLocation() async{ // I am using async property for something different but it not our concern right now
mapKey.currentState.asdd();
}
MainMap is a stateful widget and it's state contains the following function:
void asdd(){
print("triggered");
}
As a result I am getting this
Note: I am using GlobalKey to animate CameraPosition to my current location on GoogleMap widget which is inside the MainMapState
I'm sorry I don't have enough reputation points to merely comment on your post.
Based on the error you are receiving I suspect you have the same issue to which I have yet to find a correct answer. A couple of alternate approaches are listed on my same question as noted at link:
How to smoothly update a Flutter AnimatedList without using a GlobalKey.currentState?
Related
I know the code is literally in the devtools repository regarding the solution but as an learning flutter developer the code is very hard to understand and also there is no article or videos on how to create own inspectable or devtools like features.
What I am trying to do now is find the underlying Widget lets say ElevatedButton depending on the user's tap.
Below is the image i am trying to replicate.
I am able to get the specific coordinates and its renderObject but am not sure where to look for next.
final box = context.findRenderObject() as RenderBox;
final local = (context.findRenderObject() as RenderBox)
.globalToLocal(details.globalPosition);
final hitTestResult = BoxHitTestResult();
(context.findRenderObject() as RenderBox).hitTest(
hitTestResult,
position: local,
);
BoxHitTestEntry entry = hitTestResult.path
.firstWhere((element) => element is BoxHitTestEntry) as BoxHitTestEntry;
This code was working just fine a while ago, but is now misbehaving for no reasons, I tried to re-install the app 2 times, but didn't worked, what might be causing it? It was giving me a list of available cameras before, but after a hot-restart, the code is constantly breaking.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras(); // returns an empty list, which it shouldn't because I'm using a real device which has two physical cameras, all dependencies are added, all permissions are allowed.
runApp(
MyApp(),
);
}
Note: The error is coming when I try to access the cameras list, but it was able to access it two hours ago, why is it returning an empty list right now?
For all of you that may have done the same error as me by copy-pasting "camera" code from pubdev,
keep in mind that the code of "camera" was made for being main page, wich means _cameras is initialised by :
List<CameraDescription> _cameras = <CameraDescription>[];
but it's the main() function role to fill it, so if you call CameraApp() from outside of the page, main will not be triggered, therefore you need to modify the class like this:
class CameraApp extends StatelessWidget {
/// Default Constructor
const CameraApp({Key? key, required this.cameras}) : super(key: key);
final List<CameraDescription> cameras;
#override
Widget build(BuildContext context) {
_cameras=cameras;
return const MaterialApp(
home: CameraExampleHome(),
);
}
}
and call it from another page with:
await availableCameras().then((value) => Navigator.push(context,
MaterialPageRoute(builder: (_) => CameraApp(cameras: value))));
Like so the cameras are properly filled. That's my working solution.
Possible amelioration: Maybe the cameras list could be filled directly in CameraApp?
This error is most probably due to the "camera" plugin's internal working or due to Android OS's security reasons or something like that. The camera package is new, so you can expect such behaviors, but there are bunch of other enhanced packages as well based on the original one.
In my case, I used "flutter_camera" and modified the source code as per my needs in order to achieve the desired UI, and it works pretty good.
Update: I found out that the error was indirectly connected to "compileSdkVersion" in my app/build.gradle being set to 33 which was required by a random flutter plugin, setting it to 29 allowed me to access my camera and successfully executed availableCameras() method too but then the plugin can't be used.
I am trying to fix an issue that occurred when using the Dismissible widget and the Provider package.
When I dismissed a card this is called :
Provider.of<NMyProvider>(context, listen: false).toggleIsDone(object.id);
The provider :
Future<void> deleteNotebook(int id) async {
...
final notebookId = _items.indexWhere((notebook) => notebook.id == id);
...
_items.removeAt(notebookId);
notifyListeners();
}
This makes the animation clunky with noticeable lag but does not occur when removing the NotifyListeners.
Most probably the entire screen is being rebuilt upon notification from the provider. There are some solutions for that:
Move the Consumer<NMyProvider>/context.watch<NMyProvider>(context)/Provider.of<NMyProvider>(context, listen: true) closer to its usage. Flutter only rebuilds the widgets that use the same context;
Use a unique key for every notebook. Not the index position, but a unique key like the notebookId. Flutter will re-use the already built notebook widget where the key is the same in between builds;
Split the NMyProvider: Move everything that doesn't make sense to this provider into other providers. If a lot of unrelated states are together the chance of this provider being used by the root widget gets higher. NMyProvider should deal only with the list of notebooks state;
I used the BLOC architecture inside my app. One method inside my bloc resolves a picked address-ID from a listView and return the city name. After this I want my Text-Editing-Controller to have this picked value and show it on the texteditingfield:
The BlocA uses a simple ID and look it up using Google-Places API. BlocA then return a new state with the resolved address as a state property. Running the code below did not show the correct city after tapping on a listView-item.
Await do not work unfortunately.
// ListView.builder code
onTap: () {
context
.read<BlocA>()
.add(PickAddress(id: state.searchResults[index].placeId));
FocusScope.of(context).unfocus(); //hide Keyboard
_textController.value = TextEditingValue(text: state.address.city);
the code its not clear enough
remember to use "await" you have to set Async on onTap like this
onTap: () async { ....
if you did that and still not working send the whole code
Do you know what your Bloc actually returns? Use the debugger and step through your code to see what actually happens in your code.
When it comes to using Bloc's to build your state you usually don't access the state with by calling .state.
The line _textController.value = TextEditingValue(text: state.address.city); is not the way you access your state. When the Bloc sends the new state, the widget will rebuild and render based on the new state.
Sometimes an event (eg upload) starts async while the user is on one page. If they navigate away from that page the task's .then(...) will try to display the result on the page which is no longer visible, eg by means of a toast.
How can I get the context of the currently visible page at the time when the Future completes to display a snackbar, toast or dialog?
EDIT:
I see in the description of oktoast (https://pub.dev/packages/oktoast) that version 2 "Does not need the buildContext to be passed", and further
Quote:
Explain #
There are two reasons why you need to wrap MaterialApp
Because this ensures that toast can be displayed in front of all other
controls Context can be cached so that it can be invoked anywhere
without passing in context
This implies to me that there is a better way by providing a Material app ancestor somewhere....
For a simple Solution I would use the Provider Package. Keyword here is StateManagement (https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple)
The Model would look sth like this:
class UploadModel extends ChangeNotifier {
final bool loading = false;
void uploadXY() async{
loading = true;
// This call tells the widgets that are listening to this model to rebuild.
notifyListeners();
await realUploadStuff();
loading = true;
notifyListeners();
}
}
To start the upload:
Provider.of<UploadModel>(this).uploadXY()
To react if loading-bool changes:
if(Provider.of<UploadModel>(this).loading)...
You can find a simple Example here:
https://github.com/flutter/samples/blob/master/provider_counter/lib/main.dart