Flutter 自定义插件开发:实现原生 Toast 提示功能
·
Flutter 自定义插件开发:实现原生 Toast 提示功能
1. 插件创建与配置
使用命令创建插件项目:
flutter create --template=plugin --org com.example flutter_toast_plugin
项目结构:
flutter_toast_plugin/
├── android/ # Android 原生实现
├── ios/ # iOS 原生实现
└── lib/ # Dart 接口
2. Android 原生实现
在 android/src/main/kotlin/com/example/flutter_toast_plugin/ToastPlugin.kt:
package com.example.flutter_toast_plugin
import android.content.Context
import android.widget.Toast
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class ToastPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private lateinit var channel: MethodChannel
private lateinit var context: Context
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(binding.binaryMessenger, "toast_channel")
channel.setMethodCallHandler(this)
context = binding.applicationContext
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"showToast" -> {
val message = call.argument<String>("msg") ?: ""
val duration = call.argument<Int>("duration") ?: Toast.LENGTH_SHORT
Toast.makeText(context, message, duration).show()
result.success(null)
}
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
3. iOS 原生实现
在 ios/Classes/ToastPlugin.swift:
import Flutter
import UIKit
public class ToastPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "toast_channel", binaryMessenger: registrar.messenger())
let instance = ToastPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "showToast":
guard let args = call.arguments as? [String: Any],
let message = args["msg"] as? String else {
result(FlutterError(code: "INVALID_ARGS", message: "Invalid arguments", details: nil))
return
}
showToast(message: message)
result(nil)
default:
result(FlutterMethodNotImplemented)
}
}
private func showToast(message: String) {
DispatchQueue.main.async {
guard let window = UIApplication.shared.keyWindow else { return }
let toastView = UILabel()
toastView.text = message
toastView.textAlignment = .center
toastView.backgroundColor = UIColor.black.withAlphaComponent(0.7)
toastView.textColor = UIColor.white
toastView.layer.cornerRadius = 10
toastView.clipsToBounds = true
toastView.numberOfLines = 0
let maxSize = CGSize(width: window.bounds.width - 40, height: window.bounds.height)
let textSize = toastView.sizeThatFits(maxSize)
toastView.frame = CGRect(
x: window.center.x - textSize.width/2 - 10,
y: window.bounds.height - 100,
width: textSize.width + 20,
height: textSize.height + 20
)
window.addSubview(toastView)
UIView.animate(withDuration: 2.0, delay: 1.5, options: .curveEaseOut, animations: {
toastView.alpha = 0.0
}, completion: { _ in
toastView.removeFromSuperview()
})
}
}
}
4. Dart 接口封装
在 lib/flutter_toast_plugin.dart:
import 'package:flutter/services.dart';
class FlutterToastPlugin {
static const MethodChannel _channel =
const MethodChannel('toast_channel');
/// 显示原生 Toast
/// [msg] 提示内容
/// [duration] 显示时长(仅Android有效)
static Future<void> showToast({
required String msg,
int duration = 0, // 0=短时, 1=长时
}) async {
try {
await _channel.invokeMethod('showToast', {
'msg': msg,
'duration': duration,
});
} on PlatformException catch (e) {
print("Toast显示失败: ${e.message}");
}
}
}
5. 使用示例
import 'package:flutter/material.dart';
import 'package:flutter_toast_plugin/flutter_toast_plugin.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Toast 示例')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: Text('显示短Toast'),
onPressed: () => FlutterToastPlugin.showToast(msg: '你好 Flutter!'),
),
ElevatedButton(
child: Text('显示长Toast'),
onPressed: () => FlutterToastPlugin.showToast(
msg: '这是一个长时间提示',
duration: 1
),
)
],
),
),
),
);
}
}
关键技术点
- 平台通道:通过
MethodChannel实现 Dart 与原生通信 - 平台差异处理:
- Android 使用原生
Toast组件 - iOS 使用自定义
UILabel模拟 Toast
- Android 使用原生
- 线程安全:
- iOS 通过
DispatchQueue.main.async确保 UI 操作在主线程
- iOS 通过
- 参数传递:使用 Map 传递多参数
常见问题解决
- iOS 无法显示:检查是否在
AppDelegate.swift中注册插件:
import flutter_toast_plugin
@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
- Android 空指针:确保在
onAttachedToEngine中初始化 Context
此插件已实现基础 Toast 功能,可通过扩展参数支持位置调整、样式自定义等高级特性。
更多推荐

所有评论(0)