3_flutter简单教程

Flutter 简单教程

概述

Flutter是Google开发的跨平台移动应用开发框架,使用Dart语言编写。本教程将从UI设计和代码逻辑两个方面介绍Flutter应用开发。

一、UI开发方面

1. Widget基础

Flutter应用由Widget组成,Widget是Flutter的基本构建块。

常用Widget类型

// 基础Widget
Text('Hello World')
Image.asset('assets/image.png')
Icon(Icons.star)

// 布局Widget
Container(
  width: 100,
  height: 100,
  color: Colors.blue,
)

Column(
  children: [
    Text('Item 1'),
    Text('Item 2'),
  ],
)

Row(
  children: [
    Icon(Icons.star),
    Text('Rating'),
  ],
)

2. 页面布局

Material Design风格

import 'package:flutter/material.dart';

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('我的应用'),
        backgroundColor: Colors.blue,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '欢迎使用Flutter!',
              style: TextStyle(fontSize: 24),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // 按钮点击事件
              },
              child: Text('点击我'),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // FAB点击事件
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

Cupertino风格(iOS风格)

import 'package:flutter/cupertino.dart';

class IosStylePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('iOS风格页面'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () {},
          child: Text('iOS风格按钮'),
        ),
      ),
    );
  }
}

3. 响应式设计

媒体查询

class ResponsiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 获取屏幕尺寸
    final screenWidth = MediaQuery.of(context).size.width;
    final screenHeight = MediaQuery.of(context).size.height;
    
    return Container(
      width: screenWidth > 600 ? 300 : 200, // 根据屏幕宽度调整
      height: screenHeight * 0.5, // 屏幕高度的50%
      child: Text('响应式布局'),
    );
  }
}

自适应布局

class AdaptiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth > 600) {
          // 平板或桌面布局
          return Row(
            children: [
              Expanded(flex: 1, child: Sidebar()),
              Expanded(flex: 3, child: MainContent()),
            ],
          );
        } else {
          // 手机布局
          return Column(
            children: [
              Expanded(child: MainContent()),
              BottomNavigation(),
            ],
          );
        }
      },
    );
  }
}

4. 动画和过渡

简单动画

class AnimatedContainerExample extends StatefulWidget {
  @override
  _AnimatedContainerExampleState createState() => _AnimatedContainerExampleState();
}

class _AnimatedContainerExampleState extends State<AnimatedContainerExample> {
  bool _expanded = false;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          _expanded = !_expanded;
        });
      },
      child: AnimatedContainer(
        duration: Duration(milliseconds: 300),
        width: _expanded ? 200 : 100,
        height: _expanded ? 200 : 100,
        color: _expanded ? Colors.blue : Colors.red,
        child: Center(child: Text('点击动画')),
      ),
    );
  }
}

二、代码后端逻辑方面

1. 状态管理

setState方法(简单状态)

class CounterApp extends StatefulWidget {
  @override
  _CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
  int _counter = 0;

  /// 增加计数器
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  /// 减少计数器
  void _decrementCounter() {
    setState(() {
      _counter--;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('计数器: $_counter', style: TextStyle(fontSize: 24)),
            SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: _decrementCounter,
                  child: Text('-'),
                ),
                SizedBox(width: 20),
                ElevatedButton(
                  onPressed: _incrementCounter,
                  child: Text('+'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Provider状态管理(推荐)

import 'package:provider/provider.dart';

// 数据模型
class UserModel with ChangeNotifier {
  String _name = '';
  int _age = 0;

  String get name => _name;
  int get age => _age;

  /// 更新用户信息
  void updateUser(String newName, int newAge) {
    _name = newName;
    _age = newAge;
    notifyListeners(); // 通知监听器更新UI
  }
}

// 使用Provider
class UserProfile extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<UserModel>(
      builder: (context, user, child) {
        return Column(
          children: [
            Text('姓名: ${user.name}'),
            Text('年龄: ${user.age}'),
            ElevatedButton(
              onPressed: () {
                user.updateUser('张三', 25);
              },
              child: Text('更新用户'),
            ),
          ],
        );
      },
    );
  }
}

2. 数据持久化

SharedPreferences(本地存储)

import 'package:shared_preferences/shared_preferences.dart';

class SettingsService {
  static const String _themeKey = 'theme';
  static const String _languageKey = 'language';

  /// 保存主题设置
  static Future<void> saveTheme(String theme) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_themeKey, theme);
  }

  /// 获取主题设置
  static Future<String?> getTheme() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(_themeKey);
  }

