Flutter打印功能插件rav_printer的使用
Flutter打印功能插件rav_printer的使用
rav_printer
插件用于实现标签打印机的TSPL命令和收据打印机的ESC/POS命令。
测试设备
- 标签打印机:型号 IW-C8LP -> IWARE
- 收据打印机:型号 C5813 -> IWARE
示例代码
以下是一个完整的示例代码,展示了如何在 Flutter 应用程序中使用 rav_printer
插件来实现标签和收据的打印功能。
import 'package:flutter/material.dart';
import 'package:bluetooth_print/bluetooth_print.dart';
import 'package:bluetooth_thermal_printer_plus/bluetooth_thermal_printer_plus.dart';
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:rav_printer/rav_printer.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyWidget(),
);
}
}
class ListWidth {
LabelWidth lw;
String screen;
ListWidth({
required this.lw,
required this.screen,
});
}
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
[@override](/user/override)
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
BluetoothPrint bluetoothPrint = BluetoothPrint.instance;
TextEditingController controllerHeight = TextEditingController(text: "100");
TextEditingController controllerGap = TextEditingController(text: "3");
List<ListWidth> lw = [
ListWidth(lw: LabelWidth.mm40, screen: "40mm"),
ListWidth(lw: LabelWidth.mm58, screen: "58mm"),
ListWidth(lw: LabelWidth.mm80, screen: "80mm"),
];
bool _connected = false;
String tips = 'no device connect';
String mac = "";
List<dynamic>? bds;
LabelWidth? labelWidth;
[@override](/user/override)
void initState() {
super.initState();
initBluetooth();
}
Future<void> doPrint({required bool isPrintLabel}) async {
String? isConnected = await BluetoothThermalPrinter.connectionStatus;
if (isConnected == "true" && labelWidth != null) {
int labelHeight = int.tryParse(controllerHeight.text) ?? 100;
int labelGap = int.tryParse(controllerGap.text) ?? 3;
RavPrinter printer = RavPrinter(
heightLabel: labelHeight,
gapLabel: labelGap,
widthLabel: labelWidth!,
);
List<RavTextStyle> texts = [];
texts.add(RavTextStyle(text: "LEFT", align: RavAlign.left));
texts.add(RavTextStyle(text: "CENTER", align: RavAlign.center));
texts.add(RavTextStyle(text: "RIGHT", align: RavAlign.right));
texts.add(RavTextStyle(text: "QRCODE", align: RavAlign.center, isQrCode: true));
texts.add(RavTextStyle(text: "", align: RavAlign.right, lineEnter: 2));
texts.add(RavTextStyle(text: "BARCODE", align: RavAlign.center, isBarCode: true));
if (isPrintLabel) {
await printer.doPrintLabel(
texts: texts,
);
} else {
await printer.doPrintReceipt(
texts: texts,
paperSize: labelWidth == LabelWidth.mm58 ? PaperSize.mm58 : PaperSize.mm80,
);
}
} else {
tips = "Label or bluetooth no connect";
setState(() {});
}
}
Future<void> initBluetooth() async {
bds = await BluetoothThermalPrinter.getBluetooths;
setState(() {});
}
[@override](/user/override)
Widget build(BuildContext context) {
Size size = MediaQuery.sizeOf(context);
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
minimum: EdgeInsets.zero,
child: Column(
children: [
const SizedBox(
height: 20,
),
Text("Information: $tips"),
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
const Divider(),
Container(
width: size.width,
height: 250,
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView.builder(
itemCount: bds?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
title: Text(bds?[index] ?? ""),
subtitle: Text(bds?[index].split("#")[1] ?? ""),
onTap: () async {
setState(() {
mac = bds?[index].split("#")[1] ?? "";
tips = "mac selected $mac";
});
},
trailing: mac != "" && mac == bds?[index].split("#")[1]
? Icon(Icons.check, color: Colors.green)
: null,
);
}),
),
const Divider(),
Text("Select Width"),
Container(
width: size.width,
height: 200,
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView.builder(
itemCount: lw.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(lw[index].screen),
onTap: () async {
setState(() {
labelWidth = lw[index].lw;
});
},
trailing: labelWidth != null && labelWidth == lw[index].lw
? Icon(Icons.check, color: Colors.green)
: null,
);
}),
),
const Divider(),
Text("Label Height (mm)"),
SizedBox(
height: 10,
),
TextField(
controller: controllerHeight,
keyboardType: TextInputType.number,
),
SizedBox(
height: 10,
),
Text("Label Gap (mm)"),
TextField(
controller: controllerGap,
keyboardType: TextInputType.number,
),
SizedBox(
height: 10,
),
const Divider(),
ElevatedButton(
onPressed: _connected
? null
: () async {
String? isConnected = await BluetoothThermalPrinter.connectionStatus;
if (isConnected != "true") {
setState(() {
tips = 'connecting...';
});
String? result = await BluetoothThermalPrinter.connect(mac);
if (result == "true") {
setState(() {
_connected = true;
tips = "Connected";
});
}
} else {
setState(() {
tips = 'please select device';
});
}
},
child: Text("Connect"),
),
ElevatedButton(
onPressed: _connected
? () async {
setState(() {
tips = 'disconnecting...';
});
await BluetoothThermalPrinter.disconnect();
String? res = await BluetoothThermalPrinter.disconnect();
if (res == "true") {
setState(() {
_connected = false;
tips = "Disconnected";
});
}
}
: null,
child: Text("Disconnect"),
),
Divider(),
ElevatedButton(
onPressed: () async {
if (_connected) {
doPrint(isPrintLabel: true);
} else {
setState(() {
tips = "Printer not connect";
});
}
},
child: Text("Print Label"),
),
ElevatedButton(
onPressed: () async {
if (_connected) {
doPrint(isPrintLabel: false);
} else {
setState(() {
tips = "Printer not connect";
});
}
},
child: Text("Print Receipt"),
),
SizedBox(height: 100,)
],
),
),
),
),
],
),
),
);
}
}
代码解释
-
导入必要的库:
import 'package:flutter/material.dart'; import 'package:bluetooth_print/bluetooth_print.dart'; import 'package:bluetooth_thermal_printer_plus/bluetooth_thermal_printer_plus.dart'; import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart'; import 'package:rav_printer/rav_printer.dart';
-
定义主应用类:
void main() { runApp(const MyApp()); }
-
定义应用程序主题和主页面:
class MyApp extends StatelessWidget { const MyApp({super.key}); [@override](/user/override) Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyWidget(), ); } }
-
定义标签宽度列表:
class ListWidth { LabelWidth lw; String screen; ListWidth({ required this.lw, required this.screen, }); }
-
定义状态管理类:
class MyWidget extends StatefulWidget { const MyWidget({super.key}); [@override](/user/override) State<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { BluetoothPrint bluetoothPrint = BluetoothPrint.instance; TextEditingController controllerHeight = TextEditingController(text: "100"); TextEditingController controllerGap = TextEditingController(text: "3"); List<ListWidth> lw = [ ListWidth(lw: LabelWidth.mm40, screen: "40mm"), ListWidth(lw: LabelWidth.mm58, screen: "58mm"), ListWidth(lw: LabelWidth.mm80, screen: "80mm"), ]; bool _connected = false; String tips = 'no device connect'; String mac = ""; List<dynamic>? bds; LabelWidth? labelWidth;
-
初始化蓝牙连接:
[@override](/user/override) void initState() { super.initState(); initBluetooth(); } Future<void> initBluetooth() async { bds = await BluetoothThermalPrinter.getBluetooths; setState(() {}); }
-
打印逻辑:
Future<void> doPrint({required bool isPrintLabel}) async { String? isConnected = await BluetoothThermalPrinter.connectionStatus; if (isConnected == "true" && labelWidth != null) { int labelHeight = int.tryParse(controllerHeight.text) ?? 100; int labelGap = int.tryParse(controllerGap.text) ?? 3; RavPrinter printer = RavPrinter( heightLabel: labelHeight, gapLabel: labelGap, widthLabel: labelWidth!, ); List<RavTextStyle> texts = []; texts.add(RavTextStyle(text: "LEFT", align: RavAlign.left)); texts.add(RavTextStyle(text: "CENTER", align: RavAlign.center)); texts.add(RavTextStyle(text: "RIGHT", align: RavAlign.right)); texts.add(RavTextStyle(text: "QRCODE", align: RavAlign.center, isQrCode: true)); texts.add(RavTextStyle(text: "", align: RavAlign.right, lineEnter: 2)); texts.add(RavTextStyle(text: "BARCODE", align: RavAlign.center, isBarCode: true)); if (isPrintLabel) { await printer.doPrintLabel( texts: texts, ); } else { await printer.doPrintReceipt( texts: texts, paperSize: labelWidth == LabelWidth.mm58 ? PaperSize.mm58 : PaperSize.mm80, ); } } else { tips = "Label or bluetooth no connect"; setState(() {}); } }
-
构建UI界面:
[@override](/user/override) Widget build(BuildContext context) { Size size = MediaQuery.sizeOf(context); return Scaffold( backgroundColor: Colors.white, body: SafeArea( minimum: EdgeInsets.zero, child: Column( children: [ const SizedBox( height: 20, ), Text("Information: $tips"), Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( children: [ const Divider(), Container( width: size.width, height: 250, padding: const EdgeInsets.symmetric(horizontal: 20), child: ListView.builder( itemCount: bds?.length ?? 0, itemBuilder: (context, index) { return ListTile( title: Text(bds?[index] ?? ""), subtitle: Text(bds?[index].split("#")[1] ?? ""), onTap: () async { setState(() { mac = bds?[index].split("#")[1] ?? ""; tips = "mac selected $mac"; }); }, trailing: mac != "" && mac == bds?[index].split("#")[1] ? Icon(Icons.check, color: Colors.green) : null, ); }), ), const Divider(), Text("Select Width"), Container( width: size.width, height: 200, padding: const EdgeInsets.symmetric(horizontal: 20), child: ListView.builder( itemCount: lw.length, itemBuilder: (context, index) { return ListTile( title: Text(lw[index].screen), onTap: () async { setState(() { labelWidth = lw[index].lw; }); }, trailing: labelWidth != null && labelWidth == lw[index].lw ? Icon(Icons.check, color: Colors.green) : null, ); }), ), const Divider(), Text("Label Height (mm)"), SizedBox( height: 10, ), TextField( controller: controllerHeight, keyboardType: TextInputType.number, ), SizedBox( height: 10, ), Text("Label Gap (mm)"), TextField( controller: controllerGap, keyboardType: TextInputType.number, ), SizedBox( height: 10, ), const Divider(), ElevatedButton( onPressed: _connected ? null : () async { String? isConnected = await BluetoothThermalPrinter.connectionStatus; if (isConnected != "true") { setState(() { tips = 'connecting...'; }); String? result = await BluetoothThermalPrinter.connect(mac); if (result == "true") { setState(() { _connected = true; tips = "Connected"; }); } } else { setState(() { tips = 'please select device'; }); } }, child: Text("Connect"), ), ElevatedButton( onPressed: _connected ? () async { setState(() { tips = 'disconnecting...'; }); await BluetoothThermalPrinter.disconnect(); String? res = await BluetoothThermalPrinter.disconnect(); if (res == "true") { setState(() { _connected = false; tips = "Disconnected"; }); } } : null, child: Text("Disconnect"), ), Divider(), ElevatedButton( onPressed: () async { if (_connected) { doPrint(isPrintLabel: true); } else { setState(() { tips = "Printer not connect"; }); } }, child: Text("Print Label"), ), ElevatedButton( onPressed: () async { if (_connected) { doPrint(isPrintLabel: false); } else { setState(() { tips = "Printer not connect"; }); } }, child: Text("Print Receipt"), ), SizedBox(height: 100,) ], ), ), ), ), ], ), ), ); }
更多关于Flutter打印功能插件rav_printer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter打印功能插件rav_printer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter应用中使用rav_printer
插件来实现打印功能的示例代码。rav_printer
是一个用于Flutter的打印插件,支持多种类型的打印机。
1. 添加依赖
首先,你需要在你的pubspec.yaml
文件中添加rav_printer
依赖:
dependencies:
flutter:
sdk: flutter
rav_printer: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
2. 导入插件
在你的Dart文件中导入rav_printer
插件:
import 'package:rav_printer/rav_printer.dart';
3. 初始化打印机
在使用打印机之前,你需要初始化打印机实例。这通常是在应用的某个初始化阶段完成的。
final RavPrinter _printer = RavPrinter();
4. 打印文本
下面是一个简单的示例,展示如何使用rav_printer
打印文本:
void printText() async {
try {
// 打印机配置,可以根据实际情况调整
PrinterConfig config = PrinterConfig(
printerType: PrinterType.bluetooth, // 蓝牙打印机
bluetoothName: '你的蓝牙打印机名称', // 蓝牙打印机名称
bluetoothAddress: '你的蓝牙打印机地址', // 蓝牙打印机地址
// 其他配置参数...
);
// 打印内容
String content = "Hello, Flutter Printing!\nThis is a test.";
// 调用打印方法
await _printer.printText(content, config: config);
print("Print successful!");
} catch (e) {
print("Print failed: $e");
}
}
5. 打印图片
如果需要打印图片,可以使用printImage
方法。这里是一个示例:
void printImage() async {
try {
// 打印机配置
PrinterConfig config = PrinterConfig(
printerType: PrinterType.bluetooth, // 蓝牙打印机
bluetoothName: '你的蓝牙打印机名称', // 蓝牙打印机名称
bluetoothAddress: '你的蓝牙打印机地址', // 蓝牙打印机地址
// 其他配置参数...
);
// 图片路径(可以是本地路径或网络图片URL)
String imagePath = "assets/images/sample.png"; // 本地图片示例
// String imagePath = "https://example.com/sample.png"; // 网络图片示例
// 调用打印方法
await _printer.printImage(imagePath, config: config);
print("Image print successful!");
} catch (e) {
print("Image print failed: $e");
}
}
6. 打印自定义布局
对于更复杂的打印需求,你可以使用printCustom
方法来打印自定义布局。这通常涉及将内容转换为打印机可以理解的格式(如ESC/POS命令)。
void printCustomLayout() async {
try {
// 打印机配置
PrinterConfig config = PrinterConfig(
printerType: PrinterType.bluetooth, // 蓝牙打印机
bluetoothName: '你的蓝牙打印机名称', // 蓝牙打印机名称
bluetoothAddress: '你的蓝牙打印机地址', // 蓝牙打印机地址
// 其他配置参数...
);
// 自定义打印命令(ESC/POS命令示例)
List<int> commands = [
0x1B, 0x40, // 初始化打印机
// 其他ESC/POS命令...
0x0A, // 换行
];
// 调用打印方法
await _printer.printCustom(commands, config: config);
print("Custom layout print successful!");
} catch (e) {
print("Custom layout print failed: $e");
}
}
注意事项
- 权限:确保你的应用有访问蓝牙和其他必要硬件的权限。
- 打印机配置:根据你的打印机类型和配置调整
PrinterConfig
参数。 - 错误处理:在生产环境中,添加适当的错误处理和用户反馈。
这个示例展示了如何使用rav_printer
插件进行基本的打印操作。根据你的具体需求,你可能需要调整配置和打印内容。