因為自己最近迷上了釣魚,但卻常常苦於不知道該去哪裡釣魚才能安全又有魚,因此想做個讓大家可以分享自己釣點以及釣況的App,讓大家都能找到適合自己的地方釣魚!
最近有新開一個
部落格是在介紹Flutter相關的文章,大家可以去看看~
專案架構
專案架構可以參考我上一篇文章,這個專案我也是使用這個架構搭配GetX作為管理套件。
Pub.dev
Pub.dev提供了許多專門給Dart和Flutter使用的套件,如果有要實作的功能,可以先到這裡尋找有沒有別人已經做好的套件可以使用,可以省下許多麻煩,如果你有做好的套件也可以上傳到這裡供大家使用!
基本設定
Dart會找到你專案中的main()這個方法作為整個程式的起點,因此只能有一個main function,在你創建好專案後就會有基本的設定,不需要特別去調整。
接下來我們針對我們的App,做一些基本的設定
void main() async {
await Firebase.initializeApp(); -> 確保建立Firebase相關的實例
runZonedGuarded(() async {
runApp(MyApp()); -> 啟動 App
}, (Object error, StackTrace stack) async {
// 這邊是錯誤處理,防止沒有被catch到的error, app會直接crash
// 可以做一個dialog來提醒user 或是在此紀錄錯誤log 方便之後修正
});
}
- getPages 為整個app所有的畫面路徑設定
- initialRoute 為app 進入的第一個畫面的路徑
- initialBinding 是開啟app時會初始化的GetX Binding
- 將原本的 MaterialApp 改為 GetMaterialApp,這樣就可以使用GetX來管理路徑了
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Fish Info',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: Routes.splashRoute, -> 第一個畫面的路徑
getPages: Routes.routes,
localizationsDelegates: const [
DefaultCupertinoLocalizations.delegate, -> 之後說明用處
],
initialBinding: GlobalBinding(),
);
}
}
路徑設定
這裡就是設定所有畫面的地方,以後有要新增畫面記得要回來這邊新增路徑跟GetPage,記得一定要使用binding來註冊GetXController,否則在某些特定情況下GetXController不會被正常初始化及釋放!
class Routes {
Routes._();
static const splashRoute = '/splash';
static const homeRoute = '/home';
static final List<GetPage> routes = [
GetPage(name: splashRoute, page: () => const SplashPage(), binding: SplashBinding()),
GetPage(name: homeRoute, page: () => const HomePage(), binding: HomeBinding()),
];
}
如何連結GetX Controller
只需要繼承Bindings並覆寫dependecies,在裡面初始化你想要的GetXController即可,如果需要多個相同種類的controller,可以新增tag的參數並在使用時代入參數即可,之後有機會再做詳細的說明。
如果不想要你的controller在頁面被移除時也跟著被移除,像是我們的GlobalController,可以在初始化時代入permanent參數為true即可。
class GlobalBinding extends Bindings {
@override
void dependencies() {
Get.put<GlobalController>(GlobalController(), permanent: true);
}
}
啟動畫面
在這個畫面我們要獲取使用者的位置,因此需要獲取權限才能去定位使用者,我們使用
Geolocator這個套件來幫忙,根據不同的平台會有不同的設定需要先設定,大家可以點進去照著做就可以了!
我們創建一個GeoHelper class,裡面用來放我們Geo相關的code,方便我們之後重複使用。
class GeoHelper {
GeoHelper._();
static Future<Position> determinePosition() async {
...
}
}
畫面
目前畫面還是空空如也,等到之後背景決定好之後再加上去~
class SplashPage extends StatelessWidget {
const SplashPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const SizedBox();
}
}
GetX Controller
我們會在這個class內處理所有的邏輯,late可以讓參數不用馬上賦予值,但是一定要確保他在被使用前被賦予值,否則程式會出現錯誤,目前沒有方法檢查變數是否已經被賦予值,因此在使用時要格外小心!
這邊我們會使用CameraPosition,需要先拿到
Google Map的套件才會有這個model,可以先去安裝,我們在下個畫面會使用到。
可以直接在terminal到專案位置輸入 flutter pub add google_maps_flutter,就會自己安裝了,所有在
pub.dev的套件都有這個功能,可以到每個套件的Installing內找到。
class SplashController extends GetxController {
late CameraPosition initialCameraPosition;
late bool isPermissionAllowed;
@override
void onInit() {
GeoHelper.determinePosition().then((position) {
// 成功得到使用者的位置資訊
initialCameraPosition = CameraPosition(
target: LatLng(position.latitude, position.longitude),
zoom: Config.defaultCameraZoom,
);
isPermissionAllowed = true;
}).catchError((_) {
// 代表使用者拒絕提供位置資訊或是獲取資訊有錯誤,因此我們要給予一個預設的值
initialCameraPosition = Config.defaultCameraPosition;
isPermissionAllowed = true;
}).whenComplete(() {
// 不管有沒有錯誤最後都會進到這裡
// 這裡我們要進到下一個畫面
Get.offNamed(
Routes.homeRoute,
// 將我們在這裡得到的資訊傳到下一個頁面
arguments: HomePageArgs(
initialCameraPosition: initialCameraPosition,
isPermissionAllowed: isPermissionAllowed,
)
);
});
}
}
GetX 路徑
GetX有提供許多轉換畫面的方法,根據不同的情境可以搭配使用。
- Get.offNamed: 移除當前的畫面並進入到下一頁,因為我們不希望使用者再回到Splash畫面,因此將他移除,當然我們也可以透過WillPopScope來防止使用者透過Android back按鍵或是iPhone的向右滑回到上一頁,但因為我們也不需要保留這個頁面,所以選擇這個方法。
剩下的方法大家可以到
GetX的網站去看,他有提供許多種語言的文件方便大家閱讀。
今天就先做到這裡,如果有任何問題、錯誤或是希望我介紹的主題都可以留言告訴我,謝謝!