  /// 保存语言设置
  static Future<void> saveLanguage(String language) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_languageKey, language);
  }

  /// 获取语言设置
  static Future<String?> getLanguage() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(_languageKey);
  }
}

SQLite数据库

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static final DatabaseHelper _instance = DatabaseHelper._internal();
  static Database? _database;

  DatabaseHelper._internal();

  factory DatabaseHelper() => _instance;

  /// 获取数据库实例
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDatabase();
    return _database!;
  }

  /// 初始化数据库
  Future<Database> _initDatabase() async {
    String path = join(await getDatabasesPath(), 'my_database.db');
    return await openDatabase(
      path,
      version: 1,
      onCreate: _createTables,
    );
  }

  /// 创建数据表
  Future<void> _createTables(Database db, int version) async {
    await db.execute('''
      CREATE TABLE users(
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT NOT NULL,
        created_at TEXT
      )
    ''');
  }

  /// 插入用户
  Future<int> insertUser(Map<String, dynamic> user) async {
    final db = await database;
    return await db.insert('users', user);
  }

  /// 查询所有用户
  Future<List<Map<String, dynamic>>> getUsers() async {
    final db = await database;
    return await db.query('users');
  }
}

3. 网络请求

HTTP请求

import 'dart:convert';
import 'package:http/http.dart' as http;

class ApiService {
  static const String baseUrl = 'https://api.example.com';

  /// 获取用户列表
  static Future<List<dynamic>> getUsers() async {
    try {
      final response = await http.get(Uri.parse('$baseUrl/users'));
      
      if (response.statusCode == 200) {
        return json.decode(response.body);
      } else {
        throw Exception('Failed to load users: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Network error: $e');
    }
  }

  /// 创建新用户
  static Future<dynamic> createUser(String name, String email) async {
    try {
      final response = await http.post(
        Uri.parse('$baseUrl/users'),
        headers: {'Content-Type': 'application/json'},
        body: json.encode({'name': name, 'email': email}),
      );

      if (response.statusCode == 201) {
        return json.decode(response.body);
      } else {
        throw Exception('Failed to create user: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Network error: $e');
    }
  }
}

使用Dio(第三方HTTP客户端)

import 'package:dio/dio.dart';

class DioService {
  static final Dio _dio = Dio();

  /// 配置Dio拦截器
  static void configureDio() {
    _dio.options.baseUrl = 'https://api.example.com';
    _dio.options.connectTimeout = Duration(seconds: 30);
    _dio.options.receiveTimeout = Duration(seconds: 30);
    
    // 添加拦截器
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        // 添加认证token
        options.headers['Authorization'] = 'Bearer your_token';
        return handler.next(options);
      },
      onError: (DioError e, handler) {
        // 错误处理
        return handler.next(e);
      },
    ));
  }

  /// 获取数据
  static Future<Response> getData(String endpoint) async {
    try {
      return await _dio.get(endpoint);
    } on DioError catch (e) {
      throw Exception('Dio error: ${e.message}');
    }
  }
}

4. 业务逻辑分离

服务层

/// 用户服务
class UserService {
  final ApiService _apiService;

  UserService(this._apiService);

  /// 获取用户信息
  Future<User> getUserById(int id) async {
    final data = await _apiService.get('/users/$id');
    return User.fromJson(data);
  }

  /// 更新用户信息
  Future<void> updateUser(User user) async {
    await _apiService.put('/users/${user.id}', user.toJson());
  }

  /// 删除用户
  Future<void> deleteUser(int id) async {
    await _apiService.delete('/users/$id');
  }
}

数据模型

/// 用户数据模型
class User {
  final int id;
  final String name;
  final String email;
  final DateTime createdAt;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.createdAt,
  });

  /// 从JSON创建User对象
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
      createdAt: DateTime.parse(json['created_at']),
    );
  }

  /// 将User对象转换为JSON
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
      'created_at': createdAt.toIso8601String(),
    };
  }
}

三、完整示例:待办事项应用

UI部分

import 'package:flutter/material.dart';

class TodoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '待办事项',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: TodoListPage(),
    );
  }
}

class TodoListPage extends StatefulWidget {
  @override
  _TodoListPageState createState() => _TodoListPageState();
}

