如何使用 CustomPainter 创建像 Flutter 中提供的图像一样的自定义 BottomNavigationBar?

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

我是使用 Flutter CustomPainter 的新手。我正在尝试实现一个BottomNavigationBar,如下图所示。

BottomNavigationBar with Path clipped at the middle and without animation

BottomNavigationBar 是静态的。单击按钮时,无动画曲线发生变化。并且没有页面转换。

我尝试了一些软件包,但它们要么有底部导航栏的动画,要么没有曲线。按钮是资产图像。

请帮助我实现设计。

flutter
1个回答
2
投票

我希望你考虑一下这个,

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

/// Flutter code sample for [FloatingActionButton].

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const FloatingActionButtonExample(),
    );
  }
}

class FloatingActionButtonExample extends StatefulWidget {
  const FloatingActionButtonExample({super.key});

  @override
  State<FloatingActionButtonExample> createState() =>
      _FloatingActionButtonExampleState();
}

class _FloatingActionButtonExampleState
    extends State<FloatingActionButtonExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FloatingActionButton Sample'),
      ),
      body: const Center(child: Text('Press the button below!')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            debugPrint('Hi I am DevQt');
          });
        },
        shape: RoundedRectangleBorder(
          side: BorderSide(color: Colors.transparent, width: 2.0),
          borderRadius: BorderRadius.circular(50),
        ),
        child: const Icon(
          CupertinoIcons.stop,
          grade: 5.0,
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: BottomAppBar(
        notchMargin: 6.0,
        shape: const CircularNotchedRectangle(),
        color: Colors.amberAccent,
        child: SizedBox(
          height: 50.0,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Align(
                alignment: Alignment.topLeft,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.speaker),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.bottomCenter,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: Text(
                    'End Session',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.topRight,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.video_camera),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

该代码最初不是我的;我只是使用 FloatingActionButton 类的源代码来即时实现小部件,并使用 Flutter 3.10:浮动操作按钮来实现

FloatingActionButton with notched BottomNavigationBar
。然后我就开始玩代码 XD。

这是设计输出:

output

更新

要遵循以下要求:

答案必须反映所提供图像的 UI 设计。这 底部导航栏高67px,加上顶部按钮, 总共 102 像素。它不应破裂或溢出。

我将代码重构为:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

/// Flutter code sample for [FloatingActionButton].

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const FloatingActionButtonExample(),
    );
  }
}

class FloatingActionButtonExample extends StatefulWidget {
  const FloatingActionButtonExample({super.key});

  @override
  State<FloatingActionButtonExample> createState() =>
      _FloatingActionButtonExampleState();
}

class _FloatingActionButtonExampleState
    extends State<FloatingActionButtonExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FloatingActionButton Sample'),
      ),
      body: const Center(child: Text('Press the button below!')),
      floatingActionButton: SizedBox(
        height: 35, // as per requirements and to achieve a rounded appearance
        width: 35, // as per requirements and to achieve a rounded appearance
        child: FloatingActionButton(
          onPressed: () {
            setState(() {
              debugPrint('Hi I am DevQt');
            });
          },
          shape: RoundedRectangleBorder(
            side: BorderSide(color: Colors.transparent, width: 2.0),
            borderRadius: BorderRadius.circular(35),
          ),
          child: const Icon(
            CupertinoIcons.stop,
            grade: 5.0,
          ),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: BottomAppBar(
        height: 67.0, // as per requirements
        notchMargin: 6.0,
        shape: const CircularNotchedRectangle(),
        color: Colors.amberAccent,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Align(
              alignment: Alignment.topLeft,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 8.0),
                child: IconButton(
                  iconSize: 25,
                  onPressed: () {},
                  icon: Icon(CupertinoIcons.speaker),
                ),
              ),
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 8.0),
                child: Text(
                  'End Session',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
              ),
            ),
            Align(
              alignment: Alignment.topRight,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 8.0),
                child: IconButton(
                  iconSize: 25,
                  onPressed: () {},
                  icon: Icon(CupertinoIcons.video_camera),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

我对此做了一个

simple arithmetic
,但仅针对相应的小部件,
a bottom navigation bar 67px high
the top button 35px high
(没有提到
maintain
的宽度,
UI aesthetic
显示为
circular button
)以获得总计102 像素不介意

notchMargin: 6.0

因为它不会影响您的固定总高度102px(即底部导航栏和顶部按钮的组合)

我在设备模式下使用开发人员工具使用 Google Chrome 浏览器进行了测试:

适用于 Mobile S - 320 像素分辨率

mobile-s-320px-res

适用于 Mobile M - 375 像素分辨率

mobile-s-375px-res

适用于 Mobile S - 425 像素分辨率

mobile-s-425px-res

如果您仍然想让事情响应(即,它不应该中断或溢出),您想要...

floating_button

然后,如果是这样,您可以应用这些代码更改:

bottomNavigationBar: BottomAppBar(
        height: 67.0,
        notchMargin: 6.0,
        shape: const CircularNotchedRectangle(),
        color: Colors.amberAccent,
        child: SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Align(
                alignment: Alignment.topLeft,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.speaker),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.bottomCenter,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: Text(
                    'End Session',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.topRight,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.video_camera),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
© www.soinside.com 2019 - 2024. All rights reserved.