Bhikkhu Subhuti
Bhikkhu Subhuti

Reputation: 542

Pass a callback function to child stateful widget (modern Flutter)

How to pass a function parameter in a Flutter object (function pointer in C++)? All samples seem to be outdated.

I have a main page with a BottomNavigationBar and it works with 4 stateful widgets. It changes the body widget to each of the four widgets as the tabs are pushed. _currentPage

     body: Padding(
    padding: const EdgeInsets.all(10.0),
    child: SingleChildScrollView(child: _currentPage),

I need some way to signal from the child widget to the parent that the settings have been saved so that it programmatically moves back to the home tab.

I guess the way to do this is to create a constructor in the stateful widget with a parameter that sets a member called.

final VoidCallBack goToHome();

This code was suggested on Stack Overflow here

I want to add a final VoidCallBack goToHome(); to my child stateful widget below. The parent has member widgets already created in the class parameters.

This was suggested on Stack Overflow here

Below is the code sample that I want to add a function callback member and have the constructor set it.

My full project code is located on GitHub here (subject to change)

   // parent has this function 
      void goToHome() {
    _currentIndex = 0;
    _currentPage = _page1;
    setState(() {});
  }
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:geolocator/geolocator.dart';

class GPSLocation extends StatefulWidget {
 // add constructor here
 // add member VoidCallBack goToHome();
  @override
  _GPSLocationState createState() => _GPSLocationState();
}

class _GPSLocationState extends State<GPSLocation> {
  Geolocator geoLocator = Geolocator();
  bool _initPerformed = false;

  String _message = "Please wait for GPS";

  @override
  void initState() {
    initGps();
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  void initGps() async {
    if (!_initPerformed) {
      bool serviceEnabled;
      LocationPermission permission;

      // Test if location services are enabled.
      serviceEnabled = await Geolocator.isLocationServiceEnabled();
      if (!serviceEnabled) {
        // Location services are not enabled don't continue
        // accessing the position and request users of the
        // App to enable the location services.
        return Future.error('Location services are disabled.');
      }

      permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
          // Permissions are denied, next time you could try
          // requesting permissions again (this is also where
          // Android's shouldShowRequestPermissionRationale
          // returned true. According to Android guidelines
          // your App should show an explanatory UI now.
          _message = 'Location permissions are denied';
        }
      }

      if (permission == LocationPermission.deniedForever) {
        // Permissions are denied forever, handle appropriately.
        _message =
            'Location permissions are permanently denied, we cannot request permissions.';
      }

      // When we reach here, permissions are granted and we can
      // continue accessing the position of the device.
    } // no finished with init of gps.
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.best);

    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setString("cityName", "GPS Generated");
    prefs.setDouble("lat", position.latitude);
    prefs.setDouble("lng", position.longitude);

    _message = 'GPS is set to ${position.latitude}, ${position.longitude}';
    setState(() {});
    // this is the magic...
    // call the parent's function here
     goToHome();
  }

  var controller = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("$_message"),
    );
  }
}

Upvotes: 1

Views: 2381

Answers (1)

Bhikkhu Subhuti
Bhikkhu Subhuti

Reputation: 542

With some trial and error and google.. I got this to work.

In the beginning the syntax to create a callback function is this GPSLocation({required this.goToHome});// passed named variable to avoid null final VoidCallback goToHome; // member decl

called later with this code widget.goToHome();

Here is the code:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:geolocator/geolocator.dart';

class GPSLocation extends StatefulWidget {
  GPSLocation({required this.goToHome});
  final VoidCallback goToHome;
  @override
  _GPSLocationState createState() => _GPSLocationState();
}

class _GPSLocationState extends State<GPSLocation> {
  Geolocator geoLocator = Geolocator();
  bool _initPerformed = false;

  String _message = "Please wait for GPS";

  @override
  void initState() {
    initGps();
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  void initGps() async {
    if (!_initPerformed) {
      bool serviceEnabled;
      LocationPermission permission;

      // Test if location services are enabled.
      serviceEnabled = await Geolocator.isLocationServiceEnabled();
      if (!serviceEnabled) {
        // Location services are not enabled don't continue
        // accessing the position and request users of the
        // App to enable the location services.
        return Future.error('Location services are disabled.');
      }

      permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
          // Permissions are denied, next time you could try
          // requesting permissions again (this is also where
          // Android's shouldShowRequestPermissionRationale
          // returned true. According to Android guidelines
          // your App should show an explanatory UI now.
          _message = 'Location permissions are denied';
        }
      }

      if (permission == LocationPermission.deniedForever) {
        // Permissions are denied forever, handle appropriately.
        _message =
            'Location permissions are permanently denied, we cannot request permissions.';
      }

      // When we reach here, permissions are granted and we can
      // continue accessing the position of the device.
    } // no finished with init of gps.
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.best);

    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setString("cityName", "GPS Generated");
    prefs.setDouble("lat", position.latitude);
    prefs.setDouble("lng", position.longitude);

    _message = 'GPS is set to ${position.latitude}, ${position.longitude}';
    setState(() {});
    widget.goToHome();
  }

  var controller = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("$_message"),
    );
  }
}

Upvotes: 3

Related Questions