4

I'm following the picture below but got some difficulties when I tried to make that white bubble.

enter image description here

I have tried a method using OverFlowBox from another post Flutter mask a circle into a container but I got the circle stuck in the middle of the Container and I don't know why alignment won't help moving it. Here is what I've tried:

return Container(
  alignment: Alignment.topCenter,
  height: screenHeight/3.5,
  width: screenWidth/3.5,
  decoration: BoxDecoration(
    borderRadius: BorderRadius.only(
      topLeft: Radius.circular(10),
      topRight: Radius.circular(60),
      bottomLeft: Radius.circular(10),
      bottomRight: Radius.circular(10),
    ),
    gradient: LinearGradient(
      begin: FractionalOffset.topLeft,
      end: FractionalOffset.bottomRight,
      colors: [boxColorBegin, boxColorEnd]
    ),
  ),
  child: ClipRect(
    clipBehavior: Clip.hardEdge,
    child: OverflowBox(
      maxHeight: screenHeight/3.5 +20,
      maxWidth: screenWidth/3.5 + 20,
      child:Container(
        decoration: BoxDecoration(
          color: Colors.white,
          shape: BoxShape.circle,
        ),
      )
    ),
  ),
);

And the result was

enter image description here

Is there any ways to overflow something inside a widget so that it looks like clipped?

Thanks in advance!

Kennith
  • 323
  • 3
  • 10
  • if you want some widget to overflow it's parent why do you use clip then? – pskink Aug 22 '20 at 06:54
  • cos I actually want the overflowed part to be clipped – Kennith Aug 22 '20 at 07:03
  • but if you want just to position your child you dont need `OverflowBox` at all: `child: Container( alignment: Alignment.topLeft, clipBehavior: Clip.antiAlias, decoration: BoxDecoration( borderRadius: BorderRadius.circular(30), color: Colors.grey, ), child: FractionalTranslation( translation: Offset(-0.25, -0.5), child: Container( width: 200, height: 200, decoration: BoxDecoration( color: Colors.orange, shape: BoxShape.circle, ), ), ), ),` – pskink Aug 22 '20 at 07:42
  • I seeee so you can use `Container` for clipping. I think your code is the simplest one without extra `Stack`, `ClipRRect` or duplicating `BorderRadius`. Do you want to leave an answer? – Kennith Aug 22 '20 at 08:02
  • "Do you want to leave an answer? " just edit your self answer and add alternate solution with `clipBehavior` and `FractionalTranslation` – pskink Aug 22 '20 at 08:06
  • Alright. Thanks! – Kennith Aug 22 '20 at 08:08
  • 1
    sure, your welcome, btw you could avoid `FractionalTranslation` too and instead of `Alignment.topLeft` use `Alignment(-1, -2)` or something but when using `FractionalTranslation` you have more precise control on how to position the child widget – pskink Aug 22 '20 at 08:12

3 Answers3

3

I found the way to achieve what I want but am still confused why OverFlowBox can't be aligned. I thought it is because the size of the OverFlowBox is larger than its parent but it still don't work when I changed it to a smaller size.

I used Stack and Positioned widget and set the overflow parameter of the Stack as overflow.clip

Here is the code:

return Container(
  height: screenHeight/3.5,
  width: screenWidth/3.2,
  decoration: BoxDecoration(
    borderRadius: BorderRadius.only(
      topLeft: Radius.circular(10),
      topRight: Radius.circular(60),
      bottomLeft: Radius.circular(10),
      bottomRight: Radius.circular(10),
    ),
    gradient: LinearGradient(
      begin: FractionalOffset.topLeft,
      end: FractionalOffset.bottomRight,
      colors: [boxColorBegin, boxColorEnd]
    ),
  ),
  child: Stack(
    overflow: Overflow.clip,
    alignment: Alignment.topCenter ,
    children: <Widget>[
      Positioned(
        bottom: screenHeight / 8,
        right: screenWidth / 12,
        child: Container(
          width: screenWidth / 3.5,
          height: screenHeight / 3.5,
          decoration: BoxDecoration(
            color: Colors.white38,
            shape: BoxShape.circle,
          ),
        )
      )
    ],
  )
)

