ListView.builder的通用小部件

时间:2020-06-20 02:16:33

标签: flutter

我试图为ListView制作一个通用的有状态小部件,主要思想是通过将数据定义为通用的,从而将数据作为参数提供给ListView。

class DynamicListView<T> extends StatefulWidget {
  Axis direction = Axis.vertical;
  int defaultSelectedIndex = 0;
  final List<T> data;
  final Widget Function(T, bool) item;
  DynamicListView(@required this.data, @required this.item, {this.direction, this.defaultSelectedIndex});

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

class _DynamicListViewState<T> extends State<DynamicListView> {
  int _selectedIndex;
  Widget Function(T, bool) item;

  @override
  void initState() {
    super.initState();
    this._selectedIndex = widget.defaultSelectedIndex;
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: widget.data.length,
        scrollDirection: Axis.horizontal,
        itemBuilder: (context, index) {
          return GestureDetector(
              onTap: () {
                setState(() {
                  _selectedIndex = index;
                });
              },
              child: widget.item(widget.data[index], _selectedIndex == index));
        }
    );
  }
}

我正在使用DynamicListView,如下所示: 1-对于DateTime数据

DynamicListView<DateTime>(dates,
                  (date, isActive) => DateItem(dateTime: date,isActive: isActive,),
              defaultSelectedIndex: 0,

2-对于字符串数据

DynamicListView<String>(leagues,
                  (name, isActive) => TextItem(name: name, isActive: isActive,),
                  defaultSelectedIndex: 0,
             ),

但我遇到以下异常:

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following _TypeError was thrown building:
type '(String, bool) => TextItem' is not a subtype of type '(dynamic, bool) => Widget'

When the exception was thrown, this was the stack: 
#0      _DynamicListViewState.build.<anonymous closure> (package:app/src/screens/home/Test.dart:143:29)
#1      SliverChildBuilderDelegate.build (package:flutter/src/widgets/sliver.dart:446:22)
#2      SliverMultiBoxAdaptorElement._build.<anonymous closure> (package:flutter/src/widgets/sliver.dart:1134:67)
#3      _HashMap.putIfAbsent (dart:collection-patch/collection_patch.dart:139:29)
#4      SliverMultiBoxAdaptorElement._build (package:flutter/src/widgets/sliver.dart:1134:26)
...
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
type '(DateTime, bool) => DateItem' is not a subtype of type '(dynamic, bool) => Widget'
════════════════════════════════════════════════════════════════════════════════════════════════════

那么,我做错了什么?

2 个答案:

答案 0 :(得分:1)

重构一点并添加示例。

import 'package:flutter/material.dart';

typedef ItemBuilder<T> = Widget Function(T item, bool isSelected);

class DynamicListView<T> extends StatefulWidget {
 final Axis axis;
  final List<T> data;
  final int defaultSelectedIndex;
  final ItemBuilder<T> itemBuilder;

  const DynamicListView({
    @required this.data,
    this.axis = Axis.vertical,
    @required this.itemBuilder,
    this.defaultSelectedIndex = 0,
  })  : assert(data != null),
        assert(itemBuilder != null);

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

class _DynamicListViewState<T> extends State<DynamicListView<T>> {
  int _selectedIndex;

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      scrollDirection: widget.axis,
      itemCount: widget.data.length,
      itemBuilder: (context, index) {
        return GestureDetector(
          onTap: () => setState(() => _selectedIndex = index),
          child: Container(
            width: 200,
            height: 200,
            color: Colors.blue[index * 100],
            child: widget.itemBuilder(
              widget.data[index],
              index == _selectedIndex,
            ),
          ),
        );
      },
    );
  }
}

class ExampleNumberList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: DynamicListView(
          data: [1, 2, 3],
          itemBuilder: (item, isSelected) {
            return Container(
              color: isSelected ? Colors.red : Colors.green,
              child: Text(item.toString()),
            );
          },
        ),
      ),
    );
  }
}

答案 1 :(得分:0)

可能是因为,您忘记了将泛型从构造器中的StatefulWidget类传递给State类。

尝试一下,

class DynamicListView<T> extends StatefulWidget {
  Axis direction = Axis.vertical;
  int defaultSelectedIndex = 0;
  final List<T> data;
  final Widget Function(T, bool) item;
  DynamicListView(this.data, this.item, {this.direction, this.defaultSelectedIndex});

  @override
  _DynamicListViewState<T> createState() => _DynamicListViewState<T>(); //TODO: Change here
}

也是在上面

  1. 您不需要@required注释。它主要用于命名参数
  2. StatefulWidget中,所有实例字段都应为最终字段