繁体   English   中英

如何制作浮动的 BottomAppBar?

[英]How to make floating BottomAppBar?

我在 flutter 应用程序中工作。 但是我很难使用 Flutter UI,因为它与 UI 不完全匹配。

这是UI设计。

这是UI设计

这是当前的 flutter 用户界面。

这是当前的 Flutter UI

这是我的代码。

      Widget buildBottomBar() {
    return BottomAppBar(
      elevation: 0.0,
      shape: const CircularNotchedRectangle(),
      notchMargin: 5.0,
      clipBehavior: Clip.antiAlias,
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(
            width: 10,
            color: Colors.transparent,
          ),
        ),
        child: BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          iconSize: 28,
          elevation: 0.0,
          currentIndex: selectedIndex,
          selectedLabelStyle: robotoStyle(FontWeight.w500,
              const Color.fromARGB(255, 49, 48, 54), null, null),
          showUnselectedLabels: true,
          unselectedLabelStyle:
              robotoStyle(FontWeight.w500, const Color(0xff313036), null, null),
          unselectedItemColor: const Color(0xff313036),
          selectedItemColor: const Color(0xff313036),
          selectedIconTheme: const IconThemeData(color: Color(0xffff2323)),
          onTap: onBottomBarButtonTapped,
          backgroundColor: Colors.transparent,
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              activeIcon: Icon(
                Icons.signal_cellular_alt_rounded,
                color: Color(0xffff2323),
              ),
              icon: Icon(
                Icons.signal_cellular_alt_rounded,
                color: Color(0xff313036),
              ),
              label: "Trend",
            ),
            BottomNavigationBarItem(
              activeIcon: Icon(
                CupertinoIcons.calendar,
                color: Color(0xffff2323),
              ),
              icon: Icon(
                CupertinoIcons.calendar,
                color: Color(0xff313036),
              ),
              label: "Calendar",
            ),
            BottomNavigationBarItem(
              activeIcon: Icon(
                Icons.search_rounded,
                color: Colors.transparent,
              ),
              icon: Icon(
                Icons.search_rounded,
                color: Colors.transparent,
              ),
              label: "",
            ),
            BottomNavigationBarItem(
              activeIcon: Icon(
                CupertinoIcons.arrow_2_circlepath,
                color: Color(0xffff2323),
              ),
              icon: Icon(
                CupertinoIcons.arrow_2_circlepath,
                color: Color(0xff313036),
              ),
              label: "Restock",
            ),
            BottomNavigationBarItem(
              activeIcon: Icon(
                Icons.account_circle,
                color: Color(0xffff2323),
              ),
              icon: Icon(
                Icons.account_circle,
                color: Color(0xff313036),
              ),
              label: "Account",
            ),
          ],
        ),
      ),
      // ),
    );
  }

 Widget build(BuildContext context) {
    return Scaffold(
      extendBody: true,
      resizeToAvoidBottomInset: false,
      appBar: null,
      backgroundColor: Colors.white,
      body: ...,
      bottomNavigationBar: buildBottomBar(),
      floatingActionButton: Padding(
        padding: const EdgeInsets.all(5.0),
        child: FloatingActionButton(...)
      ),
  }

下一个问题就是浮动搜索按钮下的半径。 如何应用这种设计的边框半径?

尽快让我知道怎么做。

我是通过自定义标准package来解决的。出现这种现象的原因是边缘被应用的Margin或Padding推到了右边。 也就是说,解决方案是将限幅器向左或向右移动与应用的边距或填充一样多。 然后,我将在下面提供一个分步解决方案。

  1. 在 BottomAppBar() 上按 Ctrl+B(对于 Android Studio)或 F12(对于 VS Code)。
  1. 单击目标按钮。

    在此处输入图像描述

  1. bottom_app_bar.dart 复制到您的自定义库目录,然后重命名custom_bottom_app_bar.dart

在此处输入图像描述

  1. 修改新的custom_bottom_app_bar.dart中的部分代码。

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

  1. 全部做完。 享受新的小部件。 在此处输入图像描述
  1. 我将在下面添加完整的示例代码。

custom_bottom_app_bar.dart

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.*

import 'package:flutter/foundation.dart';
// import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';

// import 'bottom_app_bar_theme.dart';
// import 'elevation_overlay.dart';
// import 'package:flutter/material.dart';
// import 'scaffold.dart';
// import 'theme.dart';

// Examples can assume:
// late Widget bottomAppBarContents;

/// A container that is typically used with [Scaffold.bottomNavigationBar], and
/// can have a notch along the top that makes room for an overlapping
/// [FloatingActionButton].
///
/// Typically used with a [Scaffold] and a [FloatingActionButton].
///
/// {@tool snippet}
/// ```dart
/// Scaffold(
///   bottomNavigationBar: CustomBottomAppBar(
///     color: Colors.white,
///     child: bottomAppBarContents,
///   ),
///   floatingActionButton: const FloatingActionButton(onPressed: null),
/// )
/// ```
/// {@end-tool}
///
/// {@tool dartpad}
/// This example shows the [CustomBottomAppBar], which can be configured to have a notch using the
/// [CustomBottomAppBar.shape] property. This also includes an optional [FloatingActionButton], which illustrates
/// the [FloatingActionButtonLocation]s in relation to the [CustomBottomAppBar].
///
/// ** See code in examples/api/lib/material/bottom_app_bar/bottom_app_bar.1.dart **
/// {@end-tool}
///
/// See also:
///
///  * [NotchedShape] which calculates the notch for a notched [CustomBottomAppBar].
///  * [FloatingActionButton] which the [CustomBottomAppBar] makes a notch for.
///  * [AppBar] for a toolbar that is shown at the top of the screen.
class CustomBottomAppBar extends StatefulWidget {
  /// Creates a bottom application bar.
  ///
  /// The [clipBehavior] argument defaults to [Clip.none] and must not be null.
  /// Additionally, [elevation] must be non-negative.
  ///
  /// If [color], [elevation], or [shape] are null, their [BottomAppBarTheme] values will be used.
  /// If the corresponding [BottomAppBarTheme] property is null, then the default
  /// specified in the property's documentation will be used.
  const CustomBottomAppBar({
    super.key,
    this.color,
    this.elevation,
    this.shape,
    this.clipBehavior = Clip.none,
    this.notchMargin = 4.0,
    this.child,
    this.positionInHorizontal = 0.0,
  }) : assert(elevation == null || elevation >= 0.0);

  /// The widget below this widget in the tree.
  ///
  /// {@macro flutter.widgets.ProxyWidget.child}
  ///
  /// Typically this the child will be a [Row], with the first child
  /// being an [IconButton] with the [Icons.menu] icon.
  final Widget? child;

  /// The bottom app bar's background color.
  ///
  /// If this property is null then [BottomAppBarTheme.color] of
  /// [ThemeData.bottomAppBarTheme] is used. If that's null then
  /// [ThemeData.bottomAppBarColor] is used.
  final Color? color;

  /// The z-coordinate at which to place this bottom app bar relative to its
  /// parent.
  ///
  /// This controls the size of the shadow below the bottom app bar. The
  /// value is non-negative.
  ///
  /// If this property is null then [BottomAppBarTheme.elevation] of
  /// [ThemeData.bottomAppBarTheme] is used. If that's null, the default value
  /// is 8.
  final double? elevation;

  /// The notch that is made for the floating action button.
  ///
  /// If this property is null then [BottomAppBarTheme.shape] of
  /// [ThemeData.bottomAppBarTheme] is used. If that's null then the shape will
  /// be rectangular with no notch.
  final NotchedShape? shape;

  /// {@macro flutter.material.Material.clipBehavior}
  ///
  /// Defaults to [Clip.none], and must not be null.
  final Clip clipBehavior;

  /// The margin between the [FloatingActionButton] and the [CustomBottomAppBar]'s
  /// notch.
  ///
  /// Not used if [shape] is null.
  final double notchMargin;

  final double positionInHorizontal;

  @override
  State createState() => _CustomBottomAppBarState();
}

class _CustomBottomAppBarState extends State<CustomBottomAppBar> {
  late ValueListenable<ScaffoldGeometry> geometryListenable;
  final GlobalKey materialKey = GlobalKey();
  static const double _defaultElevation = 8.0;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    geometryListenable = Scaffold.geometryOf(context);
  }

  @override
  Widget build(BuildContext context) {
    final BottomAppBarTheme babTheme = BottomAppBarTheme.of(context);
    final bool hasFab = Scaffold.of(context).hasFloatingActionButton;
    final NotchedShape? notchedShape = widget.shape ?? babTheme.shape;
    final CustomClipper<Path> clipper = notchedShape != null && hasFab
        ? _BottomAppBarClipper(
            geometry: geometryListenable,
            shape: notchedShape,
            materialKey: materialKey,
            notchMargin: widget.notchMargin,
            position2MoveHorizontal: widget.positionInHorizontal,
          )
        : const ShapeBorderClipper(shape: RoundedRectangleBorder());
    final double elevation =
        widget.elevation ?? babTheme.elevation ?? _defaultElevation;
    final Color color =
        widget.color ?? babTheme.color ?? Theme.of(context).bottomAppBarColor;
    final Color effectiveColor =
        ElevationOverlay.applyOverlay(context, color, elevation);
    return PhysicalShape(
      clipper: clipper,
      elevation: elevation,
      color: effectiveColor,
      clipBehavior: widget.clipBehavior,
      child: Material(
        key: materialKey,
        type: MaterialType.transparency,
        child: widget.child == null ? null : SafeArea(child: widget.child!),
      ),
    );
  }
}

