Flutter DropdownMenuItem в отдельном файле виджета

У меня проблема с рефакторингом кода виджета DropdownButton во Flutter. У меня простой DropdownButton.

DropdownButton(
  items: [
    DropdownMenuItem(
      child: Container(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Text('Ascending'),
            if (widget.currentDateSortOrder == SortOrderType.Ascending)
              Icon(Icons.check)
          ],
        ),
      ),
      value: 'Asc',
    ),
    DropdownMenuItem(
      child: Container(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Text('Descending'),
            if (widget.currentDateSortOrder == SortOrderType.Descending)
              Icon(Icons.check)
          ],
        ),
      ),
      value: 'Desc',
    )
  ],
  onChanged: (itemIdentifier) {
    ...
  },
)

Я хочу переместить DropdownMenuItem в отдельный виджет, чтобы сделать дерево виджетов более компактным. Тогда я переместил его.

import 'package:flutter/material.dart';

class FileListDropdownMenuItem extends StatelessWidget {
  final String labelText;
  final bool showSelectedMark;
  final String itemValue;

  FileListDropdownMenuItem(this.labelText, this.showSelectedMark, this.itemValue);

  @override
  Widget build(BuildContext context) {
    return DropdownMenuItem(
      child: Container(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Text(labelText),
            if (showSelectedMark)
              Icon(Icons.check)
          ],
        ),
      ),
      value: itemValue,
    );
  }
}

И когда я пытаюсь использовать его в DropdownButton вот так:

...
items: [
  FileListDropdownMenuItem(
      'Ascending',
      widget.currentDateSortOrder == SortOrderType.Ascending,
      'Asc')
],
...

Я получаю такую ​​ошибку:

The argument type 'List<FileListDropdownMenuItem>' can't be assigned to the parameter type 'List<DropdownMenuItem<dynamic>>'.

Есть ли способ заставить такой подход работать? Я знаю, что могу оставить DropdownMenuItem в DropdownButton и переместить только его дочернее свойство в отдельный виджет. Однако тогда мне пришлось бы управлять «значением» и другими свойствами DropdownMenuItem в основном файле.


person Alex Pritchin    schedule 28.05.2020    source источник


Ответы (1)


DropdownButton требует, чтобы его элементы были List<DropdownMenuItem>. Но ваш класс FileListDropdownMenuItem расширяет только StatelessWidget. Если вы хотите использовать его как замену DropdownMenuItem, вам следует расширить его:

class FileListDropdownMenuItem extends DropdownMenuItem {
  FileListDropdownMenuItem(
    String labelText,
    bool showSelectedMark,
    String itemValue,
  ) : super(
    child: Container(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Text(labelText),
          if (showSelectedMark)
            Icon(Icons.check)
        ],
      ),
    ),
    value: itemValue,
  );
}
person Pavel    schedule 28.05.2020
comment
Спасибо. Хороший вариант - определить этот класс не с помощью метода сборки, а с помощью конструктора. Кстати, в методе сборки FileListDropdownMenuItem я возвращаю DropdownMenuItem. Итак, я подумал, что будет объект DropdownMenuItem на том месте, где я в конце вызываю конструктор FileListDropdownMenuItem. Или все же будет объект FileListDropdownMenuItem? - person Alex Pritchin; 28.05.2020
comment
DropdownButton требует, чтобы элементы были List ‹DropdownMenuItem›, потому что он использует поля DropdownMenuItem (onTap и значение). Hovewer, во время компиляции DropdownButton не знает, что вы вернете DropdownMenuItem в build. Все, что он знает, - это то, что вы вернете какой-нибудь подкласс Widget. Кроме того, если вы даже вернете DropdownMenuItem, тем не менее, он будет заключен в ваш FileListDropdownMenuItem в дереве виджетов. Таким образом, виджет DropdownButton не будет иметь прямого доступа к объектам DropdownMenuItem. - person Pavel; 28.05.2020
comment
Напротив, если вы расширите DropdownMenuItem и передадите child / value / onTap конструктору super, во время компиляции будет гарантировано, что FileListDropdownMenuItem будет иметь их как поля. Например, это будет правильно: var d = FileListDropdownMenuItem(...); d.onTap d.child d.value - person Pavel; 28.05.2020
comment
Спасибо за объяснение. Я предполагал, что это поведение. - person Alex Pritchin; 28.05.2020