Flutter快速上手,入门教程

发布于:2025-06-06 ⋅ 阅读:(62) ⋅ 点赞:(0)

目录

一、参考文档

二、准备工作

下载Flutter SDK:

配置环境

解决环境报错 zsh:command not found:flutter

执行【flutter doctor】测试效果

安装Xcode IOS环境

需要安装brew,通过brew安装CocoaPods.

复制命令行,打开终端

分别执行下面命令

如图所示

三、创建Flutter IOS项目

Mac 创建Flutter IOS项目

通过 sudo chmod -R 777 * 修改一下文件权限

Xcode 打开Flutter项目 

Android Studio创建Flutter项目

​Flutter目录层级介绍

依赖库/图片的引用 

pub包管理系统:

 使用第三库,在官网找到对应的库

 复制地方库的引用方式

四、Flutter简单应用

1.主题设置

1.1 定义主题数据

1.2 状态管理(以 Provider 为例)

1.3 在 MaterialApp 中应用主题

1.4 创建主题切换界面

2. 国际化

2.1 添加依赖

2.2 配置支持的语言

2.3 创建多语言资源文件

定义基础接口

实现英语资源

实现中文资源

创建本地化代理

在 UI 中使用本地化字符串

3. 相机相册调用

3.1 添加依赖

3.2 配置权限

iOS

Android

3.3 实现相机和相册功能

3.4 高级功能

拍摄视频

多选图片

五、Flutter 调用原生代码

基本原理

实现步骤

在 Flutter 端创建通道

在 Android 端实现(Kotlin)

在 iOS 端实现(Swift)

六、Flutter 打包工具


一、参考文档

API文档

链接

Flutter地址

https://docs.flutter.dev/

Homebrew地址

https://brew.sh

pub包管理系统

The official repository for Dart and Flutter packages.

Material Design官方Icons图标

https://fonts.google.com/icons

二、准备工作

  1. 升级Macos系统为最新系统

  2. 安装最新的Xcode

  3. 电脑上面需要安装brew https://brew.sh/

  4. 安装chrome浏览器(开发web用)

下载Flutter SDK:

FlutterSDK下载地址: https://docs.flutter.dev/get-started/install

常用编译软件:

下载zip并解压到本地文件中

配置环境

  1. 打开命令行,执行【open ~/.bash_profile 】

  2. 把刚解压好的FlutterSDK文件地址进行配置,把内容粘贴到.bash_profile文件

export PATH="$PATH:/home/yourusername/flutter/bin"
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

      3.  执行【source ~/.bash_profile 】,将.bash_profile文件生效

      4. 执行【flutter doctor】测试效果。

注意哈:这样配置,如果你只有(bash_profile,没有zshrc文件)。
需要每次打开终端输入一下 source ~/.bash_profile 命令,再使用flutter命令。不然会报错。
zsh:command not found:flutter

像下面图片效果:

解决环境报错 zsh:command not found:flutter

1、执行:【open ~/.zshrc 】

2、如果 提示文件不存在,则执行:【vim ~/.zshrc 】新建一个新文件。

 vim ~/.zshrc

再使用source命令重新加载一下:【source ~/.zshrc】,下次再编辑这个文件就可以直接执行:【open ~/.zshrc】

source ~/.zshrc 

执行【flutter doctor】测试效果

这个时候试试关闭终端再输入flutter doctor,此时Flutter SDK配置完成,按照下面提示进行安装操作(下载Android SDK、Xcode、CocoaPods)。

安装Xcode IOS环境

需要安装brew,通过brew安装CocoaPods.

Homebrew官网: https://brew.sh/

复制命令行,打开终端

分别执行下面命令

brew install cocoapods.

pod setup

sudo xcode-select --switch /Applications/xcode.app/contents/Developer

sudo xcodebuild -runFirstLaunch

如图所示

brew doctor

三、创建Flutter IOS项目

Mac 创建Flutter IOS项目

sudo flutter create flutterdemo 

sudo chmod -R 777 flutterdemo //修改一下文件权限 可读。可写 

通过 sudo chmod -R 777 * 修改一下文件权限

Xcode 打开Flutter项目 

flutter run
flutter -d all
flutter -d chrome

Android Studio创建Flutter项目

​Flutter目录层级介绍

依赖库/图片的引用 

pub包管理系统:

官网地址:https://pub.dev/

 使用第三库,在官网找到对应的库

 复制地方库的引用方式

四、Flutter简单应用

1.主题设置

在 Flutter 项目里,实现主题切换功能需要结合状态管理和 Flutter 的主题系统。下面为你介绍实现主题切换的具体步骤:

1.1 定义主题数据

要先创建亮、暗两种主题,并且设置好各自的颜色和样式。

import 'package:flutter/material.dart';

class AppThemes {
  static final lightTheme = ThemeData(
    brightness: Brightness.light,
    primaryColor: Colors.blue,
    scaffoldBackgroundColor: Colors.white,
    // 其他主题属性...
  );

