本地化
略(建議配合 get_cli 相關命令使用)
更新 locale
var locale = Locale('en', 'US');
Get.updateLocale(locale);
獲取系統的 locale
return GetMaterialApp(
locale: Get.deviceLocale,
);
切換主題
Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
GetPage 中間層
示例:
// 設置中間層
GetPage(
name: AppRoutes.Main,
page: () => MainScreen(),
middlewares: [
RouteAuthMiddleware(priority: 1),
],
),
// 定義中間層
class RouteAuthMiddleware extends GetMiddleware {
RouteAuthMiddleware({required int priority}) : super(priority: priority);
@override
RouteSettings? redirect(String? route) {
var isLogin = SpUtil.getBool("isLogin");
if (isLogin == null || !isLogin) {
Future.delayed(Duration(seconds: 1), () => Get.snackbar("提示", "請先登錄APP"));
return RouteSettings(name: AppRoutes.Login);
} else {
return null;
}
}
}
GetMaterialApp 的全局配置
GetMaterialApp( enableLog: true, defaultTransition: Transition.fade, opaqueRoute: Get.isOpaqueRouteDefault, popGesture: Get.isPopGestureEnable, transitionDuration: Get.defaultDurationTransition, defaultGlobalState: Get.defaultGlobalState, ); Get.config( enableLog = true, defaultPopGesture = true, defaultTransition = Transitions.cupertino )
日志聚合
GetMaterialApp(
enableLog: true,
logWriterCallback: localLogWriter,
);
void localLogWriter(String text, {bool isError = false}) {
// pass the message to your favourite logging package here
// please note that even if enableLog: false log messages will be pushed in this callback
// you get check the flag if you want through GetConfig.isLogEnable
}
.obs 變量的更新
final name = 'GetX'.obs;
// only "updates" the stream, if the value is different from the current one.
name.value = 'Hey';
// All Rx properties are "callable" and returns the new value.
// but this approach does not accepts `null`, the UI will not rebuild.
name('Hello');
// is like a getter, prints 'Hello'.
name() ;
/// numbers:
final count = 0.obs;
// You can use all non mutable operations from num primitives!
count + 1;
// Watch out! this is only valid if `count` is not final, but var
count += 1;
// You can also compare against values:
count > 2;
/// booleans:
final flag = false.obs;
// switches the value between true/false
flag.toggle();
/// all types:
// Sets the `value` to null.
flag.nil();
// All toString(), toJson() operations are passed down to the `value`
print( count ); // calls `toString()` inside for RxInt
final abc = [0,1,2].obs;
// Converts the value to a json Array, prints RxList
// Json is supported by all Rx types!
print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');
// RxMap, RxList and RxSet are special Rx types, that extends their native types.
// but you can work with a List as a regular list, although is reactive!
abc.add(12); // pushes 12 to the list, and UPDATES the stream.
abc[3]; // like Lists, reads the index 3.
// equality works with the Rx and the value, but hashCode is always taken from the value
final number = 12.obs;
print( number == 12 ); // prints > true
/// Custom Rx Models:
// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.
class User {
String name, last;
int age;
User({this.name, this.last, this.age});
@override
String toString() => '$name $last, $age years old';
}
final user = User(name: 'John', last: 'Doe', age: 33).obs;
// `user` is "reactive", but the properties inside ARE NOT!
// So, if we change some variable inside of it...
user.value.name = 'Roi';
// The widget will not rebuild!,
// `Rx` don't have any clue when you change something inside user.
// So, for custom classes, we need to manually "notify" the change.
user.refresh();
// or we can use the `update()` method!
user.update((value){
value.name='Roi';
});
print( user );
GetView
直接注入 controller 實例
class AwesomeController extends GetController {
final String title = 'My Awesome View';
}
// ALWAYS remember to pass the `Type` you used to register your controller!
class AwesomeView extends GetView<AwesomeController> {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Text(controller.title), // just call `controller.something`
);
}
}
GetxService
用於代理 GetxController,並且不會自動銷毀。常用於 ApiService, StorageService, CacheService 等。僅能通過 Get.reset 刪除
Future<void> main() async {
await initServices(); /// AWAIT SERVICES INITIALIZATION.
runApp(SomeApp());
}
/// Is a smart move to make your Services intiialize before you run the Flutter app.
/// as you can control the execution flow (maybe you need to load some Theme configuration,
/// apiKey, language defined by the User... so load SettingService before running ApiService.
/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.
void initServices() async {
print('starting services ...');
/// Here is where you put get_storage, hive, shared_pref initialization.
/// or moor connection, or whatever that's async.
await Get.putAsync(() => DbService().init());
await Get.putAsync(SettingsService()).init();
print('All services started...');
}
class DbService extends GetxService {
Future<DbService> init() async {
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
}
}
class SettingsService extends GetxService {
void init() async {
print('$runtimeType delays 1 sec');
await 1.delay();
print('$runtimeType ready!');
}
}
GetResponsiveView
響應式渲染。略
本地狀態組件
ValueBuilder
ValueBuilder<bool>(
initialValue: false,
builder: (value, updateFn) => Switch(
value: value,
onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )
),
// if you need to call something outside the builder method.
onUpdate: (value) => print("Value updated: $value"),
onDispose: () => print("Widget unmounted"),
),
ObxValue
ObxValue((data) => Switch(
value: data.value,
onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,
),
false.obs,
),
其它 api
// give the current args from currentScreen Get.arguments // give name of previous route Get.previousRoute // give the raw route to access for example, rawRoute.isFirst() Get.rawRoute // give access to Routing API from GetObserver Get.routing // check if snackbar is open Get.isSnackbarOpen // check if dialog is open Get.isDialogOpen // check if bottomsheet is open Get.isBottomSheetOpen // remove one route. Get.removeRoute() // back repeatedly until the predicate returns true. Get.until() // go to next route and remove all the previous routes until the predicate returns true. Get.offUntil() // go to next named route and remove all the previous routes until the predicate returns true. Get.offNamedUntil() //Check in what platform the app is running GetPlatform.isAndroid GetPlatform.isIOS GetPlatform.isMacOS GetPlatform.isWindows GetPlatform.isLinux GetPlatform.isFuchsia //Check the device type GetPlatform.isMobile GetPlatform.isDesktop //All platforms are supported independently in web! //You can tell if you are running inside a browser //on Windows, iOS, OSX, Android, etc. GetPlatform.isWeb // Equivalent to : MediaQuery.of(context).size.height, // but immutable. Get.height Get.width // Gives the current context of the Navigator. Get.context // Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code. Get.contextOverlay // Note: the following methods are extensions on context. Since you // have access to context in any place of your UI, you can use it anywhere in the UI code // If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context. context.width context.height // Gives you the power to define half the screen, a third of it and so on. // Useful for responsive applications. // param dividedBy (double) optional - default: 1 // param reducedBy (double) optional - default: 0 context.heightTransformer() context.widthTransformer() /// Similar to MediaQuery.of(context).size context.mediaQuerySize() /// Similar to MediaQuery.of(context).padding context.mediaQueryPadding() /// Similar to MediaQuery.of(context).viewPadding context.mediaQueryViewPadding() /// Similar to MediaQuery.of(context).viewInsets; context.mediaQueryViewInsets() /// Similar to MediaQuery.of(context).orientation; context.orientation() /// Check if device is on landscape mode context.isLandscape() /// Check if device is on portrait mode context.isPortrait() /// Similar to MediaQuery.of(context).devicePixelRatio; context.devicePixelRatio() /// Similar to MediaQuery.of(context).textScaleFactor; context.textScaleFactor() /// Get the shortestSide from screen context.mediaQueryShortestSide() /// True if width be larger than 800 context.showNavbar() /// True if the shortestSide is smaller than 600p context.isPhone() /// True if the shortestSide is largest than 600p context.isSmallTablet() /// True if the shortestSide is largest than 720p context.isLargeTablet() /// True if the current device is Tablet context.isTablet() /// Returns a value<T> according to the screen size /// can give value for: /// watch: if the shortestSide is smaller than 300 /// mobile: if the shortestSide is smaller than 600 /// tablet: if the shortestSide is smaller than 1200 /// desktop: if width is largest than 1200 context.responsiveValue<T>()
2233
