如何修改Flutter_Blue读写按钮的界面设计
问题
我需要修改蓝牙设备界面上读写命令的前端样式。目前使用的是pauldemarco仓库中的Flutter_Blue代码,但该设备界面的前端设计不符合我的应用需求,请问如何修改界面上上传、下载信号按钮的设计?
import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_blue/flutter_blue.dart'; import 'widgets.dart'; import 'dart:ui' as ui; import 'package:flutter/rendering.dart'; import 'package:dproject/qrcode.dart'; void main() { // RenderErrorBox.backgroundColor = Colors.transparent; ErrorWidget.builder = (FlutterErrorDetails details) => Scaffold(body:Center(child: Text("Click the Refresh Button"),)); runApp(FlutterBlueApp()); // static ErrorWidgetBuilder builder = _defaultErrorWidgetBuilder; // RenderErrorBox.textStyle = ui.TextStyle(color: Colors.transparent); } class FlutterBlueApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder<BluetoothState>( stream: FlutterBlue.instance.state, initialData: BluetoothState.unknown, builder: (c, snapshot) { final state = snapshot.data; if (state == BluetoothState.on) { return FindDevicesScreen(); } return BluetoothOffScreen(state: state); }), ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.state}) : super(key: key); final BluetoothState? state; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.', // style: Theme.of(context) // .primaryTextTheme // .subhead // ?.copyWith(color: Colors.white), ), ], ), ), ); } } class FindDevicesScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Find Devices'), ), body: RefreshIndicator( onRefresh: () => FlutterBlue.instance.startScan(timeout: Duration(seconds: 8)), child: SingleChildScrollView( child: Column( children: <Widget>[ StreamBuilder<List<BluetoothDevice>>( stream: Stream.periodic(Duration(seconds: 2)) .asyncMap((_) => FlutterBlue.instance.connectedDevices), initialData: [], builder: (c, snapshot) => Column( children: snapshot.data! .map((d) => ListTile( // title: Text(d.toString()), // subtitle: Text(d.id.toString()), trailing: StreamBuilder<BluetoothDeviceState>( stream: d.state, initialData: BluetoothDeviceState.disconnected, builder: (c, snapshot) { if (snapshot.data == BluetoothDeviceState.connected) { return ElevatedButton( child: Text('OPEN'), onPressed: () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => DeviceScreen(device: d))), ); } return Text(snapshot.data.toString()); }, ), )) .toList(), ), ), StreamBuilder<List<ScanResult>>( stream: FlutterBlue.instance.scanResults, initialData: [], builder: (c, snapshot){ List<ScanResult> data = []; // print("sh"); for(int i=0;i<snapshot.data!.length;i++) { // print("sh"); // print(snapshot.data![i]); if(snapshot.data![i].device.id.toString()=='FC:67:78:5D:96:EF'){ data.add(snapshot.data![i]); } } // print(data); return Column( children: data .map( (r) => ScanResultTile( result: r, onTap: () => Navigator.of(context) .push(MaterialPageRoute(builder: (context) { r.device.connect(); return DeviceScreen(device: r.device); //FlutterBlueApp(); })), ), ) .toList(), ); }, ), ], ), ), ), floatingActionButton: StreamBuilder<bool>( stream: FlutterBlue.instance.isScanning, initialData: false, builder: (c, snapshot) { if (snapshot.data!) { return FloatingActionButton( child: Icon(Icons.stop), onPressed: () => FlutterBlue.instance.stopScan(), backgroundColor: Colors.red, ); } else { return FloatingActionButton( child: Icon(Icons.search), onPressed: () => FlutterBlue.instance .startScan(timeout: Duration(seconds: 8))); } }, ), ); } } class DeviceScreen extends StatelessWidget { const DeviceScreen({Key? key, required this.device}) : super(key: key); final BluetoothDevice device; List<int> _getRandomBytes() { final math = Random(); return [ math.nextInt(255), math.nextInt(255), math.nextInt(255), math.nextInt(255) ]; } List<Widget> _buildServiceTiles(List<BluetoothService> services) { List<BluetoothService> data = []; print("sh%%%%%%%%%%%%%%%%%%%%%%@@@@"); for(int i=0;i<services.length;i++) { print("sh####################################"); // print(services[i]); if(i==2){ data.add(services[i]); } } // print(data); return data //services .map( (s) => ServiceTile( service: s, characteristicTiles: s.characteristics .map( (c) => CharacteristicTile( characteristic: c, onReadPressed: () { c.read(); }, onWritePressed: () async { await c.write([1], withoutResponse: false); await c.read(); // ElevatedButton( // // style: style, // onPressed: null, // child: const Text('Disabled'), // ); }, onNotificationPressed: () async { await c.setNotifyValue(!c.isNotifying); await c.read(); }, descriptorTiles: c.descriptors .map( (d) => DescriptorTile( descriptor: d, onReadPressed: () => d.read(), onWritePressed: () => d.write([1]), ), ) .toList(), ), ) .toList(), ), ) .toList(); // print(c.read); } // @override // State<DeviceScreen> createState() => _DeviceScreenState(); // } // class _DeviceScreenState extends State<DeviceScreen> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("BITLOCK"),//device.name actions: <Widget>[ StreamBuilder<BluetoothDeviceState>( stream: device.state, initialData: BluetoothDeviceState.connecting, builder: (c, snapshot) { VoidCallback? onPressed; String text; switch (snapshot.data) { case BluetoothDeviceState.connected: onPressed = () => device.disconnect(); text = 'DISCONNECT'; break; case BluetoothDeviceState.disconnected: onPressed = () => device.connect(); text = 'CONNECT'; break; default: onPressed = null; text = snapshot.data.toString().substring(21).toUpperCase(); break; } return TextButton( onPressed: onPressed, child: Text( text, style: Theme.of(context) .primaryTextTheme .button ?.copyWith(color: Colors.white), )); }, ) ], ), body: SingleChildScrollView( child: Column( children: <Widget>[ StreamBuilder<BluetoothDeviceState>( stream: device.state, initialData: BluetoothDeviceState.connecting, builder: (c, snapshot) => ListTile( leading: (snapshot.data == BluetoothDeviceState.connected) ? Icon(Icons.bluetooth_connected) : Icon(Icons.bluetooth_disabled), title: Text(((){ if(snapshot.data.toString().split('.')[1]=="connected"){ return 'Your Lock is ${snapshot.data.toString().split('.')[1]} to your device.'; } return 'Your Lock is ${snapshot.data.toString().split('.')[1]} from your device.'; })()), // subtitle: Text('${device.id}'), trailing: StreamBuilder<bool>( stream: device.isDiscoveringServices, initialData: false, builder: (c, snapshot) => IndexedStack( index: snapshot.data! ? 1 : 0, children: <Widget>[ IconButton( icon: Icon(Icons.refresh), onPressed: () => device.discoverServices(), ), IconButton( icon: SizedBox( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(Colors.grey), ), width: 18.0, height: 18.0, ), onPressed: null, ) ], ), ), ), ), StreamBuilder<int>( stream: device.mtu, initialData: 0, builder: (c, snapshot) => ListTile( // title: Text('MTU Size'), // subtitle: Text('${snapshot.data} bytes'), trailing: IconButton( icon: Icon(Icons.lock_open), onPressed: () => device.requestMtu(223), ), ), ), StreamBuilder<List<BluetoothService>>( stream: device.services, initialData: [], builder: (c, snapshot) { return Column( children: _buildServiceTiles(snapshot.data!), ); }, ), ], ), ), ); } }

