[Newbie] Chapter 1. Flutter overview
[Newbie] Chapter 2. Flutter getting started
[Newbie] Chapter 3. Flutter initial setup
[Newbie] Chapter 4. Widget’s state
Content
- Work with asset files (image, font, files)
- Work with i18n
- Work with rest API
- Work with cache
- Work with dialog
- Work with app navigation
- Work with list
- Work with animation
- Work app version and env
- Testing
- Deal with performance, memory
Work with asset files
https://flutter.dev/docs/development/ui/assets-and-images
Work with i18n
https://flutter.dev/docs/development/accessibility-and-localization/internationalization
Create i18n
directory at <root project>/assets/
and update pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
flutter:
uses-material-design: true
assets:
- assets/i18n/
Create 2 JSON File en.json
and vi.json
and put all to i118n
created above
# en.json
{
"title": "Hello!"
}
# vi.json
{
"title": "Xin chào!"
}
Create DemoLocalizations Class And Delegate Class
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
// Helper method to keep the code in the widgets concise
// Localizations are accessed using an InheritedWidget "of" syntax
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
// Static member to have a simple access to the delegate from the MaterialApp
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
Map<String, String> _localizedStrings;
Future<bool> load() async {
// Load the language JSON file from the "lang" folder
String jsonString =
await rootBundle.loadString('assets/i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
// This method will be called from every widget which needs a localized text
String translate(String key) {
return _localizedStrings[key];
}
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
// This delegate instance will never change (it doesn't even have fields!)
// It can provide a constant constructor.
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
// Include all of your supported language codes here
return ['en', 'vi'].contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) async {
// AppLocalizations class is where the JSON loading actually runs
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
Make the MaterialApp localized
import 'package:flutter_localizations/flutter_localizations.dart';
import 'provider/app_localizations.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
supportedLocales: [
const Locale('en'),
const Locale('vi'),
],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AppContent(),
);
}
}
How to use it?
AppLocalizations.of(context).translate('title')
How to get Locale from the global setting?
import 'dart:ui' as ui;
Locale(ui.window.locale.languageCode, ui.window.locale.countryCode);
How to load Locale manually?
- First, install
bflutter
- Sample
import 'dart:ui' as ui;
class MyApp extends StatelessWidget {
static final localeBloc = BlocDefault<Locale>();
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: localeBloc.stream,
builder: (context, snapshot) {
print(snapshot);
return MaterialApp(
locale: (snapshot.hasData
? snapshot.data
: Locale(ui.window.locale.languageCode,
ui.window.locale.countryCode)),
supportedLocales: [
const Locale('en'),
const Locale('vi'),
],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AppContent(),
);
});
}
}
class AppContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(AppLocalizations.of(context).translate('title'))),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
child: Text('en'),
onPressed: () {
MyApp.localeBloc.push(Locale('en'));
},
),
RaisedButton(
child: Text('vi'),
onPressed: () {
MyApp.localeBloc.push(Locale('vi'));
},
),
],
),
));
}
}
** Use the way above, may you have to face the issue that black screen in first start app, because that approach needs time to load JSON language file and parsing, it takes a bit time. To avoid that, following below
- Install
bflutter
andflutter_localizations
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
bflutter: ^0.1.8+2
- Create languages file at
lib\provider\i18n
# lib\provider\i18n\en.dart
const en = {
'title': 'Hello'
};
# lib\provider\i18n\vi.dart
const vi = {
'title': 'Xin chào'
};
- Create
AppLocalizations
import 'package:flutter/widgets.dart';
import 'package:bflutter/provider/base_localizations.dart';
import 'package:cxi_pos/provider/i18n/en.dart';
import 'package:cxi_pos/provider/i18n/vi.dart';
class AppLocalizations extends BaseLocalizations {
AppLocalizations(locale) : super(locale);
// Helper method to keep the code in the widgets concise
// Localizations are accessed using an InheritedWidget "of" syntax
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
// Static member to have a simple access to the delegate from the MaterialApp
static LocalizationsDelegate<AppLocalizations> delegate =
AppLocalizationsDelegate(
['en', 'vi'], (locale) => AppLocalizations(locale));
@override
Map<String, String> load(Locale locale) {
switch (locale.languageCode) {
case 'vi':
return vi;
}
return en;
}
}
- Using
import 'dart:ui' as ui;
class MyApp extends StatelessWidget {
static final bloc = MainBloc.instance;
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: bloc.localeBloc.stream,
builder: (context, snapshot) {
return MaterialApp(
locale: (snapshot.hasData
? snapshot.data
: Locale(ui.window.locale.languageCode,
ui.window.locale.countryCode)),
supportedLocales: [
const Locale('en'),
const Locale('vi'),
],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AppContent(),
);
});
}
}
class AppContent extends StatelessWidget {
static final bloc = MainBloc.instance;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(AppLocalizations.of(context).translate('title'))),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
child: Text('en'),
onPressed: () {
bloc.localeBloc.push(Locale('en'));
},
),
RaisedButton(
child: Text('vi'),
onPressed: () {
bloc.localeBloc.push(Locale('vi'));
},
),
],
),
));
}
}
Work with rest API
https://flutter.dev/docs/cookbook/networking/fetch-data
Work with cache
- Image: https://flutter.dev/docs/cookbook/images/cached-images
- Storage: https://flutter.dev/docs/cookbook/persistence
Work with dialog
https://api.flutter.dev/flutter/material/AlertDialog-class.html
https://api.flutter.dev/flutter/material/Dialog-class.html
Work with app navigation
Doc: https://flutter.dev/docs/development/ui/navigation
Example: https://flutter.dev/docs/cookbook/navigation/navigation-basics
Work with list
Doc: https://flutter.dev/docs/cookbook/lists
API: https://api.flutter.dev/flutter/widgets/ListView-class.html
Work with animation
Topic: https://flutter.dev/docs/development/ui/animations
Widget: https://flutter.dev/docs/development/ui/widgets/animation
Tutorial: https://flutter.dev/docs/development/ui/animations/tutorial
Work with app version and env
- Updating the app’s version number
The default version number of the app is 1.0.0. To update it, navigate to the pubspec.yaml
file and update the following line:
version: 1.0.0+1
The version number is three numbers separated by dots, such as 1.0.0 in the example above, followed by an optional build number such as 1 in the example above, separated by a +.
Both the version and the build number may be overridden in Flutter’s build by specifying –build-name and –build-number, respectively.
In Android, build-name is used as versionName while build-number used as versionCode. For more information, see Version your app in the Android documentation.
If you want to build with a specific version, just run
flutter build apk --build-name=1.0.3
flutter build apk --build-number=3
flutter build apk --build-name=1.0.3 --build-number=3
- App environment
flutter run -t lib/Main/main_staging.dart
# Update FLUTTER_TARGET at ios/Flutter/Generated.xcconfig
FLUTTER_TARGET=lib/Main/main_staging.dart
Testing
https://flutter.dev/docs/testing
https://medium.com/stuart-engineering/flutter-ui-testing-7f7df932edf6
https://medium.com/flutter-community/testing-flutter-ui-with-flutter-driver-c1583681e337
https://blog.codemagic.io/flutter-ui-testing/
Deal with performance, memory
- Use android profile
- WidgetsBindingObserver
- Dev tools: https://flutter.dev/docs/development/tools/devtools/memory