我遇到了
TypeError
,消息如下:
Type '(Job) => ListTile' is not a subtype of type '(Model) => Widget'
在我的 Flutter 应用程序中尝试通过传递回调来构建小部件时。回调类型定义为:
final Widget Function(T) listItemBuilder;
在课堂上:
class ListPageBuilder<T extends Model> extends StatefulWidget
在调用代码中,我用以下方式实例化了
ListPageBuilder
:
ListPageBuilder(
listItemBuilder: (Job item) {
return ListTile(
key: Key(item.pk!),
title: Text(item.title),
subtitle: Text(item.description),
);
},
);
其中
Job
继承自 Model
。我希望这能起作用,因为 Job
是 Model
的子类,而 ListTile
是 Widget
。
这是完整代码
ListPageBuilder
实施
class ListPageBuilder<T extends Model> extends StatefulWidget {
final bool canView;
final bool canAdd;
final String modelVerboseName;
final Repository repository;
final void Function()? onItemTap;
final Widget Function(T) listItemBuilder;
const ListPageBuilder({
super.key,
required this.modelVerboseName,
required this.canView,
required this.canAdd,
required this.repository,
required this.listItemBuilder,
this.onItemTap,
});
@override
State<ListPageBuilder> createState() => _ListPageBuilderState();
}
class _ListPageBuilderState extends State<ListPageBuilder> {
@override
void initState() {
super.initState();
fetchItems();
}
var items = [];
int? nextPage = 1;
bool _isLoading = true;
final _scrollController = ScrollController();
final _searchController = TextEditingController();
String? getSearchTerm() {
return _searchController.text.length >= 3 ? _searchController.text : null;
}
Map<String, dynamic> getFilters() {
var filters = <String, dynamic>{"page": nextPage};
var searchTerm = getSearchTerm();
if (searchTerm != null) {
filters["search"] = searchTerm;
}
return filters;
}
void fetchItems() async {
if (nextPage == null) return;
try {
var response = await widget.repository.list(getFilters());
var items = response.results;
nextPage = response.next != null ? getPage(response.next!) : null;
_isLoading = false;
setState(() {
this.items.addAll(items);
});
} on HttpException catch (e) {
print(e);
}
}
@override
Widget build(BuildContext context) {
_scrollController.addListener(() {
var nextPageTriggerLimit =
0.75 * _scrollController.position.maxScrollExtent;
if (_scrollController.position.pixels > nextPageTriggerLimit &&
!_isLoading) {
_isLoading = true;
fetchItems();
}
});
return Scaffold(
bottomNavigationBar: const AppNavigationBar(),
floatingActionButton: widget.canAdd
? FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, "/customers/create");
},
child: const Icon(Icons.add),
)
: null,
body: SafeArea(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8),
child: widget.canView
? Column(
children: [
TextFormField(
decoration: InputDecoration(
hintText: "Rechercher un ${widget.modelVerboseName}",
suffixIcon: const Icon(Icons.search),
),
controller: _searchController,
onChanged: (value) {
if (value.isEmpty || value.length >= 3) {
setState(() {
items = [];
nextPage = 1;
fetchItems();
});
}
},
),
(items.isEmpty && _isLoading)
? const SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(),
)
: Expanded(
child: ListView.separated(
controller: _scrollController,
itemCount: items.length,
itemBuilder: (context, index) {
var item = items[index];
return widget.listItemBuilder(item);
},
separatorBuilder: (context, index) =>
const Divider(),
),
)
],
)
: const Center(
child: Text(
"Vous n'avez pas la permission de consulter cette page",
),
),
),
),
),
);
}
}
调用代码是
class JobListPage extends StatelessWidget {
const JobListPage({super.key});
@override
Widget build(BuildContext context) {
return ListPageBuilder<Job>(
canView: true,
canAdd: true,
repository: jobRepository,
modelVerboseName: "job",
listItemBuilder: (Job item) {
return ListTile(
key: Key(item.pk!),
title: Text(item.title),
subtitle: Text(item.description),
);
},
);
}
}
如何解决这个问题?
我可以通过写作让它发挥作用
class JobListPage extends StatelessWidget {
const JobListPage({super.key});
@override
Widget build(BuildContext context) {
return ListPageBuilder<Job>(
canView: true,
canAdd: true,
repository: jobRepository,
modelVerboseName: "job",
listItemBuilder: (Model item) {
Job job = item as Job;
return ListTile(
key: Key(job.pk!),
title: Text(job.title),
subtitle: Text(job.description),
);
},
);
}
}
它不干净,但它有效,我仍在寻找更好的解决方案。