Создание выпадающего меню внутри нижнего листа в Flutter - PullRequest
2 голосов
/ 07 октября 2019

Я пытаюсь сделать что-то вроде этого, чтобы раскрывающийся список основывался на содержимом списка. Мой список выглядит так:

[
    {
        id: val,
        displayName: Enter value,
        type: string, 
        value: "any"
    },
    {
        id: si,
        displayName: Source,
        type: list,
        value: [
            MO
        ],
        data: [
            {id: 1, displayId: MO},
            {id: 2, displayId: AO},
            {id: 3, displayId: OffNet}
        ]
     }
 ]

В настоящее время есть 2 записи. отобразить раскрывающийся список, содержащий эти параметры (Ввести значение и Источник) в виде 2 записей раскрывающегося списка

Если выбран параметр Ввести значение, рядом с ним должно отображаться текстовое поле, так как оно имеет тип строки. Если в раскрывающемся списке выбран параметр «Источник», то в качестве значения раскрывающегося списка должен быть указан другой раскрывающийся список, содержащий эти записи (MO, AO, Offnet), поскольку он имеет тип списка.

в зависимости от выбора 1-го раскрывающегося списка. должен быть выбран виджет для отображения (текстовое поле или другое раскрывающееся меню).

У меня есть такой код, который сделает все необходимое, но здесь я беру всю страницу как контейнер и всякий раз, когда опция меняет setStateвызвал, который перестраивает метод сборки, но я хочу реализовать то же самое внутри нижней таблицы, там я не знаю, как управлять состоянием, то есть, когда параметр в раскрывающемся списке изменяется, я хочу, чтобы базовая таблица перестраивалась с данными.

код:

import 'package:flutter/material.dart';

void main() {
  runApp(DropdownExample());
}

class DropdownExample extends StatefulWidget {
  @override
  _DropdownExampleState createState() => _DropdownExampleState();
}

class _DropdownExampleState extends State<DropdownExample> {
  String type;
  int optionId;

  final items = [
    {
      "displayName": "Enter value",
      "type": "string",
    },
    {
      "displayName": "Source",
      "type": "list",
      "data": [
        {"id": 1, "displayId": "MO"},
        {"id": 2, "displayId": "AO"},
        {"id": 3, "displayId": "OffNet"}
      ]
    }
  ];

  @override
  Widget build(BuildContext context) {
    Widget supporting = buildSupportingWidget();

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Dropdown Example")),
        body: Center(
          child: Container(
            height: 600,
            width: 300,
            child: Row(
              children: <Widget>[
                buildMainDropdown(),
                if (supporting != null) supporting,
              ],
            ),
          ),
        ),
      ),
    );
  }

  Expanded buildMainDropdown() {
    return Expanded(
      child: DropdownButtonHideUnderline(
        child: DropdownButton(
          value: type,
          hint: Text("Select a type"),
          items: items
              .map((json) => DropdownMenuItem(
                  child: Text(json["displayName"]), value: json["type"]))
              .toList(),
          onChanged: (newType) {
            setState(() {
              type = newType;
            });
          },
        ),
      ),
    );
  }

  Widget buildSupportingWidget() {
    if (type == "list") {
      List<Map<String, Object>> options = items[1]["data"];
      return Expanded(
        child: DropdownButtonHideUnderline(
          child: DropdownButton(
            value: optionId,
            hint: Text("Select an entry"),
            items: options
                .map((option) => DropdownMenuItem(
                    child: Text(option["displayId"]), value: option["id"]))
                .toList(),
            onChanged: (newId) => setState(() {
              this.optionId = newId;
            }),
          ),
        ),
      );
    } else if (type == "string") {
      return Expanded(child: TextFormField());
    }
    return null;
  }
}

приведенный выше код работает нормально, но я пытаюсь сделать то же самое, что и в нижней части таблицы с точными функциональными возможностями.

всякий раз, когда кнопка "открывает нижнюю страницу"", нижний лист должен появиться и отобразить результат кода как содержимоенижний лист.

Я сделал что-то подобное, но оно не работает

import 'package:flutter/material.dart';

void main() {
  runApp(DropdownExample());
}

class DropdownExample extends StatefulWidget {
  @override
  _DropdownExampleState createState() => _DropdownExampleState();
}

class _DropdownExampleState extends State<DropdownExample> {
  String type;
  int optionId;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Dropdown Example")),
        body: Center(
          child: Container(
            height: 600,
            width: 300,
            child: Row(
              children: <Widget>[
                Align(
                    alignment: Alignment.topRight,
                    child: FlatButton.icon(
                      label: Text('Filters'),
                      icon: Icon(Icons.filter_list),
                       onPressed: showModalSheet(),
                       )),
              ],
            ),
          ),
        ),
      ),
    );
  }

