如何在Appbar抖动中放置项目

时间:2020-10-28 09:21:36

标签: flutter

我正在尝试实现以下渲染:

enter image description here

但是我不能在蓝色背景上重叠ClipOval(配置文件图标)。这是我的代码:

  Widget build(BuildContext context) {
    return OrientationBuilder(
      builder: (context, orientation) {
        return Scaffold(
          key: _scaffoldKey,
          //empty Appbar will detect that there is a endDrawer, so will add by default a menu icon
          body: Column(
            children: <Widget>[
              AppBarProfile(
                height: 150.0,
                firstIcon: IconButton(
                  onPressed: () {
                    // to open the drawer
                    _scaffoldKey.currentState.openEndDrawer();
                  },
                  icon: Container(
                    child: Icon(Icons.settings),
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(4),
                      border: Border.all(color: Colors.white),
                    ),
                  ),
                ),
             title: 'My Profile',
                child: ClipOval(
                  child: Container(
                    color: Colors.white,
                    height: 100,
                    width: 100,
                    child: Container(
                      margin: const EdgeInsets.all(4),
                      decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        border: Border.all(
                            color: TheBaseColors.lightBlue, width: 2),
                      ),
                      child: Icon(
                        Icons.person,
                        size: 80,
                        color: TheBaseColors.lightBlue,
                      ),
                    ),
                  ),
                ),
              ),
              Expanded(
                child: Text('I am the body of the screen'),
              ),
            ],
          ),

以下是我的AppBAr的代码,它是在一个单独的文件中完成的,因此我可以多次调用它,并根据标题,应用栏的高度等更改所需的值:

class AppBarProfile extends StatelessWidget {
  final Widget firstIcon, child;
  final String title;
  final double height, childHeight;

  const AppBarProfile({
    Key key,
    this.firstIcon,
    this.title,
    this.height,
    this.childHeight,
    this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        ClipPath(
          clipper: _AppBarProfileClipper(childHeight),
          child: Container(
            padding: const EdgeInsets.only(top: 30.0),
            color: TheBaseColors.lightBlue,
            height: height,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Row(
                  // mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    Positioned(left: 0, top: 0, child: firstIcon),
                    Text(
                      title,
                      style: TextStyle(
                        fontWeight: FontWeight.w600,
                        fontSize: 18.0,
                        color: Colors.white,
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
        Positioned(
          bottom: 60, //50
          left: 0,
          right: 0,
          child: Align(
            alignment: Alignment.bottomCenter,
            child: child,
          ),
        ),
      ],
    );
  }
}

class _AppBarProfileClipper extends CustomClipper<Path> {
  final double childHeight;

  _AppBarProfileClipper(this.childHeight);

  @override
  Path getClip(Size size) {
    var path = Path();
    path.moveTo(0, size.height - 40.0);
    path.quadraticBezierTo(
        size.width / 2, size.height, size.width, size.height - 40.0);
    path.lineTo(size.width, 0);
    path.lineTo(0, 0);
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
}

代码的结果如下:

enter image description here

2 个答案:

答案 0 :(得分:1)

这是您最终结果的一种实现,我尝试保留与您代码中相同的参数:

代码

class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
  final Widget firstIcon;
  final Widget child;
  final String title;
  final double height;
  final double childHeight;
  final Color color;

  CustomAppBar({
    Key key,
    @required this.title,
    this.height = 200.0,
    @required this.childHeight,
    this.color = Colors.black,
    @required this.firstIcon,
    @required this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox.fromSize(
      size: preferredSize,
      child: LayoutBuilder(
        builder: (context, constraint) {
          return Stack(
            children: <Widget>[
              ClipPath(
                clipper: _AppBarProfileClipper(height),
                child: Container(
                  width: double.maxFinite,
                  height: preferredSize.height - childHeight,
                  color: color,
                  alignment: Alignment.topCenter,
                  child: Row(
                    children: <Widget>[
                      if (firstIcon != null) firstIcon,
                      if (firstIcon != null) Expanded(child: Container()),
                      Text(
                        title,
                        style: Theme.of(context)
                            .textTheme
                            .headline6
                            .copyWith(color: Colors.white),
                      ),
                      Expanded(child: Container()),
                      IconButton(
                        icon: Icon(
                          Icons.settings,
                          color: Colors.white,
                        ),
                        onPressed: () {},
                      ),
                    ],
                  ),
                ),
              ),
              Positioned.fill(
                child: Align(
                  alignment: Alignment.bottomCenter,
                  child: child,
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  @override
  Size get preferredSize => Size.fromHeight(height);
}

Try the full example on DartPad

我正在使用PreferredSizeWidget,因此您可以将其直接用作AppBar中的Scaffold

Scaffold(
   appBar: CustomAppBar(
      title: 'User Profile',
      childHeight: 40.0,
      firstIcon: firstIconWidget,
      child: childWidget,
   ),
);

屏幕截图 enter image description here

答案 1 :(得分:0)

您是否尝试过使用Align小部件?

 @override
 Widget build(BuildContext context) {
   const double profile_side = 200;
   const double background_height = 300;
   const double widget_height = background_height + profile_side/2;
   return Scaffold(


     body: Container(
        color: Colors.white,
        height: widget_height,
        child: Stack(
          children: [
            Container(
              color: Colors.blue,
              height: background_height,
              width: double.infinity,
            ),
            Align(
              alignment: Alignment(0.0, 1),
              child: Container(
                color: Colors.yellow,
                height: profile_side,
                width: profile_side,
              ),
            ),
            Align(
              alignment: Alignment(0,-0.8),
              child: Text('My Profile',style: TextStyle(color: Colors.white,fontWeight: FontWeight.w700,fontSize: 24),),
            ),
            Align(
              alignment: Alignment(-0.9, -0.8),
              child: Icon(Icons.menu),
            ),
            Align(
              alignment: Alignment(0.9, -0.8),
              child: Icon(Icons.settings),
            ),
          ],
        ),
      ),
    );
  }

Result