gpt4 book ai didi

flutter - 如何转换为未知的通用运行时类型(C# ChangeType 等效项)

转载 作者:行者123 更新时间:2023-12-03 03:15:44 25 4
gpt4 key购买 nike

我是 Flutter/Dart 的新手,我正在尝试构建一个具有占位符加载的可重复使用的无限滚动条。类(class)如下:

import 'dart:async';

import 'package:flutter/material.dart';

class PagedScroller<T> extends StatefulWidget {
final int limit;
final Future<List<T>> Function(int, int) getDataFunction;
final Widget Function(T) renderFunction;
final Widget Function() renderPlaceholderFunction;

PagedScroller(
{@required this.limit,
@required this.getDataFunction,
@required this.renderFunction,
@required this.renderPlaceholderFunction});

@override
_PagedScrollerState<T> createState() => _PagedScrollerState<T>();
}

class _PagedScrollerState<T> extends State<PagedScroller> {
int _offset = 0;
int _lastDataLength = 1; // Init to one so the first call can happen
List<dynamic> _items = [];
Future<List<dynamic>> _future;
bool _isInitializing = false;
bool _isInitialized = false;
bool _isLoading = false;
ScrollController _controller =
ScrollController(initialScrollOffset: 0.0, keepScrollOffset: true);

_PagedScrollerState();

void _init() {
_isInitializing = true;

_reset();

_controller.addListener(() {
bool loadMore = false;
if (_controller.position.maxScrollExtent == double.infinity) {
loadMore = _controller.offset == _controller.position.maxScrollExtent;
} else {
loadMore =
_controller.offset >= _controller.position.maxScrollExtent * 0.85;
}

// Only load more if it's not currently loading and we're not on the last page
// _lastDataLength should be 0 if there are no more pages
if (loadMore && !_isLoading && _lastDataLength > 0) {
_offset += widget.limit;
_load();
}
});

_load();
_isInitializing = false;
_isInitialized = true;
}

void _reset() {
// Clear things array and reset inital get-things link (without paging)
setState(() {
_future = _clearThings();
});

// Reload things
// Reset to initial GET link
_offset = 0;
}

void _load() {
setState(() {
_future = _loadPlaceholders();
_future = _loadData();
});
}

Future<List<dynamic>> _clearThings() async {
_items.clear();
return Future.value(_items);
}

Future<List<dynamic>> _loadPlaceholders() async {
// Add 20 empty placeholders to represent stuff that's currently loading
for (var i = 0; i < widget.limit; i++) {
_items.add(_Placeholder());
}

return Future.value(_items);
}

List<dynamic> _getInitialPlaceholders() {
var placeholders = List<dynamic>();
for (var i = 0; i < widget.limit; i++) {
placeholders.add(_Placeholder());
}
return placeholders;
}

Future<List<dynamic>> _loadData() async {
_setLoading(true);

var data = await widget.getDataFunction(widget.limit, _offset);

// When loading data is done, remove any placeholders
_items.removeWhere((item) => item is _Placeholder);

// If 0 items were returned, it's probably the last page
_lastDataLength = data.length;

for (var item in data) {
_items.add(item);
}

_setLoading(false);

return Future.value(_items);
}

void _setLoading(bool isLoading) {
if (!mounted) {
return;
}

setState(() {
_isLoading = isLoading;
});
}

Future<void> _refreshThings() async {
_reset();
_load();
return Future;
}

@override
Widget build(BuildContext context) {
if (!_isInitializing && !_isInitialized) {
_init();
}

return FutureBuilder(
future: _future,
initialData: _getInitialPlaceholders(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
List<dynamic> loadedItems = snapshot.data;
return RefreshIndicator(
onRefresh: _refreshThings,
child: ListView.builder(
itemCount: loadedItems.length,
controller: _controller,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
var item = loadedItems[index];
if (item is _Placeholder) {
return widget.renderPlaceholderFunction();
} else if (item is T) {
// THIS IS THE LINE THAT FAILS
return widget.renderFunction(item);
}

return Text('Unknown item type');
},
),
);
}
return Container();
},
);
}
}

class _Placeholder {}

上面失败的行:
return widget.renderFunction(item);

失败并出现以下情况:
type '(MyModel) => Widget' is not a subtype of type '(dynamic) => Widget'

我明白为什么会这样。编译器无法从我的 PagedScroller<T> 中知道该类型 T与 _PagedScrollerState<T> 中的类型 T 相同.因此,Dart 尝试提供帮助,并将我的回调函数类型转换为 Widget Function(T)Widget Function(dynamic) .

然后我想出了“也许我可以伪造它”,因为我知道 PagedScroller<T> 中的 T和 _PagedScrollerState<T>总是一样的:
var renderFunction = widget.renderFunction as Widget Function(T);
return renderFunction(item);

有趣的是,这给了我一个警告:
Unnecessary cast.
Try removing the cast.

然而,它甚至不会使用以下内容运行该行(崩溃):
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=BUG.md

将所有内容更改为动态效果很有魅力,但如果我不需要,我真的不想在这里失去泛型的可读性。

尽管进行了广泛的搜索,但我找不到与 C# 的 Convert.ChangeType 等效的东西,您可以在其中提供运行时的类型,因此我可以进行我想要的转换并完成它。

这似乎是一件非常简单的事情,但我被困住了。

您可以使用这个简单的 main.dart 复制/粘贴来使用滚动条:
import 'package:flutter/material.dart';
import 'package:minimal_repros/paged_scroller.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
Future<List<MyModel>> getDataFunction(int limit, int offset) async {
var myModels = List<MyModel>();

// Simulate API call
await Future.delayed(Duration(milliseconds: 1000));

for (int i = 0; i < limit; i++) {
var myModel = MyModel();
myModel.count = i + offset;
myModel.firstName = 'Bob';
myModels.add(myModel);
}

return myModels;
}

Widget renderFunction(MyModel myModel) {
return Text(myModel.firstName);
}

Widget renderPlaceholderFunction() {
return Text('Loading');
}

return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: PagedScroller(
getDataFunction: getDataFunction,
renderFunction: renderFunction,
renderPlaceholderFunction: renderPlaceholderFunction,
limit: 20));
}
}

class MyModel {
int count;
String firstName;
}

最佳答案

在您的State 的声明中类,您忘记指定小部件的通用参数。

代替:

class _PagedScrollerState<T> extends State<PagedScroller> {

做:

class _PagedScrollerState<T> extends State<PagedScroller<T>> {

关于flutter - 如何转换为未知的通用运行时类型(C# ChangeType 等效项),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59648119/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com