Kennith
Kennith

Reputation: 373

Can I overflow a widget in Container to make it like clipped?

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!

Upvotes: 5

Views: 6898

Answers (3)

Kennith
Kennith

Reputation: 373

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,
      ),
    )
  )
);

Upvotes: 5

Nemi Shah
Nemi Shah

Reputation: 876

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.

Upvotes: 1

alireza easazade
alireza easazade

Reputation: 3822

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,
                      ),
                    )),
              ),
            ),
          ),
        );

Upvotes: 0

Related Questions