class _TodoListPageState extends State<TodoListPage> {
  final List<TodoItem> _todos = [];
  final TextEditingController _textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('待办事项'),
        actions: [
          IconButton(
            icon: Icon(Icons.delete_sweep),
            onPressed: _clearCompleted,
          ),
        ],
      ),
      body: Column(
        children: [
          // 添加新待办事项
          Padding(
            padding: EdgeInsets.all(16.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _textController,
                    decoration: InputDecoration(
                      hintText: '输入新的待办事项',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                SizedBox(width: 8),
                ElevatedButton(
                  onPressed: _addTodo,
                  child: Text('添加'),
                ),
              ],
            ),
          ),
          // 待办事项列表
          Expanded(
            child: ListView.builder(
              itemCount: _todos.length,
              itemBuilder: (context, index) {
                final todo = _todos[index];
                return Dismissible(
                  key: Key(todo.id),
                  onDismissed: (direction) {
                    _removeTodo(index);
                  },
                  background: Container(color: Colors.red),
                  child: ListTile(
                    leading: Checkbox(
                      value: todo.completed,
                      onChanged: (value) {
                        _toggleTodo(index);
                      },
                    ),
                    title: Text(
                      todo.title,
                      style: todo.completed
                          ? TextStyle(decoration: TextDecoration.lineThrough)
                          : null,
                    ),
                    trailing: IconButton(
                      icon: Icon(Icons.edit),
                      onPressed: () => _editTodo(index),
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  void _addTodo() {
    if (_textController.text.isNotEmpty) {
      setState(() {
        _todos.add(TodoItem(
          id: DateTime.now().millisecondsSinceEpoch.toString(),
          title: _textController.text,
          completed: false,
        ));
        _textController.clear();
      });
    }
  }

  void _removeTodo(int index) {
    setState(() {
      _todos.removeAt(index);
    });
  }

  void _toggleTodo(int index) {
    setState(() {
      _todos[index].completed = !_todos[index].completed;
    });
  }

  void _editTodo(int index) {
    showDialog(
      context: context,
      builder: (context) {
        final controller = TextEditingController(text: _todos[index].title);
        return AlertDialog(
          title: Text('编辑待办事项'),
          content: TextField(controller: controller),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: Text('取消'),
            ),
            TextButton(
              onPressed: () {
                setState(() {
                  _todos[index].title = controller.text;
                });
                Navigator.pop(context);
              },
              child: Text('保存'),
            ),
          ],
        );
      },
    );
  }

  void _clearCompleted() {
    setState(() {
      _todos.removeWhere((todo) => todo.completed);
    });
  }
}

class TodoItem {
  final String id;
  String title;
  bool completed;

  TodoItem({
    required this.id,
    required this.title,
    required this.completed,
  });
}

后端逻辑部分

/// 待办事项服务
class TodoService {
  final DatabaseHelper _databaseHelper;

  TodoService(this._databaseHelper);

  /// 获取所有待办事项
  Future<List<TodoItem>> getTodos() async {
    // 从数据库获取数据
    final data = await _databaseHelper.getTodos();
    return data.map((item) => TodoItem.fromJson(item)).toList();
  }

  /// 保存待办事项
  Future<void> saveTodo(TodoItem todo) async {
    await _databaseHelper.insertTodo(todo.toJson());
  }

  /// 删除待办事项
  Future<void> deleteTodo(String id) async {
    await _databaseHelper.deleteTodo(id);
  }

  /// 更新待办事项
  Future<void> updateTodo(TodoItem todo) async {
    await _databaseHelper.updateTodo(todo.toJson());
  }
}

四、最佳实践

UI开发最佳实践

  1. 组件化:将UI拆分为可重用的组件
  2. 响应式设计:适配不同屏幕尺寸
  3. 一致性:保持设计风格统一
  4. 性能优化:避免不必要的重绘

代码逻辑最佳实践

  1. 分离关注点:UI、业务逻辑、数据层分离
  2. 错误处理:完善的异常处理机制
  3. 测试驱动:编写单元测试和集成测试
  4. 代码规范:遵循Dart代码规范

总结

Flutter开发需要同时关注UI设计和代码逻辑。UI方面要掌握Widget的使用、布局技巧和动画效果;代码逻辑方面要理解状态管理、数据持久化和网络请求等核心概念。通过合理的架构设计,可以开发出高性能、易维护的Flutter应用。

posted @ 2025-10-04 02:04  suveng  阅读(11)  评论(0)    收藏  举报