【发布时间】:2021-05-18 09:17:16
【问题描述】:
我正在使用 Provider 学习 Flutter 并尝试制作 CRUD 模型。我已经完成了创建部分、读取部分和删除部分,但是在模型的更新部分中遇到了困难。我进行了读取和显示数据的 API 调用,创建了一个创建新对象的方法和一个用于删除对象的方法,但剩下的就是修改/编辑对象。这是我到目前为止所做的代码:
调用 API 的车辆列表:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/vehicle.dart';
import 'screens/vehicle_details_screen.dart';
import 'services/vehicle_api.dart';
import 'models/vehicle_data_provider.dart';
class VehicleList extends StatefulWidget {
@override
_VehicleList createState() => _VehicleList();
}
class _VehicleList extends State<VehicleList> {
_getPosts() async {
var provider = Provider.of<HomePageProvider>(context, listen: false);
var postsResponse = await fetchVehicles();
if (postsResponse.isSuccessful) {
provider.setPostsList(postsResponse.data, notify: false);
} else {
provider.mergePostsList(postsResponse.data, notify: false);
}
provider.setIsHomePageProcessing(false);
}
@override
void initState() {
super.initState();
_getPosts();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Consumer<HomePageProvider>(
builder: (context, vehicleData, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
height: 12.0,
),
Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.all(
Radius.circular(12.0),
),
),
child: SingleChildScrollView(
child: DataTable(
columnSpacing: 50,
columns: <DataColumn>[
DataColumn(
label: Text(
'Friendly Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Licence Plate',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Delete',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(
vehicleData.postsList.length,
(index) {
VehicleData post = vehicleData.getPostByIndex(index);
return DataRow(
cells: <DataCell>[
DataCell(
Text('${post.friendlyName}'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
VehicleDetailsScreen(
color: post.color,
friendlyName: post.friendlyName,
licencePlate: post.licencePlate,
)));
},
),
DataCell(
Text('${post.licencePlate}'),
),
DataCell(
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
vehicleData.deletePost(post);
},
),
// onTap: vehicleData.deletePost(post),
),
],
);
},
),
),
),
),
],
);
},
),
],
);
}
}
车辆详情屏幕
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/vehicle.dart';
import 'models/vehicle_data_provider.dart';
class VehicleDetailsScreen extends StatefulWidget {
static const String id = 'vehicle_details_screen';
final vehicleList;
String color, friendlyName, licencePlate;
VehicleDetailsScreen(
{this.vehicleList, this.color, this.friendlyName, this.licencePlate});
@override
_VehicleDetailsScreenState createState() => _VehicleDetailsScreenState();
}
class _VehicleDetailsScreenState extends State<VehicleDetailsScreen> {
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
String color, friendlyName, licencePlate;
final TextEditingController _controllerfriendlyName = TextEditingController();
final TextEditingController _controllerlicencePlate = TextEditingController();
final TextEditingController _controllerColor = TextEditingController();
@override
void initState() {
super.initState();
setState(() {
_controllerColor.text = widget.color;
_controllerfriendlyName.text = widget.friendlyName;
_controllerlicencePlate.text = widget.licencePlate;
});
}
@override
void dispose() {
_controllerColor.dispose();
_controllerfriendlyName.dispose();
_controllerlicencePlate.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final myProvider = Provider.of<HomePageProvider>(context);
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white,
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0),
topRight: Radius.circular(20.0),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Vehicle Details',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30.0,
color: Colors.grey,
),
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 400,
child: Form(
key: _formKey,
child: new ListView(
shrinkWrap: true,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
children: <Widget>[
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter friendly name';
}
return null;
},
controller: _controllerColor,
onSaved: (value) {
color = value;
},
decoration: const InputDecoration(
icon: Icon(Icons.directions_car),
hintText: 'Enter friendly car name',
labelText: 'Name',
),
keyboardType: TextInputType.datetime,
),
TextFormField(
onSaved: (value) {
friendlyName = value;
},
controller: _controllerfriendlyName,
validator: (value) {
if (value.isEmpty) {
return 'Please enter vehicle model';
}
return null;
},
decoration: const InputDecoration(
icon: Icon(Icons.directions_car_outlined),
hintText: 'Enter vehicle model',
labelText: 'Model',
),
keyboardType: TextInputType.phone,
),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
controller: _controllerlicencePlate,
onSaved: (value) {
licencePlate = value;
},
decoration: const InputDecoration(
icon: Icon(Icons.calendar_today),
hintText: 'Enter manufactured year',
labelText: 'Year',
),
keyboardType: TextInputType.emailAddress,
),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlatButton(
child: Text(
'Cancel',
style: TextStyle(
color: Colors.white,
),
),
color: Colors.grey,
onPressed: () {
Navigator.pop(context);
},
),
SizedBox(
width: 10,
),
FlatButton(
child: Text(
'Edit',
style: TextStyle(
color: Colors.white,
),
),
color: Colors.grey,
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
////The method bellow updateList ()needs to be changed in order to modify the existing list, this method just creates a new one.
await myProvider.updateList(VehicleData(
friendlyName: friendlyName.toString(),
color: color.toString(),
licencePlate: licencePlate.toString(),
));
Navigator.of(context).pop();
}
},
),
],
),
],
),
),
),
);
}
}
这里是 HomePageProvider 模型:
import 'package:flutter/foundation.dart';
import 'models/vehicle.dart';
class HomePageProvider extends ChangeNotifier {
bool _isHomePageProcessing = true;
int _currentPage = 1;
String friendlyName;
List<VehicleData> _postsList = [];
bool _shouldRefresh = true;
bool get shouldRefresh => _shouldRefresh;
setShouldRefresh(bool value) => _shouldRefresh = value;
int get currentPage => _currentPage;
setCurrentPage(int page) {
_currentPage = page;
}
bool get isHomePageProcessing => _isHomePageProcessing;
setIsHomePageProcessing(bool value) {
_isHomePageProcessing = value;
notifyListeners();
}
List<VehicleData> get postsList => _postsList;
setPostsList(List<VehicleData> list, {bool notify = true}) {
_postsList = list;
if (notify) notifyListeners();
}
// This method needs to be changed
updateList(VehicleData list) {
_postsList.add(list);
notifyListeners();
}
mergePostsList(List<VehicleData> list, {bool notify = true}) {
_postsList.addAll(list);
if (notify) notifyListeners();
}
deletePost(VehicleData list) {
_postsList.remove(list);
notifyListeners();
}
addPost(VehicleData post, {bool notify = true}) {
_postsList.add(post);
if (notify) notifyListeners();
}
VehicleData getPostByIndex(int index) => _postsList[index];
int get postsListLength => _postsList.length;
}
这就是车辆数据模型:
class VehicleData {
final String id,
licencePlate,
countryRegistered,
type,
color,
vin,
owner,
garage,
friendlyName,
model,
make,
year,
status,
insuredBy,
insurancePolicyNumber,
policyExpirationDate,
mobile,
cellPhoneProvider,
notes;
final int capacity, co2perKm, luggageCapacity;
VehicleData(
{this.id,
this.licencePlate,
this.countryRegistered,
this.type,
this.color,
this.vin,
this.co2perKm,
this.owner,
this.garage,
this.friendlyName,
this.model,
this.make,
this.year,
this.capacity,
this.luggageCapacity,
this.status,
this.insuredBy,
this.insurancePolicyNumber,
this.policyExpirationDate,
this.mobile,
this.cellPhoneProvider,
this.notes});
factory VehicleData.fromJson(Map<String, dynamic> json) {
return VehicleData(
id: json['id'],
licencePlate: json['licencePlate'],
countryRegistered: json['countryRegistered'],
type: json['type'],
color: json['color'],
vin: json['vin'],
co2perKm: json['co2perKm'],
owner: json['owner'],
garage: json['garage'],
friendlyName: json['friendlyName'],
model: json['model'],
make: json['make'],
year: json['year'],
capacity: json['capacity'],
luggageCapacity: json['luggageCapacity'],
status: json['status'],
insuredBy: json['insuredBy'],
insurancePolicyNumber: json['insurancePolicyNumber '],
policyExpirationDate: json['policyExpirationDate '],
mobile: json['mobile'],
cellPhoneProvider: json['cellPhoneProvider '],
notes: json['notes '],
);
}
}
API 调用:
import 'dart:convert';
import 'package:http/http.dart';;
import 'models/vehicle.dart';
Future<HTTPResponse<List<VehicleData>>> fetchVehicles() async {
final response =
await get('https://run.mocky.io/v3/d7a00528-176c-402f-850e-76567de3c68d');
if (response.statusCode == 200) {
var body = jsonDecode(response.body)['data'];
List<VehicleData> posts = [];
body.forEach((e) {
VehicleData post = VehicleData.fromJson(e);
posts.add(post);
});
return HTTPResponse<List<VehicleData>>(
true,
posts,
message: 'Request Successful',
statusCode: response.statusCode,
);
} else {
return HTTPResponse<List<VehicleData>>(
false,
null,
message:
'Invalid data received from the server! Please try again in a moment.',
statusCode: response.statusCode,
);
}
}
class HTTPResponse<T> {
bool isSuccessful;
T data;
int statusCode;
String message;
HTTPResponse(this.isSuccessful, this.data, {this.message, this.statusCode});
}
主要:
import 'package:flutter/material.dart';
import 'components/vehicle_list.dart';
import 'screens/settings_screen.dart';
import 'package:provider/provider.dart';
import 'models/vehicle_data_provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<HomePageProvider>(
create: (_) => HomePageProvider()),
ChangeNotifierProvider<AppLocale>(create: (_) => AppLocale()),
],
child: Consumer<AppLocale>(builder: (context, locale, child) {
return MaterialApp(
home: VehicleList(),
);
}),
);
}
}
就像我说的,我只需要更新(编辑)现有数据,这些数据已经从一个屏幕传递到另一个屏幕。有人可以向我解释在更新数据时我做错了什么。我知道updateList() 方法与 addNew 方法完全相同,但我似乎找不到解决方案。
【问题讨论】:
-
你能分享你注册
HomePageProvider的代码吗?这将帮助我理解问题。 -
@PreetShah 已添加到帖子中。
标签: flutter mobile crud flutter-dependencies flutter-provider