在 _WidgetsAppState 中找不到路由 RouteSettings("todoscreen",'ScreenArguments' 的实例)的生成器。扑
Could not find a generator for route RouteSettings("todoscreen", Instance of 'ScreenArguments') in the _WidgetsAppState. FLUTTER
好吧,这个错误很奇怪的原因是它在我向我的项目添加蓝牙功能之前不存在。如果我不能解决这个问题,作为一个 flutter 初学者,我可能不得不从头开始制作我的应用程序,我花了几周的时间才走到这一步。让我简单描述一下我的应用程序:它是一款配有可穿戴手环的健康应用程序。登录后,系统会提示用户连接到设备,一旦连接,就会返回 HomeScreen(),其中显示了通过蓝牙从 arduino 发送的温度和脉冲数据。目前,pulse 是硬编码的,但温度从传感器发送到应用程序,并更新到 firestore,然后检索和显示。
因此该应用程序同时具有用户界面和管理员界面。
这里是main.dart
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:vitality/screens/btInitialize.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:vitality/screens/welcome.dart';
import 'package:vitality/components/route.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Color(0xff222831),
accentColor: Color(0xff00adb5),
textTheme: TextTheme(
headline1: TextStyle(
fontSize: 25.0, fontFamily: 'Montserrat', color: Colors.black),
headline2: TextStyle(
fontSize: 60.0, fontFamily: 'CrimsonText', color: Colors.black),
headline3: TextStyle(
fontSize: 30.0, fontFamily: 'Lora', color: Colors.white),
headline4: TextStyle(
fontSize: 30.0, fontFamily: 'Montserrat', color: Colors.white),
headline5: TextStyle(
fontSize: 85.0, fontFamily: 'Montserrat', color: Colors.black),
headline6: TextStyle(
fontSize: 20.0, fontFamily: 'Montserrat', color: Colors.white),
),
),
initialRoute: Welcome.id,
onGenerateRoute: RouteGen.generateRoute,
);
}
}
这里是route.dart
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:vitality/screens/login.dart';
import 'package:vitality/screens/homescreen.dart';
import 'package:vitality/screens/chatbot.dart';
import 'package:vitality/screens/todo.dart';
import 'package:vitality/screens/welcome.dart';
import 'package:vitality/screens/register.dart';
import 'package:vitality/components/ScreenArguments.dart';
import 'package:vitality/screens/btInitialize.dart';
import 'package:vitality/components/HomeArguments.dart';
class RouteGen {
static Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
case btInit.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as ScreenArguments;
return btInit(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
);
});
case Welcome.id:
return MaterialPageRoute(builder: (_) => Welcome());
case HomeScreen.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as HomeArgs;
return HomeScreen(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
currentDevice: argument.currentDevice);
});
case LoginScreen.id:
return MaterialPageRoute(builder: (_) => LoginScreen());
case Register.id:
return MaterialPageRoute(builder: (_) => Register());
case ChatBot.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as ScreenArguments;
return ChatBot(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
);
});
case Todo.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as ScreenArguments;
return Todo(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
);
});
}
}
}
因为我必须传递多个参数,所以我有一个屏幕参数 class 在屏幕之间传递 docid 和 isCaregiver (bool)。第一个主屏幕需要传递一个设备参数,所以我只为家里做了一个不同的 class。
他们在这里
class ScreenArguments {
final String docid;
final bool isCaretaker;
ScreenArguments({this.docid, this.isCaretaker});
}
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class HomeArgs {
final String docid;
final bool isCaretaker;
final BluetoothDevice currentDevice;
HomeArgs({this.docid, this.isCaretaker, this.currentDevice});
}
当按下登录按钮时,这是它转到的屏幕
btinitialize.dart
import 'package:flutter/material.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:vitality/screens/connection.dart';
import 'package:vitality/screens/homescreen.dart';
class btInit extends StatelessWidget {
final String docid;
final bool isCaretaker;
static const String id = 'btinit';
btInit({@required this.docid, @required this.isCaretaker});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: FutureBuilder(
future: FlutterBluetoothSerial.instance.requestEnable(),
builder: (context, future) {
if (future.connectionState == ConnectionState.waiting) {
return Scaffold(
body: Container(
height: double.infinity,
child: Center(
child: Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.blue,
),
),
),
);
} else if (future.connectionState == ConnectionState.done) {
print('bluetooth turned on');
// return MyHomePage(title: 'Flutter Demo Home Page');
return Home(docid: docid, isCaretaker: isCaretaker);
} else {
return Home(docid: docid, isCaretaker: isCaretaker);
}
},
// child: MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
class Home extends StatelessWidget {
final String docid;
final bool isCaretaker;
Home({this.docid, this.isCaretaker});
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
toolbarHeight: 50.0,
centerTitle: true,
title: Text(
'HEALTH TRACKER',
style: Theme.of(context).textTheme.headline4,
)),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://www.setaswall.com/wp-content/uploads/2017/06/Blur-Phone-Wallpaper-1080x2340-011-340x550.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(.7), BlendMode.dstATop),
)),
child: SelectBondedDevicePage(
Upload: (device1) {
BluetoothDevice device = device1;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return HomeScreen(
docid: docid,
isCaretaker: isCaretaker,
currentDevice: device,
);
},
),
);
},
),
),
));
}
}
首先它要求用户打开蓝牙。然后它 returns class SELECTBONDEDDEVICEPAGE 哪个是设备和一个按钮,按下该按钮将带您到主屏幕。
connection.dart
该页面是发现设备的代码。这里UI东西不多
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
enum _DeviceAvailability {
maybe,
yes,
}
class _DeviceWithAvailability extends BluetoothDevice {
BluetoothDevice device;
_DeviceAvailability availability;
int rssi;
_DeviceWithAvailability(this.device, this.availability, [this.rssi]);
}
class SelectBondedDevicePage extends StatefulWidget {
final bool checkAvailability;
final Function Upload;
final String docid;
final bool isCaretaker;
static const String id = 'connect';
const SelectBondedDevicePage(
{this.checkAvailability = true,
this.Upload,
this.docid,
this.isCaretaker});
@override
_SelectBondedDevicePage createState() => new _SelectBondedDevicePage();
}
class _SelectBondedDevicePage extends State<SelectBondedDevicePage> {
List<_DeviceWithAvailability> devices = List<_DeviceWithAvailability>();
// Availability
StreamSubscription<BluetoothDiscoveryResult> _discoveryStreamSubscription;
bool _isDiscovering;
_SelectBondedDevicePage();
@override
void initState() {
super.initState();
_isDiscovering = widget.checkAvailability;
if (_isDiscovering) {
_startDiscovery();
}
// Setup a list of the bonded devices
FlutterBluetoothSerial.instance
.getBondedDevices()
.then((List<BluetoothDevice> bondedDevices) {
setState(() {
devices = bondedDevices
.map(
(device) => _DeviceWithAvailability(
device,
widget.checkAvailability
? _DeviceAvailability.maybe
: _DeviceAvailability.yes,
),
)
.toList();
});
});
}
void _startDiscovery() {
_discoveryStreamSubscription =
FlutterBluetoothSerial.instance.startDiscovery().listen((r) {
setState(() {
Iterator i = devices.iterator;
while (i.moveNext()) {
var _device = i.current;
if (_device.device == r.device) {
_device.availability = _DeviceAvailability.yes;
_device.rssi = r.rssi;
}
}
});
});
_discoveryStreamSubscription.onDone(() {
setState(() {
_isDiscovering = false;
});
});
}
@override
void dispose() {
// Avoid memory leak (`setState` after dispose) and cancel discovery
_discoveryStreamSubscription?.cancel();
super.dispose();
}
//build returns list of bletooth devices entries (name, and connect button) with an on tap method Upload()
@override
Widget build(BuildContext context) {
List<BluetoothDeviceListEntry> list = devices
.map(
(_device) => BluetoothDeviceListEntry(
device: _device.device,
onTap: () {
widget.Upload(_device.device);
},
),
)
.toList();
return ListView(
children: list,
);
}
}
class BluetoothDeviceListEntry extends StatelessWidget {
final Function onTap;
final BluetoothDevice device;
BluetoothDeviceListEntry({this.onTap, @required this.device});
@override
Widget build(BuildContext context) {
return ListTile(
onTap: onTap,
leading: Icon(Icons.devices),
title: Text(device.name ?? "Unknown device"),
subtitle: Text(device.address.toString()),
trailing: FlatButton(
child: Text('Connect'),
onPressed: onTap,
color: Colors.transparent,
),
);
}
}
最后,当按下按钮时,它会进入带有参数 docid、isCaretaker 和 hte 设备的主屏幕。
homescreen.dart
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:typed_data';
import 'package:vitality/components/bottomAppBar.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:vitality/components/biom.dart';
import 'package:flutter_phone_direct_caller/flutter_phone_direct_caller.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class HomeScreen extends StatefulWidget {
static const String id = 'home_screen';
final String docid;
final bool isCaretaker;
final BluetoothDevice currentDevice;
HomeScreen(
{@required this.docid,
@required this.isCaretaker,
@required this.currentDevice});
@override
_HomeScreenState createState() => _HomeScreenState();
}
_callNumber() async {
const number = '8606535166'; //set the number here
bool res = await FlutterPhoneDirectCaller.callNumber(number);
}
class _HomeScreenState extends State<HomeScreen> {
final auth = FirebaseAuth.instance;
var pulse;
var temp;
static final clientID = 0;
BluetoothConnection connection;
String _messageBuffer = '';
bool isConnecting = true;
bool get isConnected => connection != null && connection.isConnected;
bool isDisconnecting = false;
@override
void initState() {
super.initState();
BluetoothConnection.toAddress(widget.currentDevice.address)
.then((_connection) {
print('Connected to the device');
print('device is ${widget.currentDevice}');
connection = _connection;
setState(() {
isConnecting = false;
isDisconnecting = false;
});
connection.input.listen(_onDataReceived).onDone(() {
if (isDisconnecting) {
print('Disconnecting locally!');
} else {
print('Disconnected remotely!');
}
if (this.mounted) {
setState(() {});
}
});
}).catchError((error) {
print('Cannot connect, exception occurred');
print(error);
});
}
@override
void dispose() {
// Avoid memory leak (`setState` after dispose) and disconnect
if (isConnected) {
isDisconnecting = true;
connection.dispose();
connection = null;
}
super.dispose();
}
void _onDataReceived(Uint8List data) {
// Allocate buffer for parsed data
int backspacesCounter = 0;
data.forEach((byte) {
if (byte == 8 || byte == 127) {
backspacesCounter++;
}
});
Uint8List buffer = Uint8List(data.length - backspacesCounter);
int bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
String dataString = String.fromCharCodes(buffer);
print('$dataString');
changePulse(int.parse(dataString));
int index = buffer.indexOf(13);
if (~index != 0) {
setState(() {
_messageBuffer = dataString.substring(index);
//print('In message buffer is $_messageBuffer');
});
} else {
_messageBuffer = (backspacesCounter > 0
? _messageBuffer.substring(
0, _messageBuffer.length - backspacesCounter)
: _messageBuffer + dataString);
}
}
void _sendMessage(String text) async {
text = text.trim();
if (text.length > 0) {
try {
connection.output.add(utf8.encode(text + "\r\n"));
await connection.output.allSent;
} catch (e) {
// Ignore error, but notify state
setState(() {});
}
}
}
changePulse(int dataString) {
main
.doc(widget.docid)
.update({'pulse': dataString})
.then((value) => print("User Updated"))
.catchError((error) => print("Failed to update user: $error"));
}
@override
Widget build(BuildContext context) {
print(
'in homescreen each iis ${widget.docid}, ${widget.isCaretaker},${widget.currentDevice}');
_sendMessage('1');
print('got here');
CollectionReference main = FirebaseFirestore.instance.collection('maindb');
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
toolbarHeight: 50.0,
centerTitle: true,
title: Text(
'HEALTH TRACKER',
style: Theme.of(context).textTheme.headline4,
)),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://www.setaswall.com/wp-content/uploads/2017/06/Blur-Phone-Wallpaper-1080x2340-011-340x550.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(.7), BlendMode.dstATop),
)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(height: 100.0),
Text(widget.docid),
Text({widget.isCaretaker}.toString()),
biom(which: 'pulse', image: 'pulse', docid: widget.docid),
RoundBorderText(text: 'PULSE'),
biom(which: 'temperature', image: 'temper', docid: widget.docid),
RoundBorderText(text: 'TEMPERATURE'),
SizedBox(height: 30.0),
FlatButton(
child: Text('test call'),
onPressed: () async {
_callNumber();
})
]),
),
**bottomNavigationBar**: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://www.setaswall.com/wp-content/uploads/2017/06/Blur-Phone-Wallpaper-1080x2340-011-340x550.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(1), BlendMode.dstATop),
)),
child: bottomAppBar()),
);
}
}
class RoundBorderText extends StatelessWidget {
final String text;
RoundBorderText({this.text});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(
left: 40.0, right: 40.0, top: 8.0, bottom: 8.0),
decoration: BoxDecoration(
// ),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Text(text, style: Theme.of(context).textTheme.headline1));
}
}
基本上,当它从 arduino 接收到数据时,它会将它添加到 firestore 并在屏幕上显示它。
底部是一个 bottomappbar,我将其提取到 class.
问题出在这里。
import 'package:flutter/material.dart';
import 'package:vitality/screens/login.dart';
import 'package:vitality/components/ScreenArguments.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class bottomAppBar extends StatefulWidget {
final String id;
bottomAppBar({this.id});
@override
_bottomAppBarState createState() => _bottomAppBarState();
}
class _bottomAppBarState extends State<bottomAppBar> {
@override
Widget build(BuildContext context) {
print('id in bottom is ${widget.id}');
return BottomAppBar(
color: Colors.transparent,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: Icon(Icons.list),
color: Colors.white,
onPressed: () {
print('to do pressed');
print(docid);
print(isCaretaker.toString());
Navigator.of(context).pushNamed('todoscreen',
arguments: ScreenArguments(
docid: docid, isCaretaker: isCaretaker));
}),
IconButton(
icon: Icon(Icons.data_usage),
color: Colors.white,
onPressed: () {
Navigator.of(context).pushNamed('home_screen',
arguments: ScreenArguments(
docid: widget.id, isCaretaker: isCaretaker));
}),
IconButton(
icon: Icon(Icons.chat),
color: Colors.white,
onPressed: () {
Navigator.of(context).pushNamed('chat_screen',
arguments: ScreenArguments(
docid: widget.id, isCaretaker: isCaretaker));
}),
],
),
);
}
}
底部栏由 3 个图标组成,一个提醒图标,一个主屏幕和一个聊天机器人。我们目前在主屏幕上,但是当按下待办事项图标时,它应该会转到该屏幕。这在我将其放入蓝牙代码之前有效,但现在我收到此错误:
无法在 _WidgetsAppState 中找到路由 RouteSettings(“chat_screen”,'ScreenArguments' 的实例)的生成器。
对于待办事项屏幕和聊天屏幕。
此处 todo.dart 代码只是为了让您可以看到它已使用必要的参数进行了初始化
bool temp;
var todoid;
int number = 0;
final auth = FirebaseAuth.instance;
Stream collectionStream =
FirebaseFirestore.instance.collection('todo').snapshots();
CollectionReference main = FirebaseFirestore.instance.collection('maindb');
CollectionReference todo = FirebaseFirestore.instance.collection('todo');
final myController = TextEditingController();
class Todo extends StatefulWidget {
final String docid;
final bool isCaretaker;
Todo({this.docid, this.isCaretaker});
@override
_TodoState createState() => _TodoState();
static const String id = 'todoscreen';
}
任何帮助将不胜感激,因为我完全不知道出了什么问题。 (蓝牙代码有效)
在使用 Navigator.of(context)
时,Flutter 遍历 widget 树中的祖先以找到最近的 Navigator
.
现在,您实际上并没有在树中特别提供任何 Navigator
小部件,那么您的 Navigator
来自哪里?
那就是 MaterialApp
。
现在,您的主 MaterialApp
位于根目录。
但是如果您检查 btInit
小部件,您已经在其中声明了另一个 MaterialApp
。因此,当您调用 pushNamed('todoscreen')
时,它实际上是从 btInit
小部件的 MaterialApp
获取 Navigator
而不是主小部件。
因为您只在主 MaterialApp
上定义了 onGenerateRoute
,它无法解析对 todoscreen
路由名称的请求。
删除 btInit
小部件中的 MaterialApp
,这应该可以解决。
好吧,这个错误很奇怪的原因是它在我向我的项目添加蓝牙功能之前不存在。如果我不能解决这个问题,作为一个 flutter 初学者,我可能不得不从头开始制作我的应用程序,我花了几周的时间才走到这一步。让我简单描述一下我的应用程序:它是一款配有可穿戴手环的健康应用程序。登录后,系统会提示用户连接到设备,一旦连接,就会返回 HomeScreen(),其中显示了通过蓝牙从 arduino 发送的温度和脉冲数据。目前,pulse 是硬编码的,但温度从传感器发送到应用程序,并更新到 firestore,然后检索和显示。 因此该应用程序同时具有用户界面和管理员界面。
这里是main.dart
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:vitality/screens/btInitialize.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:vitality/screens/welcome.dart';
import 'package:vitality/components/route.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Color(0xff222831),
accentColor: Color(0xff00adb5),
textTheme: TextTheme(
headline1: TextStyle(
fontSize: 25.0, fontFamily: 'Montserrat', color: Colors.black),
headline2: TextStyle(
fontSize: 60.0, fontFamily: 'CrimsonText', color: Colors.black),
headline3: TextStyle(
fontSize: 30.0, fontFamily: 'Lora', color: Colors.white),
headline4: TextStyle(
fontSize: 30.0, fontFamily: 'Montserrat', color: Colors.white),
headline5: TextStyle(
fontSize: 85.0, fontFamily: 'Montserrat', color: Colors.black),
headline6: TextStyle(
fontSize: 20.0, fontFamily: 'Montserrat', color: Colors.white),
),
),
initialRoute: Welcome.id,
onGenerateRoute: RouteGen.generateRoute,
);
}
}
这里是route.dart
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:vitality/screens/login.dart';
import 'package:vitality/screens/homescreen.dart';
import 'package:vitality/screens/chatbot.dart';
import 'package:vitality/screens/todo.dart';
import 'package:vitality/screens/welcome.dart';
import 'package:vitality/screens/register.dart';
import 'package:vitality/components/ScreenArguments.dart';
import 'package:vitality/screens/btInitialize.dart';
import 'package:vitality/components/HomeArguments.dart';
class RouteGen {
static Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
case btInit.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as ScreenArguments;
return btInit(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
);
});
case Welcome.id:
return MaterialPageRoute(builder: (_) => Welcome());
case HomeScreen.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as HomeArgs;
return HomeScreen(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
currentDevice: argument.currentDevice);
});
case LoginScreen.id:
return MaterialPageRoute(builder: (_) => LoginScreen());
case Register.id:
return MaterialPageRoute(builder: (_) => Register());
case ChatBot.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as ScreenArguments;
return ChatBot(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
);
});
case Todo.id:
return MaterialPageRoute(builder: (BuildContext context) {
final argument = args as ScreenArguments;
return Todo(
docid: argument.docid,
isCaretaker: argument.isCaretaker,
);
});
}
}
}
因为我必须传递多个参数,所以我有一个屏幕参数 class 在屏幕之间传递 docid 和 isCaregiver (bool)。第一个主屏幕需要传递一个设备参数,所以我只为家里做了一个不同的 class。 他们在这里
class ScreenArguments {
final String docid;
final bool isCaretaker;
ScreenArguments({this.docid, this.isCaretaker});
}
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class HomeArgs {
final String docid;
final bool isCaretaker;
final BluetoothDevice currentDevice;
HomeArgs({this.docid, this.isCaretaker, this.currentDevice});
}
当按下登录按钮时,这是它转到的屏幕 btinitialize.dart
import 'package:flutter/material.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:vitality/screens/connection.dart';
import 'package:vitality/screens/homescreen.dart';
class btInit extends StatelessWidget {
final String docid;
final bool isCaretaker;
static const String id = 'btinit';
btInit({@required this.docid, @required this.isCaretaker});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: FutureBuilder(
future: FlutterBluetoothSerial.instance.requestEnable(),
builder: (context, future) {
if (future.connectionState == ConnectionState.waiting) {
return Scaffold(
body: Container(
height: double.infinity,
child: Center(
child: Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.blue,
),
),
),
);
} else if (future.connectionState == ConnectionState.done) {
print('bluetooth turned on');
// return MyHomePage(title: 'Flutter Demo Home Page');
return Home(docid: docid, isCaretaker: isCaretaker);
} else {
return Home(docid: docid, isCaretaker: isCaretaker);
}
},
// child: MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
class Home extends StatelessWidget {
final String docid;
final bool isCaretaker;
Home({this.docid, this.isCaretaker});
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
toolbarHeight: 50.0,
centerTitle: true,
title: Text(
'HEALTH TRACKER',
style: Theme.of(context).textTheme.headline4,
)),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://www.setaswall.com/wp-content/uploads/2017/06/Blur-Phone-Wallpaper-1080x2340-011-340x550.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(.7), BlendMode.dstATop),
)),
child: SelectBondedDevicePage(
Upload: (device1) {
BluetoothDevice device = device1;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return HomeScreen(
docid: docid,
isCaretaker: isCaretaker,
currentDevice: device,
);
},
),
);
},
),
),
));
}
}
首先它要求用户打开蓝牙。然后它 returns class SELECTBONDEDDEVICEPAGE 哪个是设备和一个按钮,按下该按钮将带您到主屏幕。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
enum _DeviceAvailability {
maybe,
yes,
}
class _DeviceWithAvailability extends BluetoothDevice {
BluetoothDevice device;
_DeviceAvailability availability;
int rssi;
_DeviceWithAvailability(this.device, this.availability, [this.rssi]);
}
class SelectBondedDevicePage extends StatefulWidget {
final bool checkAvailability;
final Function Upload;
final String docid;
final bool isCaretaker;
static const String id = 'connect';
const SelectBondedDevicePage(
{this.checkAvailability = true,
this.Upload,
this.docid,
this.isCaretaker});
@override
_SelectBondedDevicePage createState() => new _SelectBondedDevicePage();
}
class _SelectBondedDevicePage extends State<SelectBondedDevicePage> {
List<_DeviceWithAvailability> devices = List<_DeviceWithAvailability>();
// Availability
StreamSubscription<BluetoothDiscoveryResult> _discoveryStreamSubscription;
bool _isDiscovering;
_SelectBondedDevicePage();
@override
void initState() {
super.initState();
_isDiscovering = widget.checkAvailability;
if (_isDiscovering) {
_startDiscovery();
}
// Setup a list of the bonded devices
FlutterBluetoothSerial.instance
.getBondedDevices()
.then((List<BluetoothDevice> bondedDevices) {
setState(() {
devices = bondedDevices
.map(
(device) => _DeviceWithAvailability(
device,
widget.checkAvailability
? _DeviceAvailability.maybe
: _DeviceAvailability.yes,
),
)
.toList();
});
});
}
void _startDiscovery() {
_discoveryStreamSubscription =
FlutterBluetoothSerial.instance.startDiscovery().listen((r) {
setState(() {
Iterator i = devices.iterator;
while (i.moveNext()) {
var _device = i.current;
if (_device.device == r.device) {
_device.availability = _DeviceAvailability.yes;
_device.rssi = r.rssi;
}
}
});
});
_discoveryStreamSubscription.onDone(() {
setState(() {
_isDiscovering = false;
});
});
}
@override
void dispose() {
// Avoid memory leak (`setState` after dispose) and cancel discovery
_discoveryStreamSubscription?.cancel();
super.dispose();
}
//build returns list of bletooth devices entries (name, and connect button) with an on tap method Upload()
@override
Widget build(BuildContext context) {
List<BluetoothDeviceListEntry> list = devices
.map(
(_device) => BluetoothDeviceListEntry(
device: _device.device,
onTap: () {
widget.Upload(_device.device);
},
),
)
.toList();
return ListView(
children: list,
);
}
}
class BluetoothDeviceListEntry extends StatelessWidget {
final Function onTap;
final BluetoothDevice device;
BluetoothDeviceListEntry({this.onTap, @required this.device});
@override
Widget build(BuildContext context) {
return ListTile(
onTap: onTap,
leading: Icon(Icons.devices),
title: Text(device.name ?? "Unknown device"),
subtitle: Text(device.address.toString()),
trailing: FlatButton(
child: Text('Connect'),
onPressed: onTap,
color: Colors.transparent,
),
);
}
}
最后,当按下按钮时,它会进入带有参数 docid、isCaretaker 和 hte 设备的主屏幕。
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:typed_data';
import 'package:vitality/components/bottomAppBar.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:vitality/components/biom.dart';
import 'package:flutter_phone_direct_caller/flutter_phone_direct_caller.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class HomeScreen extends StatefulWidget {
static const String id = 'home_screen';
final String docid;
final bool isCaretaker;
final BluetoothDevice currentDevice;
HomeScreen(
{@required this.docid,
@required this.isCaretaker,
@required this.currentDevice});
@override
_HomeScreenState createState() => _HomeScreenState();
}
_callNumber() async {
const number = '8606535166'; //set the number here
bool res = await FlutterPhoneDirectCaller.callNumber(number);
}
class _HomeScreenState extends State<HomeScreen> {
final auth = FirebaseAuth.instance;
var pulse;
var temp;
static final clientID = 0;
BluetoothConnection connection;
String _messageBuffer = '';
bool isConnecting = true;
bool get isConnected => connection != null && connection.isConnected;
bool isDisconnecting = false;
@override
void initState() {
super.initState();
BluetoothConnection.toAddress(widget.currentDevice.address)
.then((_connection) {
print('Connected to the device');
print('device is ${widget.currentDevice}');
connection = _connection;
setState(() {
isConnecting = false;
isDisconnecting = false;
});
connection.input.listen(_onDataReceived).onDone(() {
if (isDisconnecting) {
print('Disconnecting locally!');
} else {
print('Disconnected remotely!');
}
if (this.mounted) {
setState(() {});
}
});
}).catchError((error) {
print('Cannot connect, exception occurred');
print(error);
});
}
@override
void dispose() {
// Avoid memory leak (`setState` after dispose) and disconnect
if (isConnected) {
isDisconnecting = true;
connection.dispose();
connection = null;
}
super.dispose();
}
void _onDataReceived(Uint8List data) {
// Allocate buffer for parsed data
int backspacesCounter = 0;
data.forEach((byte) {
if (byte == 8 || byte == 127) {
backspacesCounter++;
}
});
Uint8List buffer = Uint8List(data.length - backspacesCounter);
int bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
String dataString = String.fromCharCodes(buffer);
print('$dataString');
changePulse(int.parse(dataString));
int index = buffer.indexOf(13);
if (~index != 0) {
setState(() {
_messageBuffer = dataString.substring(index);
//print('In message buffer is $_messageBuffer');
});
} else {
_messageBuffer = (backspacesCounter > 0
? _messageBuffer.substring(
0, _messageBuffer.length - backspacesCounter)
: _messageBuffer + dataString);
}
}
void _sendMessage(String text) async {
text = text.trim();
if (text.length > 0) {
try {
connection.output.add(utf8.encode(text + "\r\n"));
await connection.output.allSent;
} catch (e) {
// Ignore error, but notify state
setState(() {});
}
}
}
changePulse(int dataString) {
main
.doc(widget.docid)
.update({'pulse': dataString})
.then((value) => print("User Updated"))
.catchError((error) => print("Failed to update user: $error"));
}
@override
Widget build(BuildContext context) {
print(
'in homescreen each iis ${widget.docid}, ${widget.isCaretaker},${widget.currentDevice}');
_sendMessage('1');
print('got here');
CollectionReference main = FirebaseFirestore.instance.collection('maindb');
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
toolbarHeight: 50.0,
centerTitle: true,
title: Text(
'HEALTH TRACKER',
style: Theme.of(context).textTheme.headline4,
)),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://www.setaswall.com/wp-content/uploads/2017/06/Blur-Phone-Wallpaper-1080x2340-011-340x550.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(.7), BlendMode.dstATop),
)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(height: 100.0),
Text(widget.docid),
Text({widget.isCaretaker}.toString()),
biom(which: 'pulse', image: 'pulse', docid: widget.docid),
RoundBorderText(text: 'PULSE'),
biom(which: 'temperature', image: 'temper', docid: widget.docid),
RoundBorderText(text: 'TEMPERATURE'),
SizedBox(height: 30.0),
FlatButton(
child: Text('test call'),
onPressed: () async {
_callNumber();
})
]),
),
**bottomNavigationBar**: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://www.setaswall.com/wp-content/uploads/2017/06/Blur-Phone-Wallpaper-1080x2340-011-340x550.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(1), BlendMode.dstATop),
)),
child: bottomAppBar()),
);
}
}
class RoundBorderText extends StatelessWidget {
final String text;
RoundBorderText({this.text});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(
left: 40.0, right: 40.0, top: 8.0, bottom: 8.0),
decoration: BoxDecoration(
// ),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Text(text, style: Theme.of(context).textTheme.headline1));
}
}
基本上,当它从 arduino 接收到数据时,它会将它添加到 firestore 并在屏幕上显示它。 底部是一个 bottomappbar,我将其提取到 class.
问题出在这里。
import 'package:flutter/material.dart';
import 'package:vitality/screens/login.dart';
import 'package:vitality/components/ScreenArguments.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class bottomAppBar extends StatefulWidget {
final String id;
bottomAppBar({this.id});
@override
_bottomAppBarState createState() => _bottomAppBarState();
}
class _bottomAppBarState extends State<bottomAppBar> {
@override
Widget build(BuildContext context) {
print('id in bottom is ${widget.id}');
return BottomAppBar(
color: Colors.transparent,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: Icon(Icons.list),
color: Colors.white,
onPressed: () {
print('to do pressed');
print(docid);
print(isCaretaker.toString());
Navigator.of(context).pushNamed('todoscreen',
arguments: ScreenArguments(
docid: docid, isCaretaker: isCaretaker));
}),
IconButton(
icon: Icon(Icons.data_usage),
color: Colors.white,
onPressed: () {
Navigator.of(context).pushNamed('home_screen',
arguments: ScreenArguments(
docid: widget.id, isCaretaker: isCaretaker));
}),
IconButton(
icon: Icon(Icons.chat),
color: Colors.white,
onPressed: () {
Navigator.of(context).pushNamed('chat_screen',
arguments: ScreenArguments(
docid: widget.id, isCaretaker: isCaretaker));
}),
],
),
);
}
}
底部栏由 3 个图标组成,一个提醒图标,一个主屏幕和一个聊天机器人。我们目前在主屏幕上,但是当按下待办事项图标时,它应该会转到该屏幕。这在我将其放入蓝牙代码之前有效,但现在我收到此错误:
无法在 _WidgetsAppState 中找到路由 RouteSettings(“chat_screen”,'ScreenArguments' 的实例)的生成器。
对于待办事项屏幕和聊天屏幕。
此处 todo.dart 代码只是为了让您可以看到它已使用必要的参数进行了初始化
bool temp;
var todoid;
int number = 0;
final auth = FirebaseAuth.instance;
Stream collectionStream =
FirebaseFirestore.instance.collection('todo').snapshots();
CollectionReference main = FirebaseFirestore.instance.collection('maindb');
CollectionReference todo = FirebaseFirestore.instance.collection('todo');
final myController = TextEditingController();
class Todo extends StatefulWidget {
final String docid;
final bool isCaretaker;
Todo({this.docid, this.isCaretaker});
@override
_TodoState createState() => _TodoState();
static const String id = 'todoscreen';
}
任何帮助将不胜感激,因为我完全不知道出了什么问题。 (蓝牙代码有效)
在使用 Navigator.of(context)
时,Flutter 遍历 widget 树中的祖先以找到最近的 Navigator
.
现在,您实际上并没有在树中特别提供任何 Navigator
小部件,那么您的 Navigator
来自哪里?
那就是 MaterialApp
。
现在,您的主 MaterialApp
位于根目录。
但是如果您检查 btInit
小部件,您已经在其中声明了另一个 MaterialApp
。因此,当您调用 pushNamed('todoscreen')
时,它实际上是从 btInit
小部件的 MaterialApp
获取 Navigator
而不是主小部件。
因为您只在主 MaterialApp
上定义了 onGenerateRoute
,它无法解析对 todoscreen
路由名称的请求。
删除 btInit
小部件中的 MaterialApp
,这应该可以解决。