31

I am trying to add a shadow to only the right side of of my container widget using the boxShadow parameter in the BoxDecoration widget.

new Container(
  decoration: BoxDecoration(
    color: Colors.grey.withOpacity(0.5),
    boxShadow: [
      BoxShadow(
        blurRadius: 5.0
      ),
    ],
  ),
),

This code works but adds a shadow to every possible side of the container. I would like to have it only be on the right side.

countpablo
  • 501
  • 1
  • 5
  • 15

7 Answers7

17

You can set the offset property of BoxShadow. It is defined as Offset(double dx, double dy). So, for example:

boxShadow: [
  BoxShadow(
    blurRadius: 5.0,
    offset: Offset(3.0, 0),
  ),
],

This will cast a shadow only at 3 units to the right (dx).

Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76
James Casia
  • 1,457
  • 9
  • 15
  • 9
    Thanks for your response, this seems to make the shadow "bigger" on the right than on the other sides but still doesn't seem to get rid of the shadow on the other sides :/ – countpablo Jul 08 '19 at 16:45
  • I'm not on my machine right now but could you try to tweak the blurRadius, I'm suspecting that since the blurRadius is greater than the x-offset, still a shadow of about 2 units can be seen on the left side of the Container . – James Casia Jul 08 '19 at 16:49
  • 1
    That was my first thought and so I tried setting the blurRadius to be as low as even 0.5 but the container still seems elevated somewhat (due to the remaining shadows on the other sides) from its parent widget. – countpablo Jul 08 '19 at 16:52
  • 3
    ^This will *move* the whole shadow to 3 pixels on the right rather than drawing only on the right. – RoyalGriffin Apr 28 '20 at 10:29
13

boxShadow property of BoxDecoration takes a list of BoxShadow, so you can pass solid BoxShadow to the rest of the sides and corners with background color. Note that a small shadow remains at the corners, but hey!... Life is not perfect ;)

return Scaffold(
  backgroundColor: Colors.white,
  appBar: AppBar(title: Text('Shadow Test')),
  body: Center(
    child: Container(
      width: 200,
      height: 200,
      decoration: BoxDecoration(
        color: Colors.blueAccent,
        boxShadow: [
          BoxShadow(blurRadius: 8.0),
          BoxShadow(color: Colors.white, offset: Offset(0, -16)),
          BoxShadow(color: Colors.white, offset: Offset(0, 16)),
          BoxShadow(color: Colors.white, offset: Offset(-16, -16)),
          BoxShadow(color: Colors.white, offset: Offset(-16, 16)),
        ],
      ),
    ),
  ),
);

Screenshot

enter image description here

georkings
  • 616
  • 8
  • 8
13

This is one way:

Container(
  width: 230,
  height: 200,
  clipBehavior: Clip.antiAlias,
  decoration: BoxDecoration(),
  child: Container(
    margin: EdgeInsets.only(right: 30), // ***
    decoration: BoxDecoration(
      color: Colors.blue,
      boxShadow: [
        BoxShadow(
          color: Colors.red,
          blurRadius: 20,
          spreadRadius: 8,
        )
      ],
    ),
  ),
)

*** : whichever side you give margin to, that side will show the shadow. Giving margin to multiple sides also works.

Demo

SIMMORSAL
  • 1,402
  • 1
  • 16
  • 32
3

A box shadow is actually just a tinted, blurred and shifted version of the parent object which is then rendered underneath it. That's why having a box shadow just on one side isn't trivial.

The most straight forward solution is to cut off the shadow on the sides where you do not need it. In Flutter this can be nicely achieved via the CustomClipper class. The example below clips the entire shadow of the object except on the sides where we define a padding (which should be at least as large as the overlapping shadow).

/// Clips the given object by its size.
/// The clip area can optionally be enlarged by a given padding.
class ClipPad extends CustomClipper<Rect> {
  final EdgeInsets padding;
    
  const ClipPad({
    this.padding = EdgeInsets.zero
  });
  
  @override
  Rect getClip(Size size) => padding.inflateRect(Offset.zero & size);

  @override
  bool shouldReclip(ClipPad oldClipper) => oldClipper.padding != padding;
}


