Flutter floatingActionButton自定义的问题

701 阅读1分钟

floatingActionButton的一些常见用法我就不说了,如果遇到跟bottomNavigationBar结合使用的时候,可以参考一下这篇文章。

需求上要在bottomNavigationBar中间加上一个自定义的按钮,这个按钮和BottomNavigationBarItem要在同一水平线上居中,floatingActionButtonLocation已经提供了很多个位置,但是不能满足我们的需求,所以自定了这个类FloatingActionButtonLocation:

class FloatingButtonCustomLocation extends FloatingActionButtonLocation {
  FloatingActionButtonLocation location;
  final double offsetX; // X方向的偏移量
  final double offsetY; // Y方向的偏移量

  FloatingButtonCustomLocation(this.location,
      {this.offsetX = 0, this.offsetY = 0});

  @override
  Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {
    Offset offset = location.getOffset(scaffoldGeometry);
    return Offset(offset.dx + offsetX, offset.dy + offsetY);
  }
}

这样子就可以修改按钮的位置:

floatingActionButton: SizedBox(
  child: FloatingActionButton(
    backgroundColor: Colors.transparent,
    child: Image.asset("images/tab/plus.png",
        width: 40, height: 40, fit: BoxFit.cover),
    onPressed: () {},
  ),
),
floatingActionButtonLocation: FloatingButtonCustomLocation(
    FloatingActionButtonLocation.centerDocked,
    offsetY: Platform.isIOS && Screen.bottomBarHeight > 0 ? 25 : -10,
    offsetX: 0),

image.png 看到效果ok了,但是会有一个问题,切换tab的时候中间的按钮会闪动,现象如下:

屏幕录制2022-10-11 11.33.34.gif 后来查看文档发现Scaffold还有一个属性floatingActionButtonAnimator

/// If null, the [ScaffoldState] will use the default animator, [FloatingActionButtonAnimator.scaling].
final FloatingActionButtonAnimator? floatingActionButtonAnimator;

原来是ScaffoldState搞的怪,Scaffold如果不实现这个动画,默认就会实现缩放的一个效果,setState的时候就会触发这个动画:

onTap: (int index) {
  setState(() {
    _currentIndex = index; // 这里会触发floatingActionButton动画
  });
},

如果没有自定义floatingActionButtonLocation是不会有这个问题的,猜测是自定义floatingActionButtonLocation导致位置变化,导致每次都会刷新触发动画。

来到正题,我们需要自定义FloatingActionButtonAnimator

class ScalingCustomAnimation extends FloatingActionButtonAnimator{
  late double _x;
  late double _y;
  @override
  Offset getOffset({required Offset begin, required Offset end, required double progress}) {
    _x = begin.dx +(end.dx - begin.dx)*progress ;
    _y = begin.dy +(end.dy - begin.dy)*progress;
    return Offset(_x,_y);
  }

  @override
  Animation<double> getRotationAnimation({required Animation<double> parent}) {
    return Tween<double>(begin: 1.0, end: 1.0).animate(parent);
  }

  @override
  Animation<double> getScaleAnimation({required Animation<double> parent}) {
    return Tween<double>(begin: 1.0, end: 1.0).animate(parent);
  }
}

使用:

floatingActionButton: SizedBox(
  child: FloatingActionButton(
    backgroundColor: Colors.transparent,
    child: Image.asset("images/tab/plus.png",
        width: 40, height: 40, fit: BoxFit.cover),
    onPressed: () {},
  ),
),
// floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButtonLocation: FloatingButtonCustomLocation(
    FloatingActionButtonLocation.centerDocked,
    offsetY: Platform.isIOS && Screen.bottomBarHeight > 0 ? 25 : -10,
    offsetX: 0),
floatingActionButtonAnimator: ScalingCustomAnimation()

stop后重新运行,发现不会闪动了,大功告成!

屏幕录制2022-10-11 11.43.25.gif