Generi c Виджет для ListView.builder - PullRequest
0 голосов
/ 20 июня 2020

Я попытался сделать общий виджет c Stateful для ListView, основная идея - предоставить данные ListView в качестве параметра, определяя данные как общие c. Я использую DynamicListView следующим образом: 1- Для данных DateTime

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

2- Для данных String

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 ]

1 голос
/ 20 июня 2020

Немного отредактирован и добавлен пример.

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()),
            );
          },
        ),
      ),
    );
  }
}
0 голосов
/ 20 июня 2020

Может быть потому, что вы забыли передать тип generi c из класса 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 все поля экземпляра должны быть окончательными
...