实现在 flutter 中创建下拉按钮的功能

Implement a function to create dropdown butttons in flutter

我是 dart 编程的新手,我想实现一个创建下拉按钮的功能。 条件是: -下拉按钮的值应该作为一个变量。

示例函数调用:

buildDropdownField(dropdownHeader:"tank 1", dropdownValue:_tank2)

此函数的预期输出是创建一个下拉按钮并将其值存储到 _tank2 中,以便我以后可以使用它。到目前为止,我尝试了不同的方法,但我似乎无法正确处理。 这是我的最终功能,它不会在屏幕上显示值,但会保存给定的值。

Widget buildDropdownField(
      {required String dropdownHeader,
        required String? dropdownValue,
      required VoidCallback? OnChanged(Value)}) {
    return Column(
      children: <Widget>[
        Text(dropdownHeader),
        const SizedBox(
          height: 10,
        ),
        StatefulBuilder(
          builder: (_, setDropState) {
            return DropdownButton<String>(
              value: dropdownValue,
              icon: const Icon(Icons.arrow_downward),
              elevation: 16,
              style: const TextStyle(color: Colors.deepPurple),
              underline: Container(
                height: 2,
                color: Colors.deepPurpleAccent,
              ),
              onChanged: (value){
                OnChanged(value);
              },
              items: <String>['-', 'Geçti', 'Kaldı', 'Belirsiz']
                  .map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value),
                );
              }).toList(),
            );
          },
        )
      ],
    );
  }

最后是我最后一次函数迭代的函数调用:

buildDropdownField(dropdownHeader:"tank 1", dropdownValue:_tank2, OnChanged: (Value) {
                      setState(() {
                       tank1 = Value;
                    });
                    })

这是我在我的项目中使用的自定义扩展磁贴。它来自一个包的代码,稍微符合我的需要。

import 'package:flutter/material.dart';

const Duration _kExpand = Duration(milliseconds: 200);

class CustomExpansionTile extends StatefulWidget {
  const CustomExpansionTile({
    Key key,
    this.leading,
    @required this.title,
    this.backgroundColor,
    this.children = const <Widget>[],
    this.trailing,
    @required this.expandedItem,
    @required this.expansionCallback,
    @required this.onHeaderClick,
    this.subtitleWidget,
  }) : super(key: key);

  /// A widget to display before the title.
  ///
  /// Typically a [CircleAvatar] widget.
  final Widget leading;

  /// The primary content of the list item.
  ///
  /// Typically a [Text] widget.
  final Widget title;

  final Widget subtitleWidget;

  /// The widgets that are displayed when the tile expands.
  ///
  /// Typically [ListTile] widgets.
  final List<Widget> children;

  /// The color to display behind the sublist when expanded.
  final Color backgroundColor;

  /// A widget to display instead of a rotating arrow icon.
  final Widget trailing;

  final ValueNotifier<Key> expandedItem;

  final Function(bool hasExpanded) expansionCallback;

  final Function() onHeaderClick;

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

class _CustomExpansionTileState extends State<CustomExpansionTile>
    with SingleTickerProviderStateMixin {
  static final Animatable<double> _easeOutTween =
      CurveTween(curve: Curves.easeOut);
  static final Animatable<double> _easeInTween =
      CurveTween(curve: Curves.easeIn);
  static final Animatable<double> _halfTween =
      Tween<double>(begin: 0.0, end: 0.5);

  final ColorTween _borderColorTween = ColorTween();
  final ColorTween _headerColorTween = ColorTween();
  final ColorTween _iconColorTween = ColorTween();
  final ColorTween _backgroundColorTween = ColorTween();

  AnimationController _controller;
  Animation<double> _iconTurns;
  Animation<double> _heightFactor;
  Animation<Color> _borderColor;
  Animation<Color> _headerColor;
  Animation<Color> _iconColor;
  Animation<Color> _backgroundColor;

  bool _isExpanded = false;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(duration: _kExpand, vsync: this);
    _heightFactor = _controller.drive(_easeInTween);
    _iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
    _borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween));
    _headerColor = _controller.drive(_headerColorTween.chain(_easeInTween));
    _iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
    _backgroundColor =
        _controller.drive(_backgroundColorTween.chain(_easeOutTween));

    _isExpanded = widget.expandedItem.value == widget.key;
    if (_isExpanded) _controller.value = 1.0;

    widget.expandedItem.addListener(listener);
  }

  void listener() {
    setState(() {
      _changeState(widget.expandedItem.value == widget.key);
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    widget.expandedItem.removeListener(listener);
    super.dispose();
  }

  void _changeState(bool isExpanded) {
    setState(() {
      _isExpanded = isExpanded;
      if (_isExpanded) {
        _controller.forward();
      } else {
        _controller.reverse().then<void>((void value) {
          if (!mounted) return;
          setState(() {
            // Rebuild without widget.children.
          });
        });
      }
      PageStorage.of(context)?.writeState(context, _isExpanded);
    });
  }

  //action to perform when the "expand" icon is pressed
  void _onExpansionIconClick() {
    widget.expansionCallback(!_isExpanded);
    _changeState(!_isExpanded);
    widget.expandedItem.value = _isExpanded ? widget.key : null;
  }

  Widget _buildChildren(BuildContext context, Widget child) {
    final Color borderSideColor = _borderColor.value ?? Colors.transparent;

    return Container(
      decoration: BoxDecoration(
        color: _backgroundColor.value ?? Colors.transparent,
        border: Border(
          top: BorderSide(color: borderSideColor),
          bottom: BorderSide(color: borderSideColor),
        ),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          ListTileTheme.merge(
            iconColor: _iconColor.value,
            textColor: _headerColor.value,
            child: ListTile(
              //if the list isExpanded, the click on the tile is disabled
              //otherwise the action defined for the callback 
              //is performed
              onTap: () => _isExpanded ? null : widget.onHeaderClick(),
              leading: widget.leading,
              title: widget.title,
              subtitle: widget.subtitleWidget,
              //arrow icon
              trailing: InkWell(
                onTap: _onExpansionIconClick,
                child: Container(
                  padding: EdgeInsets.all(16),
                  //rotate arrow icon if the tile is expanded
                  child: widget.trailing ??
                      RotationTransition(
                        turns: _iconTurns,
                        child: const Icon(Icons.expand_more),
                      ),
                ),
              ),
              contentPadding: EdgeInsets.only(left: 16),
            ),
          ),
          ClipRect(
            child: Align(
              heightFactor: _heightFactor.value,
              child: child,
            ),
          ),
        ],
      ),
    );
  }

  @override
  void didChangeDependencies() {
    final ThemeData theme = Theme.of(context);
    _borderColorTween..end = theme.dividerColor;
    _headerColorTween
      ..begin = theme.textTheme.subtitle1.color
      ..end = theme.accentColor;
    _iconColorTween
      ..begin = theme.unselectedWidgetColor
      ..end = theme.accentColor;
    _backgroundColorTween..end = widget.backgroundColor;
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    final bool closed = !_isExpanded && _controller.isDismissed;
    return AnimatedBuilder(
      animation: _controller.view,
      builder: _buildChildren,
      child: closed ? null : Column(children: widget.children),
    );
  }
}