And the result is

enter image description here

EDIT

Turns out you can just use Container as a clipper with the clipBehavior parameter and use FractionalTranslation widget as child to manipulate the position of the white circle. Thanks to pskink for the simple answer.

Here is the new code

return Container(
  alignment: Alignment.topLeft,
  clipBehavior: Clip.antiAlias,
  height: screenHeight/3.5,
  width: screenWidth/3.2,
  decoration: BoxDecoration(
    borderRadius: BorderRadius.only(
      topLeft: Radius.circular(10),
      topRight: Radius.circular(60),
      bottomLeft: Radius.circular(10),
      bottomRight: Radius.circular(10),
    ),
    gradient: LinearGradient(
      begin: FractionalOffset.topLeft,
      end: FractionalOffset.bottomRight,
      colors: [boxColorBegin, boxColorEnd]
    ),
  ),
  child: FractionalTranslation(
    translation: Offset(-0.25, -0.5),
    child: Container(
      width: screenWidth / 3.5,
      height: screenHeight / 3.5,
      decoration: BoxDecoration(
        color: Colors.white38,
        shape: BoxShape.circle,
      ),
    )
  )
);
Kennith
  • 323
  • 3
  • 10
  • I wish I could give you 3 upvotes – Pythogen Jan 02 '23 at 02:33
  • i don't get why did you put `Stack.overflow` there. i thought it's because you're get carried away from the site name :D can you please correct it because there's no `Stack.overflow` property in flutter? – stackunderflow Jan 15 '23 at 14:42
1

You can easily accomplish this using ClipRRect as your root container for this widget. Provide it a border radius and it will clip all children and prevent them from painting outside the bounds. You can then use Transform.translate to render a circle and offset it outside its parent.

I created a sample pen for you to try

return ClipRRect(
  borderRadius: BorderRadius.only(
    topLeft: Radius.circular(8),
    bottomLeft: Radius.circular(8),
    bottomRight: Radius.circular(8),
    topRight: Radius.circular(125),
  ),
  child: Container(
    height: 400,
    width: 250,
    decoration: BoxDecoration(
      color: Colors.red,
    ),
    child: Stack(
      children: [
        Align(
          alignment: Alignment.topLeft,
          child: Transform.translate(
            offset: Offset(-40, -100),
            child: Container(
              height: 220,
              width: 220,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(110)),
                color: Colors.white.withOpacity(0.4),
              ),
            ),
          ),
        ),
      ],
    ),
  ),
);

For more information on ClipRRect and Transform.translate visit the API docs.

Nemi Shah
  • 856
  • 1
  • 7
  • 11
0

you can use padding to move the OverflowBox. you also need to clip the parent Container with ClipRRect

here is your fix (tested and works):

return ClipRRect(
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(10),
            topRight: Radius.circular(60),
            bottomLeft: Radius.circular(10),
            bottomRight: Radius.circular(10),
          ),
          child: Container(
            alignment: Alignment.topCenter,
            height: screenHeight / 3.5,
            width: screenWidth / 3.5,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(10),
                topRight: Radius.circular(60),
                bottomLeft: Radius.circular(10),
                bottomRight: Radius.circular(10),
              ),
              gradient: LinearGradient(
                  begin: FractionalOffset.topLeft, end: FractionalOffset.bottomRight, colors: [boxColorBegin, boxColorEnd]),
            ),
            child: ClipRect(
              clipBehavior: Clip.hardEdge,
              child: Padding(
                padding: const EdgeInsets.only(right: 130, bottom: 150),
                child: OverflowBox(
                    maxHeight: screenHeight / 3.5 + 20,
                    maxWidth: screenWidth / 3.5 + 20,
                    child: Container(
                      decoration: BoxDecoration(
                        color: Colors.white.withAlpha(80),
                        shape: BoxShape.circle,
                      ),
                    )),
              ),
            ),
          ),
        );
alireza easazade
  • 3,324
  • 4
  • 27
  • 35