我是Flutter的新手,目前正在开发一个学生记录应用程序。该应用程序使用列表平铺显示学生记录列表。然而,我在尝试实现删除功能时遇到了一个问题。我想让用户能够通过单击与学生数据关联的ListTile来删除学生记录。问题是,我当前的实现总是删除第一个索引ListTile,而不管单击的是哪一个。我使用的是SQFlite数据库。我在这里提供我的代码。
主镖
import 'package:flutter/material.dart';
import 'package:student/Screens/home_screen.dart';
import 'package:student/functions/functions.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
initializeDatabase();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.from(
colorScheme: const ColorScheme.light(
background: Colors.white,
primary: Color.fromARGB(255, 0, 238, 226),
brightness: Brightness.light,
secondary: Color(0xff03dac6)),
),
home: const HomeScreen(),
);
}
}
字符串
主页屏幕.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:student/Screens/add_student_screen.dart';
import 'package:student/Screens/edit_screen.dart';
import 'package:student/Screens/profile_student_screen.dart';
import 'package:student/functions/functions.dart';
import 'package:student/model/students.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool isLoading = true;
List<Students>? studentList;
Students? student;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Student Record'),
actions: [
IconButton(
onPressed: () {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (context) => const SearchScreen(),
// ));
},
icon: const Icon(Icons.search),
),
IconButton(
onPressed: () {
getAllStudents(student,context);
},
icon: const Icon(Icons.refresh),
),
],
),
body: ValueListenableBuilder(
builder: (BuildContext context, studentList, Widget? child) {
return FutureBuilder(
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('key'),
);
}
return ListView.builder(
itemCount: studentList.length,
itemBuilder: (context, index) {
final student = studentList[index];
return SizedBox(
height: 60,
child: ListTile(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ProfileStudentScreen(
student: student,
),
));
},
leading: SizedBox.square(
dimension: 50,
child: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: student.image.isEmpty
? Image.network(
'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png')
: Image.file(
File(student.image),
fit: BoxFit.cover,
),
),
),
title: Text(student.name),
trailing: Wrap(
spacing: 20,
direction: Axis.horizontal,
children: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => EditStudentScreen(
student: student,
)),
);
},
icon: const Icon(Icons.edit),
),
IconButton(
onPressed: () {
deleteStudent(studentList[index].id! , context);
},
icon: const Icon(Icons.delete),
),
],
),
),
);
},
);
});
},
valueListenable: studentListNotifier,
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddStudentScreen(),
),
);
},
child: const Icon(Icons.add),
),
);
}
}
型
studentsModel.dart
const String studentsTable = 'students';
class StudentsFields {
static final List<String> values = [id, name, age, email, domain, image];
static const String id = 'id';
static const String name = 'name';
static const String age = 'age';
static const String email = 'email';
static const String domain = 'domain';
static const String image = 'image';
}
class Students {
int? id;
String name;
int? age;
String email;
String domain;
String image;
Students({
this.id,
this.name = '',
this.age = 0,
this.email = '',
this.domain = '',
this.image = '',
});
Students copy({
int? id,
String? name,
int? age,
String? email,
String? domain,
String? image,
}) =>
Students(
id: id ?? this.id,
name: name ?? this.name,
age: age ?? this.age,
email: email ?? this.email,
domain: domain ?? this.domain,
image: image ?? this.image,
);
static Students fromMap(Map<String, Object?> map) {
final id = map['id'] as int;
final name = map['name'] as String;
final age = map['age'] as int;
final email = map['email'] as String;
final domain = map['domain'] as String;
final image = map['image'] as String;
return Students(
id: id,
name: name,
age: age,
email: email,
domain: domain,
image: image,
);
}
Map<String, dynamic> toMap() {
return {
StudentsFields.id: id,
StudentsFields.name: name,
StudentsFields.age: age,
StudentsFields.email: email,
StudentsFields.domain: domain,
StudentsFields.image: image,
};
}
}
型
数据库功能
// ignore_for_file: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:student/model/students.dart';
ValueNotifier<List<Students>> studentListNotifier = ValueNotifier([]);
late Database _db;
Future<void> initializeDatabase() async {
_db = await openDatabase('student.db', version: 1, onCreate: (db, version) {
db.execute('''
CREATE TABLE $studentsTable (
${StudentsFields.id} INTEGER PRIMARY KEY NOT NULL,
${StudentsFields.name} TEXT,
${StudentsFields.age} INTEGER NOT NULL,
${StudentsFields.email} TEXT,
${StudentsFields.domain} TEXT,
${StudentsFields.image} TEXT
)
''');
});
}
Future<void> getAllStudents(Students? student, BuildContext ctx) async {
studentListNotifier.value.clear();
try {
final values = await _db.rawQuery('SELECT * FROM $studentsTable');
for (var map in values) {
final student = Students.fromMap(map);
studentListNotifier.value.add(student);
studentListNotifier.notifyListeners();
log("SUcess");
}
} catch (e) {
log("Error getting data : $e");
showDialog(
context: ctx,
builder: (context) => const AlertDialog(
title: Text("Warning"),
),
);
}
}
Future<void> addStudent(Students student, BuildContext ctx) async {
try {
await _db.rawInsert(
'INSERT INTO $studentsTable (${StudentsFields.name},${StudentsFields.age},${StudentsFields.email},${StudentsFields.domain},${StudentsFields.image}) VALUES (?, ?, ?, ?, ?)',
[student.name, student.age, student.email, student.domain, student.image],
);
studentListNotifier.value.add(student);
studentListNotifier.notifyListeners();
} catch (e) {
log('Error updating student: $e');
showDialog(
context: ctx,
builder: (context) => const AlertDialog(
title: Text("Warning"),
),
);
}
}
Future<void> editStudent(Students student, BuildContext ctx) async {
try {
final updatedRows = await _db.rawUpdate(
'UPDATE $studentsTable SET '
'WHERE ${StudentsFields.age} = ?, '
'${StudentsFields.email} = ?, '
'${StudentsFields.domain} = ? '
' ${StudentsFields.name} = ?',
[
student.age,
student.email,
student.domain,
student.name,
],
);
ScaffoldMessenger.of(ctx).showSnackBar(const SnackBar(
backgroundColor: Colors.green,
content: Text("Sucesfully Updated"),
duration: Duration(milliseconds: 600),
));
if (updatedRows > 0) {
studentListNotifier.notifyListeners();
log('Success: Student updated');
} else {
log('No rows updated.');
}
} catch (e) {
log('Error updating student: $e');
ScaffoldMessenger.of(ctx).showSnackBar(const SnackBar(
backgroundColor: Colors.red,
content: Text("Error occured"),
duration: Duration(milliseconds: 600),
));
}
}
Future<void> deleteStudent(int id, BuildContext ctx) async {
try {
await _db.rawDelete(
'DELETE FROM $studentsTable WHERE $id = ?',
[id],
);
studentListNotifier.value.removeAt(id);
studentListNotifier.notifyListeners();
log('Success: Student deleted');
} catch (e) {
log('Error deleting student: $e');
showDialog(
context: ctx,
builder: (context) => const AlertDialog(
title: Text("Warning"),
),
);
}
}
Future<void> refreshList(BuildContext ctx) async {
try {
final values = await _db.rawQuery('SELECT * FROM $studentsTable');
studentListNotifier.value =
values.map((map) => Students.fromMap(map)).toList();
studentListNotifier.notifyListeners();
} catch (e) {
log("Error refreshing data");
showDialog(
context: ctx,
builder: (context) => const AlertDialog(
title: Text("Warning"),
),
);
}
}
型
我也提供了我的搜索屏幕与它。请更正它我想通过搜索名称显示数据。
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:student/model/students.dart';
import 'package:student/Screens/profile_student_screen.dart';
class SearchScreen extends StatefulWidget {
final List<Students>? studentList;
const SearchScreen({required this.studentList, Key? key}) : super(key: key);
@override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
List<Students> filteredList = [];
String searchQuery = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Search Students'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
onChanged: (value) {
setState(() {
searchQuery = value;
filteredList = widget.studentList!
.where((student) => student.name
.toLowerCase()
.contains(value.toLowerCase()))
.toList();
});
},
decoration: const InputDecoration(
hintText: 'Search by name...',
prefixIcon: Icon(Icons.search),
),
),
),
Expanded(
child: _buildStudentList(),
),
],
),
);
}
Widget _buildStudentList() {
if (filteredList.isEmpty) {
return const Center(child: Text('No students found'));
} else {
return ListView.builder(
itemCount: filteredList.length,
itemBuilder: (context, index) {
final student = filteredList[index];
return ListTile(
leading: SizedBox.square(
dimension: 50,
child: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: student.image.isEmpty
? Image.network(
'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png')
: Image.file(
File(student.image),
fit: BoxFit.cover,
),
),
),
title: Text(student.name),
onTap: () {
// Handle tapping on the student in the search results.
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ProfileStudentScreen(student: student),
),
);
},
);
},
);
}
}
}
型
- 更新 *:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:student/Screens/add_student_screen.dart';
import 'package:student/Screens/edit_screen.dart';
import 'package:student/Screens/profile_student_screen.dart';
import 'package:student/functions/functions.dart';
import 'package:student/model/students.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool isLoading = true;
List<Students>? studentList;
Students? student;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Student Record'),
actions: [
IconButton(
onPressed: () {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (context) => const SearchScreen(),
// ));
},
icon: const Icon(Icons.search),
),
],
),
body: ValueListenableBuilder(
builder: (BuildContext context, studentList, Widget? child) {
return ListView.builder(
itemCount: studentList.length,
itemBuilder: (context, index) {
final student = studentList[index];
return SizedBox(
height: 60,
child: ListTile(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ProfileStudentScreen(
student: student,
),
));
},
leading: SizedBox.square(
dimension: 50,
child: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: student.image.isEmpty
? Image.network(
'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png')
: Image.file(
File(student.image),
fit: BoxFit.cover,
),
),
),
title: Text(student.name),
trailing: Wrap(
spacing: 20,
direction: Axis.horizontal,
children: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => EditStudentScreen(
student: student,
)),
);
},
icon: const Icon(Icons.edit),
),
IconButton(
onPressed: () {
deleteStudent(studentList[index].id!);
},
icon: const Icon(Icons.delete),
),
],
),
),
);
},
);
},
valueListenable: studentListNotifier,
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddStudentScreen(),
),
);
},
child: const Icon(Icons.add),
),
);
}
}
型
更改:未来版本已删除。
添加学生屏幕:
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:student/functions/functions.dart';
import 'package:student/model/students.dart';
class AddStudentScreen extends StatefulWidget {
final Students? student;
const AddStudentScreen({
super.key,
this.student,
});
@override
State<AddStudentScreen> createState() => _AddEditStudentScreenState();
}
class _AddEditStudentScreenState extends State<AddStudentScreen> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _ageController = TextEditingController();
final _emailController = TextEditingController();
final _domainController = TextEditingController();
final _imageController = TextEditingController();
/*Image Picker Functions */
XFile? _imageFile;
Future<void> _getImageFromCamera() async {
final pickedFile =
await ImagePicker().pickImage(source: ImageSource.camera);
if (pickedFile != null) {
setState(() {
_imageFile = XFile(pickedFile.path);
});
}
}
Future<void> _getImageFromGallery() async {
final pickedFile =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_imageFile = XFile(pickedFile.path);
});
}
}
@override
void dispose() {
_nameController.dispose();
_ageController.dispose();
_emailController.dispose();
_domainController.dispose();
_imageController.dispose();
super.dispose();
}
// Image picker end here
//Email validation
bool isEmailValid(String email) {
final emailRegExp = RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+");
return emailRegExp.hasMatch(email);
}
// Save Student Function
void _saveStudent() async {
if (_formKey.currentState!.validate()) {
final newStudent = Students(
id: int.tryParse(StudentsFields.id) ?? 0,
name: _nameController.text,
age: int.tryParse(_ageController.text) ?? 0,
email: _emailController.text,
domain: _domainController.text,
image: _imageFile?.path ?? '',
);
addStudents(newStudent);
Navigator.of(context).pop();
}
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: const Text(
"Add Student",
),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: _nameController,
decoration: const InputDecoration(labelText: 'Name'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a name';
}
return null;
},
),
TextFormField(
controller: _ageController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Age',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter an age';
}
return null;
},
),
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(labelText: 'Email'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
} else if (!isEmailValid(value)) {
return 'Invalid email';
}
return null;
},
),
TextFormField(
controller: _domainController,
decoration: const InputDecoration(
labelText: 'Domain',
labelStyle: TextStyle(color: Colors.black)),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your domain';
}
return null;
},
),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black),
onPressed: _getImageFromCamera,
icon: const Icon(
Icons.camera,
color: Colors.white,
),
label: const Text(
'Camera',
style: TextStyle(color: Colors.white),
),
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black),
onPressed: _getImageFromGallery,
icon: const Icon(
Icons.upload,
color: Colors.white,
),
label: const Text(
'Upload',
style: TextStyle(color: Colors.white),
),
),
],
),
),
SizedBox(
width: size.width,
child: ElevatedButton(
style:
ElevatedButton.styleFrom(backgroundColor: Colors.black),
onPressed: () async {
_saveStudent();
},
child: const Text(
'Save',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
],
),
),
),
),
);
}
}
型
我进入了一个错误,在addstudent页面输入的数据没有显示在主界面
1条答案
按热度按时间pb3skfrl1#
字符串
代替这种用途,
型