1. Flutter 基础
-
Flutter SDK
brew install flutter sudo snap install flutter --classic
-
开发工具
-
Android Studio
-
VS Code
-
Xcode (仅 macOS)
-
环境检查
flutter doctor
-
VS Code 插件
-
Flutter
-
Dart
-
Flutter Widget Snippets
-
Android Studio 插件
flutter create my_app flutter create --org com.example my_app flutter create --platforms android,ios my_app flutter create --sample=material.AppBar.1 my_app
-
打开 VS Code
-
按下
Ctrl+Shift+P
(Windows/Linux)或 Cmd+Shift+P
(macOS)
-
输入
Flutter: New Project
-
选择项目存储位置
-
输入项目名称(使用小写字母和下划线)
-
等待项目创建和依赖安装完成
my_app/
├── android/ # Android 平台相关代码
├── ios/ # iOS 平台相关代码
├── lib/ # Dart 源代码
│ └── main.dart # 应用入口文件
├── test/ # 测试文件
├── web/ # Web 平台相关代码
├── pubspec.yaml # 项目配置文件
└── README.md # 项目说明文档
-
Ctrl + F5
(Windows/Linux)或 Cmd + F5
(macOS):无调试运行
-
Ctrl + Shift + F5
:重新运行
-
Shift + Alt + F
:格式化代码
-
Ctrl + .
:快速修复/重构
-
Ctrl + Space
:触发建议
-
Ctrl + Shift + R
:重新加载
-
Flutter
-
Dart
-
Flutter Widget Snippets
-
Awesome Flutter Snippets
-
Flutter Tree
-
pubspec Assist
-
Error Lens
var name = 'Bob'; String name = 'Bob'; dynamic name = 'Bob'; final name = 'Bob'; const pi = 3.14; int age = 30; double height = 1.75; String name = 'Bob'; bool isStudent = true;
List<String> fruits = ['apple', 'banana', 'orange']; var numbers = <int>[1, 2, 3, 4, 5]; Set<String> uniqueNames = {'John', 'Jane', 'Bob'}; Map<String, int> scores = { 'math': 95, 'english': 85, 'history': 90, };
int add(int a, int b) { return a + b; } int multiply(int a, int b) => a * b; String greet(String name, [String? title]) { return title != null ? '$title $name' : 'Hello $name'; } void printPerson({ required String name, int? age, String? address, }) { print('Name: $name, Age: ${age ?? "Unknown"}, Address: ${address ?? "N/A"}'); } void processNumbers(List<int> numbers, int Function(int) processor) { for (var number in numbers) { print(processor(number)); } }
class Person { final String name; int age; Person(this.name, this.age); Person.guest() : name = 'Guest', age = 0; void introduce() { print('My name is $name and I am $age years old.'); } String get info => '$name ($age)'; set setAge(int value) { if (value >= 0) { age = value; } } } class Student extends Person { String school; Student(String name, int age, this.school) : super(name, age); @override void introduce() { super.introduce(); print('I study at $school.'); } } mixin Musical { void playMusic() { print('Playing music...'); } } class MusicStudent extends Student with Musical { MusicStudent(String name, int age, String school) : super(name, age, school); }
Flutter 中一切都是 Widget,它们是用户界面的基本构建块。
class GreetingWidget extends StatelessWidget { final String name; const GreetingWidget({ Key? key, required this.name, }) : super(key: key); @override Widget build(BuildContext context) { return Text('Hello, $name!'); } }
class CounterWidget extends StatefulWidget { @override _CounterWidgetState createState() => _CounterWidgetState(); } class _CounterWidgetState extends State<CounterWidget> { int _counter = 0; void _increment() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Column( children: [ Text('Count: $_counter'), ElevatedButton( onPressed: _increment, child: Text('Increment'), ), ], ); } }
class LifecycleWidget extends StatefulWidget { @override _LifecycleWidgetState createState() => _LifecycleWidgetState(); } class _LifecycleWidgetState extends State<LifecycleWidget> { @override void initState() { super.initState(); print('1. initState - 组件初始化'); } @override void didChangeDependencies() { super.didChangeDependencies(); print('2. didChangeDependencies - 依赖变化'); } @override void didUpdateWidget(LifecycleWidget oldWidget) { super.didUpdateWidget(oldWidget); print('3. didUpdateWidget - 组件更新'); } @override void setState(VoidCallback fn) { super.setState(fn); print('4. setState - 状态更新'); } @override void deactivate() { print('5. deactivate - 组件停用'); super.deactivate(); } @override void dispose() { print('6. dispose - 组件销毁'); super.dispose(); } @override Widget build(BuildContext context) { print('7. build - 构建UI'); return Container(); } }
Text( 'Hello World', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue, ), ) Image.network('https://example.com/image.jpg') Image.asset('assets/images/logo.png') ElevatedButton( onPressed: () {}, child: Text('点击我'), ) TextButton( onPressed: () {}, child: Text('文本按钮'), ) IconButton( icon: Icon(Icons.add), onPressed: () {}, ) TextField( decoration: InputDecoration( labelText: '用户名', hintText: '请输入用户名', border: OutlineInputBorder(), ), onChanged: (value) { print('输入内容: $value'); }, )
Container( width: 200, height: 200, padding: EdgeInsets.all(16), margin: EdgeInsets.symmetric(vertical: 8), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.black26, offset: Offset(0, 2), blurRadius: 6, ), ], ), child: Text('容器内容'), ) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('左侧'), Text('中间'), Text('右侧'), ], ) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('顶部'), Text('中部'), Text('底部'), ], ) Stack( children: [ Image.asset('background.jpg'), Positioned( bottom: 16, right: 16, child: Text('覆盖文本'), ), ], ) Row( children: [ Expanded( flex: 2, child: Container(color: Colors.red), ), Flexible( flex: 1, child: Container(color: Colors.blue), ), ], )
Scaffold( appBar: AppBar( title: Text('应用标题'), actions: [ IconButton( icon: Icon(Icons.settings), onPressed: () {}, ), ], ), body: Center( child: Text('页面内容'), ), floatingActionButton: FloatingActionButton( onPressed: () {}, child: Icon(Icons.add), ), drawer: Drawer( child: ListView( children: [ DrawerHeader( child: Text('侧边栏头部'), decoration: BoxDecoration( color: Colors.blue, ), ), ListTile( title: Text('菜单项 1'), onTap: () {}, ), ], ), ), )
Navigator.push( context, MaterialPageRoute( builder: (context) => SecondScreen(), ), ); Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(id: 123), ), ); MaterialApp( initialRoute: '/', routes: { '/': (context) => HomeScreen(), '/detail': (context) => DetailScreen(), '/settings': (context) => SettingsScreen(), }, ) Navigator.pushNamed( context, '/detail', arguments: {'id': 123}, ); class DetailScreen extends StatelessWidget { @override Widget build(BuildContext context) { final args = ModalRoute.of(context)!.settings.arguments as Map; return Scaffold( body: Center( child: Text('详情页 ID: ${args['id']}'), ), ); } }
class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } } void main() { runApp( ChangeNotifierProvider( create: (context) => Counter(), child: MyApp(), ), ); } class CounterWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: [ Consumer<Counter>( builder: (context, counter, child) { return Text('Count: ${counter.count}'); }, ), ElevatedButton( onPressed: () { context.read<Counter>().increment(); }, child: Text('增加'), ), ], ); } }
class CounterController extends GetxController { var count = 0.obs; void increment() => count++; } class CounterPage extends StatelessWidget { final controller = Get.put(CounterController()); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( children: [ Obx(() => Text('Count: ${controller.count}')), ElevatedButton( onPressed: controller.increment, child: Text('增加'), ), ], ), ), ); } }
class ApiService { final Dio _dio = Dio(); ApiService() { _dio.options.baseUrl = 'https://api.example.com'; _dio.options.connectTimeout = 5000; _dio.options.receiveTimeout = 3000; _dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { options.headers['Authorization'] = 'Bearer token'; return handler.next(options); }, onResponse: (response, handler) { return handler.next(response); }, onError: (DioError e, handler) { return handler.next(e); }, )); } Future<List<Post>> getPosts() async { try { final response = await _dio.get('/posts'); return (response.data as List) .map((json) => Post.fromJson(json)) .toList(); } catch (e) { throw Exception('Failed to load posts'); } } Future<Post> createPost(Post post) async { try { final response = await _dio.post( '/posts', data: post.toJson(), ); return Post.fromJson(response.data); } catch (e) { throw Exception('Failed to create post'); } } }
const String getPostsQuery = r'''
query GetPosts {
posts {
id
title
content
author {
name
}
}
}
'''; class GraphQLService { late GraphQLClient _client; GraphQLService() { final HttpLink httpLink = HttpLink('https://api.example.com/graphql'); _client = GraphQLClient( link: httpLink, cache: GraphQLCache(), ); } Future<List<Post>> getPosts() async { try { final QueryResult result = await _client.query( QueryOptions( document: gql(getPostsQuery), ), ); if (result.hasException) { throw result.exception!; } return (result.data!['posts'] as List) .map((json) => Post.fromJson(json)) .toList(); } catch (e) { throw Exception('Failed to fetch posts: $e'); } } }
class PreferencesService { static late SharedPreferences _prefs; static Future<void> init() async { _prefs = await SharedPreferences.getInstance(); } static Future<bool> setString(String key, String value) async { return await _prefs.setString(key, value); } static Future<bool> setInt(String key, int value) async { return await _prefs.setInt(key, value); } static String? getString(String key) { return _prefs.getString(key); } static int? getInt(String key) { return _prefs.getInt(key); } static Future<void> saveUserInfo(User user) async { await setString('username', user.name); await setInt('age', user.age); } static User? getUserInfo() { final name = getString('username'); final age = getInt('age'); if (name != null && age != null) { return User(name: name, age: age); } return null; } }
class DatabaseHelper { static final DatabaseHelper instance = DatabaseHelper._init(); static Database? _database; DatabaseHelper._init(); Future<Database> get database async { if (_database != null) return _database!; _database = await _initDB('app.db'); return _database!; } Future<Database> _initDB(String filePath) async { final dbPath = await getDatabasesPath(); final path = join(dbPath, filePath); return await openDatabase( path, version: 1, onCreate: _createDB, ); } Future<void> _createDB(Database db, int version) async { await db.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TEXT NOT NULL
)
'''); await db.execute('''
CREATE TABLE articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
user_id INTEGER,
created_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users (id)
)
'''); } Future<int> insertUser(User user) async { final db = await database; return await db.insert('users', user.toMap()); } Future<User?> getUser(int id) async { final db = await database; final maps = await db.query( 'users', where: 'id = ?', whereArgs: [id], ); if (maps.isNotEmpty) { return User.fromMap(maps.first); } return null; } Future<List<User>> getAllUsers() async { final db = await database; final result = await db.query('users'); return result.map((map) => User.fromMap(map)).toList(); } Future<int> updateUser(User user) async { final db = await database; return await db.update( 'users', user.toMap(), where: 'id = ?', whereArgs: [user.id], ); } Future<int> deleteUser(int id) async { final db = await database; return await db.delete( 'users', where: 'id = ?', whereArgs: [id], ); } }
android { defaultConfig { applicationId "com.example.myapp"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0.0" } signingConfigs { release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword'] } } buildTypes { release { signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
const MyWidget({Key? key}) : super(key: key); @override void dispose() { _controller.dispose(); _focusNode.dispose(); super.dispose(); } Image.network( url, cacheWidth: 300, cacheHeight: 300, )
RepaintBoundary( child: MyComplexWidget(), ) ListView.builder( itemCount: items.length, cacheExtent: 100.0, itemBuilder: (context, index) { return ListTile( key: ValueKey(items[index].id), title: Text(items[index].title), ); }, )
void main() async { WidgetsFlutterBinding.ensureInitialized(); await precacheImage( AssetImage('assets/images/splash.png'), null, ); await Future.wait([ SharedPreferences.getInstance(), DatabaseHelper.instance.initDatabase(), loadConfigurations(), ]); runApp(MyApp()); }
https://gitee.com/NextEraAbyss/flutter_forge
本文档详细介绍了 Flutter 开发的各个方面,从基础知识到进阶技巧,并通过一个完整的新闻阅读器项目展示了 Flutter 的实际应用。希望这份文档能够帮助你更好地学习和使用 Flutter 进行开发。
记住,优秀的应用不仅要实现功能,还要注重性能优化、用户体验和代码质量。在实际开发中,要根据具体需求和场景选择合适的技术方案,并持续优化和改进。
发表评论