【问题标题】:How to design a flutter semi circular menu with dynamic radius如何设计具有动态半径的颤动半圆形菜单
【发布时间】:2020-10-11 11:34:00
【问题描述】:

帮助,我正在尝试创建一个像这样的半圆形菜单,image of what I want here

但我不知道如何将小部件放置在较大的白线之上...我已尝试使用以下代码。请将该小部件用作 main.dart 中的主页小部件并查看结果。我在包 pub 中使用了 font_awesome_flutter 包作为图标:-

image of how it is currently here

import 'package:flutter/material.dart';
import 'dart:math';
import 'package:vector_math/vector_math.dart' show radians, Vector3;
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

class Homewidgettoslack extends StatefulWidget {
  Homewidgettoslack({
    Key key,
  }) : super(key: key);

  @override
  _HomewidgettoslackState createState() => _HomewidgettoslackState();
}

class _HomewidgettoslackState extends State<Homewidgettoslack> with TickerProviderStateMixin {
  Animation<double> rotation;
  Animation<double> translation;
  Animation<double> menuscale;
  AnimationController menuController;

  @override
  void initState() {
    super.initState();
    menuController =
        AnimationController(duration: Duration(milliseconds: 900), vsync: this);
    rotation = Tween<double>(
      begin: 0.0,
      end: 1.0,
    ).animate(
      CurvedAnimation(
        parent: menuController,
        curve: Interval(
          0.0,
          0.7,
          curve: Curves.decelerate,
        ),
      ),
    );
    translation = Tween<double>(
      begin: 0.0,
      end: 100.0,
    ).animate(
      CurvedAnimation(parent: menuController, curve: Curves.elasticOut),
    );

    menuscale = Tween<double>(
      begin: 1.5,
      end: 0.0,
    ).animate(
      CurvedAnimation(parent: menuController, curve: Curves.fastOutSlowIn),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blueGrey,
      child: Scaffold(
        backgroundColor: Colors.transparent,
        body: Stack(
          children: <Widget>[
            Positioned(
              left: -27,
              right: -27,
              top: 57,
              bottom: 57,
              child: Container(
                height: MediaQuery.of(context).size.height,
                width: MediaQuery.of(context).size.width,
                child: CustomPaint(
                  painter: CurvedblacklinePainter(),
                ),
              ),
            ),
            Container(
              height: MediaQuery.of(context).size.height,
              width: MediaQuery.of(context).size.width,
              child: CustomPaint(
                painter: CurvedblacklinePainter(),
              ),
            ),
            Container(
              height: MediaQuery.of(context).size.height,
              width: MediaQuery.of(context).size.width,
              child: AnimatedBuilder(
                animation: menuController,
                builder: (context, widget) {
                  return Transform.rotate(
                    angle: radians(rotation.value),
                    child:
                        Stack(alignment: Alignment.center, children: <Widget>[
                      _buildButton(0,
                          color: Colors.red, icon: FontAwesomeIcons.thumbtack),
                      _buildButton(45,
                          color: Colors.green, icon: FontAwesomeIcons.sprayCan),
                      _buildButton(90,
                          color: Colors.orange, icon: FontAwesomeIcons.fire),
                      _buildButton(270,
                          color: Colors.pink, icon: FontAwesomeIcons.car),
                      _buildButton(315,
                          color: Colors.yellow, icon: FontAwesomeIcons.bolt),
                      Transform.scale(
                        scale: menuscale.value - 1,
                        child: FloatingActionButton(
                            child: Icon(FontAwesomeIcons.timesCircle),
                            onPressed: _close,
                            backgroundColor: Colors.red),
                      ),
                      Transform.scale(
                        scale: menuscale.value,
                        child: FloatingActionButton(
                            child: Icon(
                              FontAwesomeIcons.solidDotCircle,
                              color: Colors.red,
                            ),
                            onPressed: _open),
                      )
                    ]),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }

  _buildButton(double angle, {Color color, IconData icon}) {
    final double rad = radians(angle);
    return Transform(
        transform: Matrix4.identity()
          ..translate(
              (translation.value) * cos(rad), (translation.value) * sin(rad)),
        child: FloatingActionButton(
            child: Icon(icon),
            backgroundColor: color,
            onPressed: _close,
            elevation: 0));
  }

  _open() {
    print('OPEN CLICKED');
    menuController.forward();
  }

  _close() {
    print('CLOSE CLICKED');
    menuController.reverse();
  }
}

class CurvedblacklinePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = new Paint()
      ..color = Colors.white
      ..strokeWidth = 1.8
      ..style = PaintingStyle.stroke;

    Path path = Path();
    path.moveTo(0, 0);

    var secondEndPoint = Offset(0, size.height);
    path.arcToPoint(secondEndPoint,
        radius: Radius.circular((size.width / 2)),
        clockwise: true,
        largeArc: false);

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

【问题讨论】:

    标签: android ios flutter user-interface mobile


    【解决方案1】:

    我改进了您的代码,并将其修复如下,

    请用你的代码替换我的代码

    import 'dart:math';
    
    import 'package:flutter/material.dart';
    import 'package:flutter_screenutil/flutter_screenutil.dart';
    import 'package:font_awesome_flutter/font_awesome_flutter.dart';
    import 'package:vector_math/vector_math.dart' show radians, Vector3;
    
    class Homewidgettoslack extends StatefulWidget {
      Homewidgettoslack({
        Key key,
      }) : super(key: key);
    
      @override
      _HomewidgettoslackState createState() => _HomewidgettoslackState();
    }
    
    class _HomewidgettoslackState extends State<Homewidgettoslack>
        with TickerProviderStateMixin {
      Animation<double> rotation;
      Animation<double> translationY;
      Animation<double> translationX;
      Animation<double> menuscale;
      AnimationController menuController;
    
      double _menuIconSize;
    
      @override
      void initState() {
        super.initState();
        menuController =
            AnimationController(duration: Duration(milliseconds: 900), vsync: this);
        rotation = Tween<double>(
          begin: 0.0,
          end: 1.0,
        ).animate(
          CurvedAnimation(
            parent: menuController,
            curve: Interval(
              0.0,
              0.7,
              curve: Curves.decelerate,
            ),
          ),
        );
    
        menuscale = Tween<double>(
          begin: 1.5,
          end: 0.0,
        ).animate(
          CurvedAnimation(parent: menuController, curve: Curves.fastOutSlowIn),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        ScreenUtil.init(width: 360, height: 640, allowFontScaling: false);
        _menuIconSize = ScreenUtil().setWidth(60);
        double _bigCurveHeight = ScreenUtil().setHeight(520);
        double _bigCurveWidth = ScreenUtil().setWidth(250);
    
        translationY = Tween<double>(
          begin: 0.0,
          end: ((_bigCurveHeight / 2) - (_menuIconSize / 2)),
        ).animate(
          CurvedAnimation(parent: menuController, curve: Curves.elasticOut),
        );
    
        translationX = Tween<double>(
          begin: 0.0,
          end: (_bigCurveWidth - (_menuIconSize / 2)),
        ).animate(
          CurvedAnimation(parent: menuController, curve: Curves.elasticOut),
        );
    
        return Container(
          color: Colors.blueGrey,
          child: Scaffold(
            backgroundColor: Colors.transparent,
            body: Align(
              alignment: Alignment.centerLeft,
              child: Stack(
                alignment: Alignment.centerLeft,
                children: <Widget>[
                  Container(
                    height: _bigCurveHeight,
                    width: _bigCurveWidth,
                    child: CustomPaint(
                      painter: CurvedblacklinePainter(strokeWidth: 2),
                    ),
                  ),
                  Container(
                    height: ScreenUtil().setHeight(350),
                    width: ScreenUtil().setWidth(130),
                    child: CustomPaint(
                      painter: CurvedblacklinePainter(
                          strokeWidth: ScreenUtil().setWidth(60)),
                    ),
                  ),
                  Container(
                    child: AnimatedBuilder(
                      animation: menuController,
                      builder: (context, widget) {
                        return Transform.rotate(
                          angle: radians(rotation.value),
                          child:
                              Stack(alignment: Alignment.center, children: <Widget>[
                            _buildButton(0,
                                color: Colors.red,
                                icon: FontAwesomeIcons.thumbtack),
                            _buildButton(45,
                                color: Colors.green,
                                icon: FontAwesomeIcons.sprayCan),
                            _buildButton(90,
                                color: Colors.orange, icon: FontAwesomeIcons.fire),
                            _buildButton(270,
                                color: Colors.pink, icon: FontAwesomeIcons.car),
                            _buildButton(315,
                                color: Colors.yellow, icon: FontAwesomeIcons.bolt),
                            Transform.scale(
                              scale: menuscale.value - 1,
                              child: FloatingActionButton(
                                  child: Icon(FontAwesomeIcons.timesCircle),
                                  onPressed: _close,
                                  backgroundColor: Colors.red),
                            ),
                            Transform.scale(
                              scale: menuscale.value,
                              child: FloatingActionButton(
                                  child: Icon(
                                    FontAwesomeIcons.solidDotCircle,
                                    color: Colors.red,
                                  ),
                                  onPressed: _open),
                            )
                          ]),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    
      _buildButton(double angle, {Color color, IconData icon}) {
        final double rad = radians(angle);
        return Transform(
            transform: Matrix4.identity()
              ..translate(
                  (translationX.value) * cos(rad), (translationY.value) * sin(rad)),
            child: FloatingActionButton(
                child: Icon(icon),
                backgroundColor: color,
                onPressed: _close,
                elevation: 0));
      }
    
      _open() {
        print('OPEN CLICKED');
        menuController.forward();
      }
    
      _close() {
        print('CLOSE CLICKED');
        menuController.reverse();
      }
    }
    
    class CurvedblacklinePainter extends CustomPainter {
      final double strokeWidth;
    
      CurvedblacklinePainter({@required this.strokeWidth});
    
      @override
      void paint(Canvas canvas, Size size) {
        Paint paint = new Paint()
          ..color = Colors.white
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke;
    
        canvas.drawOval(
            Rect.fromCenter(
                center: Offset(-size.width / 2, size.height / 2),
                width: size.width * 3,
                height: size.height),
            paint);
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) {
        return true;
      }
    }
    
    

    并在您的 pubspec.yaml 中添加依赖项:

    dev_dependencies:
      flutter_test:
        sdk: flutter
      font_awesome_flutter: ^8.8.1
      flutter_screenutil: ^2.1.0
    

    结果截图:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      • 2017-04-07
      • 1970-01-01
      • 2018-10-05
      • 1970-01-01
      • 2018-02-24
      • 2014-01-20
      相关资源
      最近更新 更多