  static final darkTheme = ThemeData(
    brightness: Brightness.dark,
    primaryColor: Colors.blue,
    scaffoldBackgroundColor: Colors.black,
    // 其他主题属性...
  );
}

1.2 状态管理(以 Provider 为例)

接着创建一个主题状态管理类,以此来保存和更新当前使用的主题。

import 'package:flutter/material.dart';

class ThemeProvider with ChangeNotifier {
  ThemeMode _themeMode = ThemeMode.system;

  ThemeMode get themeMode => _themeMode;

  void toggleTheme(bool isDark) {
    _themeMode = isDark ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }

  void setSystemTheme() {
    _themeMode = ThemeMode.system;
    notifyListeners();
  }
}

1.3 在 MaterialApp 中应用主题

然后在应用的根 Widget 里配置主题,并监听主题变化。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => ThemeProvider(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeProvider>(
      builder: (context, themeProvider, child) {
        return MaterialApp(
          title: 'Flutter Theme Demo',
          theme: AppThemes.lightTheme,
          darkTheme: AppThemes.darkTheme,
          themeMode: themeProvider.themeMode,
          home: const HomePage(),
        );
      },
    );
  }
}

1.4 创建主题切换界面

最后添加一个用于切换主题的 UI 组件,像开关或按钮。

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final themeProvider = Provider.of<ThemeProvider>(context);
    final isDark = themeProvider.themeMode == ThemeMode.dark;

    return Scaffold(
      appBar: AppBar(
        title: const Text('主题切换示例'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('切换主题'),
            Switch(
              value: isDark,
              onChanged: (value) {
                themeProvider.toggleTheme(value);
              },
            ),
          ],
        ),
      ),
    );
  }
}

2. 国际化

在 Flutter 项目中设置国际化需要配置多语言资源并确保应用能根据系统语言自动切换。以下是实现步骤:

2.1 添加依赖

pubspec.yaml中添加flutter_localizationsintl插件:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.18.1  # 最新版本

2.2 配置支持的语言

MaterialApp中指定支持的语言列表和本地化代理:

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 国际化示例',
      // 支持的语言列表
      supportedLocales: [
        Locale('en', 'US'), // 英语
        Locale('zh', 'CN'), // 中文
        // 添加更多语言...
      ],
      // 本地化代理
      localizationsDelegates: [
        AppLocalizations.delegate, // 自定义代理
        GlobalMaterialLocalizations.delegate, // Material组件本地化
        GlobalWidgetsLocalizations.delegate, // 小部件库本地化
        GlobalCupertinoLocalizations.delegate, // Cupertino组件本地化
      ],
      // 根据系统语言自动选择locale
      localeResolutionCallback: (locale, supportedLocales) {
        for (var supportedLocale in supportedLocales) {
          if (supportedLocale.languageCode == locale?.languageCode) {
            return supportedLocale;
          }
        }
        return supportedLocales.first; // 默认返回第一个支持的语言
      },
      home: const HomePage(),
    );
  }
}

2.3 创建多语言资源文件

创建一个抽象类定义所有翻译键,并为每种语言创建实现类:

定义基础接口
// lib/l10n/app_localizations.dart
import 'package:flutter/material.dart';

abstract class AppLocalizations {
  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
  }

  static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();

  // 定义翻译键
  String get appTitle;
  String greeting(String name);
  // 添加更多翻译...
}
实现英语资源
// lib/l10n/app_localizations_en.dart
class AppLocalizationsEn extends AppLocalizations {
  @override
  String get appTitle => 'Flutter Internationalization';

  @override
  String greeting(String name) => 'Hello, $name!';
}
实现中文资源
// lib/l10n/app_localizations_zh.dart
class AppLocalizationsZh extends AppLocalizations {
  @override
  String get appTitle => 'Flutter 国际化';

  @override
  String greeting(String name) => '你好,$name!';
}
创建本地化代理
// lib/l10n/app_localizations.dart (继续)
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  const _AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode);

  @override
  Future<AppLocalizations> load(Locale locale) async {
    switch (locale.languageCode) {
      case 'en':
        return AppLocalizationsEn();
      case 'zh':
        return AppLocalizationsZh();
      default:
        return AppLocalizationsEn(); // 默认使用英语
    }
  }

  @override
  bool shouldReload(_AppLocalizationsDelegate old) => false;
}

在 UI 中使用本地化字符串

// lib/home_page.dart
import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final localizations = AppLocalizations.of(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(localizations.appTitle),
      ),
      body: Center(
        child: Text(localizations.greeting('World')),
      ),
    );
  }
}

3. 相机相册调用

在 Flutter 中调用相机和相册功能,需要使用image_picker插件。以下是完整实现步骤:

3.1 添加依赖

pubspec.yaml中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^1.0.2  # 最新版本

然后执行flutter pub get安装。

3.2 配置权限

iOS

ios/Runner/Info.plist中添加:

