迷你按钮可在颤动中打开抽屉式面板

问题描述 投票:0回答:1

我希望在应用程序屏幕主体的左侧放置一个迷你按钮,用于在 Flutter 中打开迷你抽屉。为了能够弄清楚,我准备了以下图片:

如图所示,当用户点击迷你按钮时,会出现一个迷你抽屉式面板,当用户再次单击同一按钮时,会关闭该面板。

谢谢你

flutter slidingdrawer
1个回答
0
投票

您可以创建自己的小部件,如下例所示。

import 'dart:math';

import 'package:flutter/material.dart';

class MiniDrawer extends StatefulWidget {
  final Widget child;
  final Widget drawerContent;
  final Duration animationDuration;
  final Size drawerSize;
  final Size drawerButtonSize;
  final Color background;
  final Color iconColor;

  const MiniDrawer({
    super.key,
    required this.child,
    required this.drawerContent,
    this.iconColor = Colors.white,
    this.background = const Color.fromRGBO(255, 120, 0, 1),
    this.drawerSize = const Size(250, 300),
    this.drawerButtonSize = const Size(50, 90),
    this.animationDuration = const Duration(milliseconds: 200),
  });

  @override
  State<MiniDrawer> createState() => _MiniDrawerState();
}

class _MiniDrawerState extends State<MiniDrawer> {
  bool _isOpen = false;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      return Stack(
        clipBehavior: Clip.none,
        children: [
          widget.child,
          _buildDrawer(constraints),
        ],
      );
    });
  }

  Widget _buildDrawer(BoxConstraints constraints) {
    return AnimatedPositioned(
      duration: widget.animationDuration,
      top: constraints.maxHeight / 2 - widget.drawerSize.height / 2,
      left: _isOpen ? 0 : min(-widget.drawerSize.width, constraints.maxWidth),
      child: SizedBox(
        height: widget.drawerSize.height,
        width: widget.drawerSize.width + widget.drawerButtonSize.width,
        child: Stack(
          alignment: Alignment.centerRight,
          clipBehavior: Clip.none,
          children: [
            _buildDrawerBtn(),
            Row(
              children: [
                Expanded(
                  child: SingleChildScrollView(
                    child: Container(
                      constraints: BoxConstraints(minHeight: widget.drawerButtonSize.height),
                      color: widget.background,
                      child: widget.drawerContent,
                    ),
                  ),
                ),
                SizedBox(width: widget.drawerButtonSize.width),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildDrawerBtn() {
    Radius radius = Radius.circular(widget.drawerButtonSize.height / 2);
    return Positioned(
      right: 10,
      child: GestureDetector(
        onTap: () {
          setState(() {
            _isOpen = !_isOpen;
          });
        },
        child: Container(
          decoration: BoxDecoration(
            color: widget.background,
            borderRadius: BorderRadius.only(
              topRight: radius,
              bottomRight: radius,
            ),
          ),
          width: widget.drawerButtonSize.width,
          height: widget.drawerButtonSize.height,
          child: AnimatedRotation(
            duration: widget.animationDuration,
            turns: _isOpen ? 0.5 : 0,
            child: Icon(
              Icons.chevron_right,
              size: 32,
              color: widget.iconColor,
            ),
          ),
        ),
      ),
    );
  }
}

然后您可以像这样在代码中使用该小部件。

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('app bar')),
      body: MiniDrawer(
        drawerContent: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: List.generate(
              10,
              (index) => ListTile(
                title: Text('Item $index'),
              ),
            ),
          ),
        ),
        child: const Column(
          children: [
            Text('Page content'),
          ],
        ),
      ),
    );
  }
© www.soinside.com 2019 - 2024. All rights reserved.