Flutter:卡片布局,卡片顶部有中心圆圈

Flutter: Card layout with centered circle on top of card

我对 flutter 还很陌生,我正在尝试制作一张包含两个部分的卡片,每个部分占 space 的一半。然后我想要一个位于卡片中心顶部的头像圆圈图像小部件,如图所示。

目前代码如下所示(包括两部分):

@override
  Widget build(BuildContext context) {
    // it enable scrolling on small device
    return Center(
      child: Card(
        margin: const EdgeInsets.all(10.0),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(16),
        ),
        color: cardColor,
        child: Flex(
          direction: Axis.vertical,
          children: [
            Expanded(
              child: ClipRRect(
                  borderRadius: const BorderRadius.only(
                      topLeft: Radius.circular(16),
                      topRight: Radius.circular(16)),
                  child: Container(
                    child: Image.asset("assets/images/card_background.jpg",
                        fit: BoxFit.fill),
                  )),
            ),
            Expanded(
              child: Column(
                children: [
                  Container(
                    child: Text("Test"),
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }

因此,我想知道如何才能让头像图像如图所示定位。或者如果我现在拥有的代码甚至有可能。在那种情况下,我想知道我应该使用哪些小部件来解决这个问题。

感谢您的帮助!

如果我没理解错的话,你想要一个 Card 的背景图片和一个位于顶部中央的 CircleAvatar 小部件。

您可以像这样使用 Stack 来做到这一点:

Card(
  margin: const EdgeInsets.all(10),
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(16),
  ),
  clipBehavior: Clip.antiAlias,
  color: cardColor,
  child: Stack(
    children: [
      Positioned.fill(
        child: Image.asset(
          'assets/images/card_background.jpg',
          fit: BoxFit.fill,
        ),
      ),
      const Positioned.fill(
        child: Align(
          alignment: Alignment.topCenter
          child: CircleAvatar(
            backgroundColor: Colors.orangeAccent,
          ),
        ),
      )
    ],
  )
),

你走在正确的轨道上,有一个Column(或Flex)和2个Expanded来平分它。您只需要另一个 Stack 小部件来覆盖顶部的圆圈。您可以用 Align 小部件包裹圆圈并将其设置为对齐 center-left.

代码看起来像这样:

Stack
 Column
   - Expanded
   - Expanded
 Align
   - Circle

没有什么是一个简单的 Stack 小部件无法解决的。


@override
  Widget build(BuildContext context) {
    // it enable scrolling on small device
    return Center(
      child: Card(
        margin: const EdgeInsets.all(10.0),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(16),
        ),
        color: Colors.blue,
        child: Stack(
          children: [
            Flex(
              direction: Axis.vertical,
              children: [
                Expanded(
                  child: ClipRRect(
                    borderRadius: const BorderRadius.only(
                      topLeft: Radius.circular(16),
                      topRight: Radius.circular(16)),
                    child: Container(
                      color: Colors.red,
                    )),
                ),
                Expanded(
                  child: Column(
                    children: [
                      Container(
                        child: Text("Test"),
                      )
                    ],
                  ),
                )
              ],
            ),
            
            // align a circle center and left, with a left margin
            Align(
              alignment: Alignment.centerLeft,
              child: Container(
                margin: const EdgeInsets.only(left: 20),
                child: ClipOval(
                  child: Container(
                    width: 80,
                    height: 80,
                    color: Colors.black
                  )
                )
              )
           )
          ] 
        ),
      ),
    );
  }

您可以使用 Stack 小部件将小部件放置在其他小部件之上。 试试这个代码

    @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: [
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                children: [
                  Expanded(
                    child: Container(
                      decoration: const BoxDecoration(
                        borderRadius: BorderRadius.only(topLeft: Radius.circular(10),topRight: Radius.circular(10)),
                        color: Colors.blue
                      ),
                    ),
                  ),
                  Expanded(
                    child: Container(
                      decoration: const BoxDecoration(
                          borderRadius: BorderRadius.only(bottomLeft: Radius.circular(10),bottomRight: Radius.circular(10)),
                          color: Colors.red
                      ),
                    ),
                  )
                ],
              ),
            ),
            Positioned.fill(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: const [
                  Padding(
                    padding: EdgeInsets.only(left: 20),
                    child: CircleAvatar(
                      radius: 40,
                      backgroundColor: Colors.grey,
                    ),
                  ),
                ],
              ),
            )
          ],
        )
      ),
    );
  }