ClipRect(
  clipper: const ClipPad(
    padding: EdgeInsets.only(left: 30, top:30)
  ),
  child: Container(
    width: 200,
    height: 200,
    decoration: const BoxDecoration(
      color: Colors.black,
      boxShadow: [
        BoxShadow(
          color: Colors.red,
          blurRadius: 20,
        )
      ]
    )
  )
);

Note: You might want to use a different Clipper-Widget and CustomClipper for shapes other than rectangles like for example ClipRRect or ClipPath.

enter image description here

Robbendebiene
  • 4,215
  • 3
  • 28
  • 35
1

Note that MyShadowSize = spreadRadius + x/y Offset. Example:

  • If spreadRadius: 1, offset: Offset(0, 0) => 4 sides is MyShadowSize has 1 + 0 = 1.
  • If you want only bottom shadow = 1, you can add: spreadRadius: 0, offset: Offset(0, 1), Explain: Current y offset = 1, => MyShadowSize bottom = 1, MyShadowSize top = -1 (because y move down) => MyShadowSize top not show.
O Thạnh Ldt
  • 1,103
  • 10
  • 11
  • 2
    I'm sorry, but I'm going to down vote this because it's difficult to read, and I'm not sure it makes sense. Can you explain further? – BananaNeil Nov 24 '20 at 12:08
1

To avoid those ugly edges from the other answers here, you can do it this.

enter image description here

 final oneSideShadow = Padding(
  padding: const EdgeInsets.only(left: 30, right: 30, top: 30),
  child: Container(
    decoration: BoxDecoration(
      color: Colors.green,
      borderRadius: borderRadius,
      boxShadow: [
        BoxShadow(
          color: Colors.red.withOpacity(0.95),
          blurRadius: 26,
          offset: const Offset(0, 2), // changes position of shadow
        ),
      ],
    ),
  ),
);

return Container(
  width: 200,
  height: 200,
  child: Stack(
    children: [
      oneSideShadow,
      Container(
        decoration: const BoxDecoration(
          color: Colors.yellow,
        ),
      ),
    ],
  ),
);

You can get pretty wild results with this, e.g. if you modify the code above, and put row+expanded childs with different shadows there.

enter image description here

Bonco
  • 122
  • 2
  • 5
1

Adding shadow to a single side is very hard since it's a shifted and blurred version of the parent widget. I tried all the other ways but didn't work really well.

for longer shadow.

I also found one other way is by use Stack Widget to cover the other sides. If you don't have anything near that widget. if you have a widget near it, you can use that widget to cover the shadow.

Please refer to the code below.

Stack(alignment: Alignment.topCenter, children: [
                Padding(
                  padding: EdgeInsets.only(top: 14),
                  child: Container(
                    decoration: BoxDecoration(
                      color: Colors.white,
                      boxShadow: [
                        BoxShadow(
                          color: Color(0xff000000).withOpacity(0.1),
                          spreadRadius: 0,
                          blurRadius: 10,
                          offset: Offset(0.0, 4),
                          // // changes position of shadow
                        ),
                      ],
                    ),
                    child: TabBar(
                      indicatorColor: Color(0xffFF7000),
                      unselectedLabelColor: Color(0xff818898),
                      labelColor: Color(0xffFF7000),
                      tabs: [
                        Tab(
                          child: Text(
                            'Tab 0'
                            style: TextStyle(
                                fontSize: UiSizeUtils.getFontSize(14),
                                fontWeight: FontWeight.w600),
                          ),
                        ),
                        Tab(
                          child: Text(
                            'Tab 1'
                            style: TextStyle(
                                color: Color(0xff8D99BB),
                                fontSize: UiSizeUtils.getFontSize(14),
                                fontWeight: FontWeight.w600),
                          ),
                        ),
                      ],
                      controller: _tabController,
                      indicatorSize: TabBarIndicatorSize.tab,
                    ),
                  ),
                ),
                Container(
                  width: double.infinity,
                  height: UiSizeUtils.getHeightSize(16),
                  color: Colors.white,
                )
              ]),

This is how I added the shadow for the bottom only for the tab view and this works best for my use case when compared with the other method mentioned above.

Alan Bosco
  • 737
  • 5
  • 20