迷你按钮打开抽屉般的面板在 Flutter

jaql4c8m  于 2023-10-22  发布在  Flutter
关注(0)|答案(2)|浏览(109)

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

如图所示,当用户点击迷你按钮时,迷你抽屉式面板进入,当用户再次点击同一按钮时,它关闭面板。
谢谢你

bvjveswy

bvjveswy1#

这段代码将允许您使用endDrawer作为您的迷你抽屉,您的主抽屉也将在那里。
您可以在网上查看,根据您的需要自定义结束抽屉的用户界面。

import 'package:flutter/material.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: TwoDrawers(),
      ),
    );
  }
}

class TwoDrawers extends StatelessWidget {
  const TwoDrawers({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Mini Drawer"),
        actions: const [SizedBox()],
      ),
      drawer: Drawer(
        child: Container(
          color: Colors.blue,
          child: const Center(
            child: Text(
              "Main Drawer",
              style: TextStyle(color: Colors.white, fontSize: 30),
            ),
          ),
        ),
      ),
      endDrawer: SizedBox(
        height: 300,
        child: Drawer(
          elevation: 0,
          backgroundColor: Colors.indigo,
          child: Row(
            children: [
              IconButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                icon: const Icon(Icons.chevron_right),
                color: Colors.white,
              ),
              Container(
                width: 240,
                color: Colors.indigo,
                child: const Center(
                  child: Text(
                    "Mini Drawer",
                    style: TextStyle(color: Colors.white, fontSize: 30),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
      body: Stack(
        children: [
          Positioned(
            height: 40,
            top: 250,
            right: -30,
            child: SizedBox(
              child: Builder(
                builder: (context) {
                  return ElevatedButton(
                    style: ButtonStyle(
                      backgroundColor:
                          const MaterialStatePropertyAll(Colors.indigo),
                      shape: MaterialStatePropertyAll(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(10),
                        ),
                      ),
                      padding: const MaterialStatePropertyAll(
                        EdgeInsets.only(right: 30),
                      ),
                    ),
                    onPressed: () {
                      Scaffold.of(context).openEndDrawer();
                    },
                    child: const Icon(Icons.chevron_left),
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

一些快照:
| 屏幕|主抽屉|迷你抽屉|
| --|--|--|
|

|

|

|

lsmd5eda

lsmd5eda2#

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

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'),
          ],
        ),
      ),
    );
  }

相关问题