<key>NSCameraUsageDescription</key>
<string>应用需要访问相机来拍摄照片</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>应用需要访问相册来选择照片</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>应用需要保存照片到相册</string>
Android

android/app/src/main/AndroidManifest.xml中添加:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 10及以下需要 -->

3.3 实现相机和相册功能

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

class CameraGalleryExample extends StatefulWidget {
  @override
  _CameraGalleryExampleState createState() => _CameraGalleryExampleState();
}

class _CameraGalleryExampleState extends State<CameraGalleryExample> {
  final ImagePicker _picker = ImagePicker();
  XFile? _pickedImage;

  // 从相机拍摄照片
  Future<void> _takePhoto() async {
    try {
      final XFile? photo = await _picker.pickImage(source: ImageSource.camera);
      if (photo != null) {
        setState(() {
          _pickedImage = photo;
        });
      }
    } catch (e) {
      print('Error taking photo: $e');
      // 显示错误提示
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('拍照失败: $e')),
      );
    }
  }

  // 从相册选择照片
  Future<void> _selectFromGallery() async {
    try {
      final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
      if (image != null) {
        setState(() {
          _pickedImage = image;
        });
      }
    } catch (e) {
      print('Error selecting image: $e');
      // 显示错误提示
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('选择图片失败: $e')),
      );
    }
  }
}

3.4 高级功能

拍摄视频
Future<void> _recordVideo() async {
  final XFile? video = await _picker.pickVideo(source: ImageSource.camera);
  if (video != null) {
    // 处理视频
  }
}
多选图片
Future<void> _selectMultipleImages() async {
  final List<XFile>? images = await _picker.pickMultiImage();
  if (images != null && images.isNotEmpty) {
    // 处理多张图片
  }
}

五、Flutter 调用原生代码

在 Flutter 中调用原生代码(如 Android 的 Java/Kotlin 或 iOS 的 Swift/Objective-C)需要使用 平台通道(Platform Channel)。以下是主要实现方式:

基本原理

MethodChannel 是 Flutter 与原生平台(Android、iOS)之间进行通信的一种机制,属于 Flutter 提供的三种通信通道之一(另外两种是 BasicMessageChannel 和 EventChannel)。它允许 Flutter 代码调用原生代码的方法,也允许原生代码调用 Flutter 代码的方法,实现双向通信。

实现步骤

在 Flutter 端创建通道

import 'package:flutter/services.dart';

class DeviceInfo {
  static const MethodChannel _channel = MethodChannel('com.example.device_info');

  // 获取设备信息
  static Future<Map<String, dynamic>> getInfo() async {
    try {
      final Map<dynamic, dynamic> result = await _channel.invokeMethod('getDeviceInfo');
      return Map<String, dynamic>.from(result);
    } on PlatformException catch (e) {
      throw Exception('Failed to get device info: ${e.message}');
    }
  }

  Future<void> _fetchDeviceInfo() async {
    try {
      final info = await DeviceInfo.getInfo();
      setState(() {
        _deviceInfo = info;
      });
    } catch (e) {
      print('Error: $e');
    }
  }
}

在 Android 端实现(Kotlin)

package com.example.device_info

import android.os.Build
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

class DeviceInfoPlugin : FlutterPlugin, MethodCallHandler {
  private lateinit var channel: MethodChannel

  override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.example.device_info")
    channel.setMethodCallHandler(this)
  }

  override fun onMethodCall(call: MethodCall, result: Result) {
    if (call.method == "getDeviceInfo") {
      val deviceInfo = mutableMapOf<String, Any>()
      
      // 添加设备信息
      deviceInfo["model"] = Build.MODEL
      deviceInfo["brand"] = Build.BRAND
      deviceInfo["device"] = Build.DEVICE
      deviceInfo["androidVersion"] = Build.VERSION.RELEASE
      deviceInfo["sdkInt"] = Build.VERSION.SDK_INT
      
      result.success(deviceInfo)
    } else {
      result.notImplemented()
    }
  }

  override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }
}


package com.example.my_app

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import com.example.device_info.DeviceInfoPlugin

class MainActivity : FlutterActivity() {
  override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    // 注册插件
    flutterEngine.plugins.add(DeviceInfoPlugin())
  }
}

在 iOS 端实现(Swift)

import Flutter
import UIKit

public class DeviceInfoPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(
      name: "com.example.device_info",
      binaryMessenger: registrar.messenger()
    )
    let instance = DeviceInfoPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    if call.method == "getDeviceInfo" {
      let device = UIDevice.current
      let info = [
        "model": device.model,
        "systemName": device.systemName,
        "systemVersion": device.systemVersion,
        "localizedModel": device.localizedModel,
        "name": device.name
      ]
      result(info)
    } else {
      result(FlutterMethodNotImplemented)
    }
  }
}

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    // 注册插件
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

六、Flutter 打包工具


网站公告

今日签到

点亮在社区的每一天
去签到