class _BottomAppBarClipper extends CustomClipper<Path> {
  const _BottomAppBarClipper({
    required this.geometry,
    required this.shape,
    required this.materialKey,
    required this.notchMargin,
    required this.position2MoveHorizontal,
  }) : super(reclip: geometry);

  final ValueListenable<ScaffoldGeometry> geometry;
  final NotchedShape shape;
  final GlobalKey materialKey;
  final double notchMargin;
  final double position2MoveHorizontal;

  // Returns the top of the CustomBottomAppBar in global coordinates.
  //
  // If the Scaffold's bottomNavigationBar was specified, then we can use its
  // geometry value, otherwise we compute the location based on the AppBar's
  // Material widget.
  double get bottomNavigationBarTop {
    final double? bottomNavigationBarTop =
        geometry.value.bottomNavigationBarTop;
    if (bottomNavigationBarTop != null) {
      return bottomNavigationBarTop;
    }
    final RenderBox? box =
        materialKey.currentContext?.findRenderObject() as RenderBox?;
    return box?.localToGlobal(Offset.zero).dy ?? 0;
  }

  @override
  Path getClip(Size size) {
    // button is the floating action button's bounding rectangle in the
    // coordinate system whose origin is at the appBar's top left corner,
    // or null if there is no floating action button.

    final Rect? button = geometry.value.floatingActionButtonArea
        ?.translate(position2MoveHorizontal, bottomNavigationBarTop * -1.0);
    return shape.getOuterPath(Offset.zero & size, button?.inflate(notchMargin));
  }

  @override
  bool shouldReclip(_BottomAppBarClipper oldClipper) {
    return oldClipper.geometry != geometry ||
        oldClipper.shape != shape ||
        oldClipper.notchMargin != notchMargin;
  }
}

家.dart

Widget buildBottomBar() {
    Map bottomAppBarMargin = {
      'left': 20.0,
      'right': 20.0,
      'bottom': 12.0,
      'top': 0.0,
    };
    return Container(
      margin: EdgeInsets.only(
        left: bottomAppBarMargin['left'],
        right: bottomAppBarMargin['right'],
        bottom: bottomAppBarMargin['bottom'],
        top: bottomAppBarMargin['top'],
      ),
      child: CustomBottomAppBar(
        elevation: 0.0,
        positionInHorizontal: (0.0-bottomAppBarMargin['left']),
        color: Colors.white,
        shape: const CircularNotchedRectangle(),
        notchMargin: 5.0,
        clipBehavior: Clip.antiAlias,
        child: SizedBox(...)
      ),
    );
}

结果

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM