Flutter 常见问题解答下拉列表

Dropdown for FAQ for flutter

嘿,谁能告诉我一个与我提供的图像相似的 flutter 小部件或库。 我想要这个作为常见问题解答部分。最初只有问题应该是可见的,点击它应该显示答案的组件。

enter image description here

我会选择 this library,或者如果您愿意,这里是我为自己的目的创建的小部件的片段:

import 'package:flutter/material.dart';


/// [CustomCollapsable] is collapsable widget which shows a [preview]
/// and a trailing with a [trailingText] by default. On tap the trailing or
/// its [trailingText], it animates to show the [child].

/// NOTE: [ExpansionTile] doesn't support layout changes, for example
/// moving trailing down or to hide the [preview] after expand the content.
/// [CustomCollapsable] is inspired on [ExpansionTile] with additional features.
class CustomCollapsable extends StatefulWidget {
  /// [Widget] shown when expanded
  final Widget child;

  /// [Widget] shown only when it is not expanded
  final Widget preview;

  /// [String] that goes on top of the trailing arrow
  final String trailingText;

  /// Callback [ValueChanged] function fired after animation
  final ValueChanged<bool> onExpansionChanged;

  const CustomCollapsable({
    Key key,
    @required this.preview,
    @required this.child,
    @required this.trailingText,
    this.onExpansionChanged,
  });

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

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

  AnimationController _controller;
  Animation<double> _heightFactor;
  Animation<double> _iconTurns;

  bool _isExpanded = false;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      duration: Duration(seconds: 1),
      vsync: this,
    );
    _iconTurns = _controller.drive(_halfTween.chain(_easeInTween));

    _heightFactor = _controller.drive(_easeInTween);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  bool get isClosed => !_isExpanded && _controller.isDismissed;

  void _handleTap() {
    setState(() {
      _isExpanded = !_isExpanded;

      if (_isExpanded) {
        _controller.forward();
      } else {
        _controller.reverse().then<void>((void value) {
          if (!mounted) return;
          setState(() {});
        });
      }

      PageStorage.of(context)?.writeState(context, _isExpanded);
    });

    if (widget.onExpansionChanged != null) {
      widget.onExpansionChanged(_isExpanded);
    }
  }

  Widget _buildTralling() {
    return GestureDetector(
      onTap: _handleTap,
      child: Padding(
        padding: const EdgeInsets.only(top: 15.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            isClosed
                ? Text(widget.trailingText.toUpperCase())                      
                : const SizedBox(),
            RotationTransition(
              turns: _iconTurns,
              child: const Icon(Icons.expand_more),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildChild(BuildContext context, Widget child) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        // Preview widget is visible only when the parent is closed
        isClosed ? widget.preview : const SizedBox(),
        ClipRect(
          child: Align(
            heightFactor: _heightFactor.value,
            child: child,
          ),
        ),
        _buildTralling()
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller.view,
      builder: _buildChild,
      child: isClosed ? null : widget.child,
    );
  }
}

您可以根据需要定义 childpreview 小部件。