showModalSheet() {

final items = [
    {
      "displayName": "Enter value",
      "type": "string",
    },
    {
      "displayName": "Source",
      "type": "list",
      "data": [
        {"id": 1, "displayId": "MO"},
        {"id": 2, "displayId": "AO"},
        {"id": 3, "displayId": "OffNet"}
      ]
    }
  ];

     showModalBottomSheet<void>(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10.0),
        ),
        context: context,
        builder: (BuildContext context) {
          return StatefulBuilder(
              builder: (BuildContext context, StateSetter state) {
            return createBox(context, items, state);
          });
        });

}

createBox(BuildContext context, List<Map<String,Object>> val,StateSetter state) {
      Widget supporting = buildSupportingWidget(val);
    return SingleChildScrollView(
      child: LimitedBox(
        child: Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
               buildMainDropdown(val),
                if (supporting != null) supporting
          ]
        )
      )
    );

}



  Expanded buildMainDropdown(List<Map<String,Object>> items) {
    return Expanded(
      child: DropdownButtonHideUnderline(
        child: DropdownButton(
          value: type,
          hint: Text("Select a type"),
          items: items
              .map((json) => DropdownMenuItem(
                  child: Text(json["displayName"]), value: json["type"]))
              .toList(),
          onChanged: (newType) {
            setState(() {
              type = newType;
            });
          },
        ),
      ),
    );
  }

  Widget buildSupportingWidget(List<Map<String,Object>>items) {
    if (type == "list") {
      List<Map<String, Object>> options = items[1]["data"];
      return Expanded(
        child: DropdownButtonHideUnderline(
          child: DropdownButton(
            value: optionId,
            hint: Text("Select an entry"),
            items: options
                .map((option) => DropdownMenuItem(
                    child: Text(option["displayId"]), value: option["id"]))
                .toList(),
            onChanged: (newId) => setState(() {
              this.optionId = newId;
            }),
          ),
        ),
      );
    } else if (type == "string") {
      return Expanded(child: TextFormField());
    }
    return null;
  }
}

сообщите мне о необходимых изменениях, Спасибо

1 Ответ

0 голосов
/ 08 октября 2019

Шаг 1: LimitedBox нужно maxHeight
Шаг 2: функции showModalSheet необходимо передать контекст
Шаг 3: createBox, buildMainDropdown и buildSupportingWidget необходимо передать состояние для StatefulBuilder

полный код

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: DropdownExample(),
    );
  }
}

class DropdownExample extends StatefulWidget {
  @override
  _DropdownExampleState createState() => _DropdownExampleState();
}

class _DropdownExampleState extends State<DropdownExample> {
  String type;
  int optionId;


  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Dropdown Example")),
        body: Center(
          child: Container(
            height: 600,
            width: 300,
            child: Row(
              children: <Widget>[
                Align(
                    alignment: Alignment.topRight,
                    child: FlatButton.icon(
                      label: Text('Filters'),
                      icon: Icon(Icons.filter_list),
                      // onPressed: showModalSheet(),
                      onPressed: () {
                        showModalSheet(context);
                      },
                    )),
              ],
            ),
          ),
        ),
      ),
    );
  }

  void showModalSheet(BuildContext context) {
    final items = [
      {
        "displayName": "Enter value",
        "type": "string",
      },
      {
        "displayName": "Source",
        "type": "list",
        "data": [
          {"id": 1, "displayId": "MO"},
          {"id": 2, "displayId": "AO"},
          {"id": 3, "displayId": "OffNet"}
        ]
      }
    ];

    showModalBottomSheet<void>(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10.0),
        ),
        context: context,
        builder: (BuildContext context) {
          return StatefulBuilder(
              builder: (BuildContext context, StateSetter state) {
                return createBox(context, items, state);
              });
        });
  }



  createBox(BuildContext context, List<Map<String,Object>> val,StateSetter state) {
    Widget supporting = buildSupportingWidget(val,state);
    return SingleChildScrollView(
        child: LimitedBox(
            maxHeight: 300,
            child: Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  buildMainDropdown(val,state),
                  if (supporting != null) supporting
                ]
            )
        )
    );

  }



  Expanded buildMainDropdown(List<Map<String,Object>> items,StateSetter setState) {
    return Expanded(
      child: DropdownButtonHideUnderline(
        child: DropdownButton(
          value: type,
          hint: Text("Select a type"),
          items: items
              .map((json) => DropdownMenuItem(
              child: Text(json["displayName"]), value: json["type"]))
              .toList(),
          onChanged: (newType) {
            setState(() {
              type = newType;
            });
          },
        ),
      ),
    );
  }

  Widget buildSupportingWidget(List<Map<String,Object>>items, StateSetter setState) {
    if (type == "list") {
      List<Map<String, Object>> options = items[1]["data"];
      return Expanded(
        child: DropdownButtonHideUnderline(
          child: DropdownButton(
            value: optionId,
            hint: Text("Select an entry"),
            items: options
                .map((option) => DropdownMenuItem(
                child: Text(option["displayId"]), value: option["id"]))
                .toList(),
            onChanged: (newId) => setState(() {
              this.optionId = newId;
            }),
          ),
        ),
      );
    } else if (type == "string") {
      return Expanded(child: TextFormField());
    }
    return null;
  }
}

enter image description here

...