解决方案
要修改读写命令的按钮样式,核心是调整CharacteristicTile组件中的按钮实现——你的代码引用了项目中widgets.dart文件里的CharacteristicTile,直接修改这个组件即可:
定位
CharacteristicTile定义
打开项目中的widgets.dart文件,找到CharacteristicTile类,里面包含了读取、写入按钮的默认实现(通常是IconButton)。替换为自定义按钮样式
将默认按钮替换为符合需求的样式,以下是示例:
修改读取(下载)按钮
// 替换原读取按钮代码 ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.blueAccent, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), onPressed: onReadPressed, child: Row( mainAxisSize: MainAxisSize.min, children: const [ Icon(Icons.download, size: 18), SizedBox(width: 6), Text("读取数据"), ], ), )
修改写入(上传)按钮
// 替换原写入按钮代码 OutlinedButton( style: OutlinedButton.styleFrom( side: BorderSide(color: Colors.green), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), onPressed: onWritePressed, child: Row( mainAxisSize: MainAxisSize.min, children: const [ Icon(Icons.upload, size: 18), SizedBox(width: 6), Text("上传数据"), ], ), )
- 添加状态样式(可选)
如果需要区分按钮禁用/激活状态,可在样式中补充状态配置:
ElevatedButton.styleFrom( backgroundColor: Colors.blueAccent, disabledBackgroundColor: Colors.grey.shade300, disabledForegroundColor: Colors.grey.shade600, )
- 调整按钮布局(可选)
若要改变按钮排列方式,用Row或Wrap包裹按钮并设置间距:
Row( mainAxisAlignment: MainAxisAlignment.end, children: [ // 读取按钮 SizedBox(width: 10), // 写入按钮 ], )
内容的提问来源于stack exchange,提问作者Shailesh Rathod
相关产品推荐
相关产品推荐

