Home > Back-end >  How do I separate a flutter package into another file then call it in main.dart?
How do I separate a flutter package into another file then call it in main.dart?

Time:06-22

I have this simple code in my main.dart which gets the user's current geolocation what I want to do is to create a separate file like get_geolocation.dart and then call it back in my main.dart just to make my main.dart file cleaner, less code in it and more organized. Here's my main.dart code:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Position? _position;

  void _getCurrentLocation() async {
    Position position = await _determinePosition();
    setState(() {
      _position = position;
    });
  }

  Future<Position> _determinePosition() async {
    LocationPermission permission;
    permission = await Geolocator.checkPermission();
    if(permission== LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if(permission == LocationPermission.denied){
        return Future.error('Location Permissions are denied');
      }
    }

    return await Geolocator.getCurrentPosition();
    }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('geolocator'),
        centerTitle: true,
      ),
      body: Center(
        child: _position != null
            ? Text('Current position: '   _position.toString())
            : Text('No Location Data'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _getCurrentLocation,
        tooltip: 'increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

CodePudding user response:

Using underscore in method names, class and variables makes it private. so you can only access it where it defined. In your code, it's in main.dart. Here I have removed underscores in get_geolocation.dart.

Here I did just like @Omi shah told in comments.

  1. Extract the widget and moved in to a new file.
  2. import the package name.

Change as you want.

main.dart

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

import 'get_geolocation.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return  MaterialApp(
      home: HomePage(),
    );
  }
}

get_geolocation.dart

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Position? _position;

  void getCurrentLocation() async {
    Position position = await determinePosition();
    setState(() {
      _position = position;
    });
  }

  Future<Position> determinePosition() async {
    LocationPermission permission;
    permission = await Geolocator.checkPermission();
    if(permission== LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if(permission == LocationPermission.denied){
        return Future.error('Location Permissions are denied');
      }
    }

    return await Geolocator.getCurrentPosition();
    }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('geolocator'),
        centerTitle: true,
      ),
      body: Center(
        child: _position != null
            ? Text('Current position: '   _position.toString())
            : Text('No Location Data'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _getCurrentLocation,
        tooltip: 'increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

CodePudding user response:

You could create a class to keep your methods and interfaces to geolocation services.

file: lib/src/utils/location_controller.dart

class LocationController {
  LocationController();

  // This way you create only one instance of Geolocator
  // instead of creating a new instance every time the method is called
  late final geolocator = Geolocator();

  Future<Position> get myPosition async {
    // Place additional logic
    return await geolocator.getCurrentPosition();
  }
}

Import this class in any widget:

class _HomePageState extends State<HomePage> {
  late final locationController = LocationController();
  Position? _position;

  void _getCurrentLocation() async {
    final position = await locationController.myPosition;
    setState(() {
      _position = position;
    });
  }

If this "controller" becomes heavy to initialize, you might want to instantiate it in your main and pass down the tree as a parameter or use another method such as Provider.

You can create your apps in flutter using the skeleton template:

flutter create -t skeleton my_app 

It will give some ideia on how to structure your files and lots of best practices.

  • Related