0

I cannot shape my TabBar Indicator with BorderRadius and BorderSide at the same time.

I get the error "A borderRadius can only be given for uniform borders" similarly to the question raised here but I still cannot find a solution to it. Having different color without a radius or using the same color with a different radius does not fix the issue.

This is how my indicator looks like when I add a borderSide:

enter image description here

And this is how my indicator looks like when I add a borderRadius

enter image description here

I want a solution where I can combine both of them. Apparently a Container Widget cannot be added. The indicator is only accepting BoxDecoration.

TabBar(
        indicator: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Theme.of(context).primaryColorLight.withOpacity(0.8),
              Theme.of(context).primaryColorLight.withOpacity(0.8),
              Theme.of(context).canvasColor.withOpacity(0.8),
            ],
          ),
          
           borderRadius: 
           const BorderRadius.only(
             topRight: Radius.circular(100.0),
             topLeft: Radius.circular(100.0),
             bottomLeft: Radius.zero,
             bottomRight: Radius.circular(-100),
           ),
          
          border: const Border(
            top: BorderSide(
                color: Color(0xFF2695F8),
                width: 4,
                style: BorderStyle.solid,
            ),
            left: BorderSide(
                color: Color(0xFF2695F8),
                width: 4,
                style: BorderStyle.solid,
            ),
            right: BorderSide(
                color: Color(0xFF2695F8),
                width: 4,
                style: BorderStyle.solid,
            ),
            bottom: BorderSide(
                color: Colors.transparent,
                width: 4,
            ),
          ),
        ),
        tabs: [
          for (int i = 0; i < widget.tabTitles.length; i++)
               Tab(
                child: Text(
                        widget.tabTitles[i],
                        maxLines: null,
                        overflow: TextOverflow.ellipsis,
                        textAlign: TextAlign.center,
                        //style: kTSMainBody(context),
                      ))]),

You can find the full code snippet here: https://dartpad.dartlang.org/?id=6a7ffa5b89475e984a5dd9ed31ea31aa

What I also tried:

class CustomTabIndicator extends Decoration {
  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) {
    return _CustomPainter(this);}}

class _CustomPainter extends BoxPainter {
  final CustomTabIndicator decoration;

  _CustomPainter(this.decoration);

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final Rect rect = offset & configuration.size!;
    final Paint paint = Paint()
      ..color = const Color(0xFF2695F8) 
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.0; 

    // final RRect rrect = RRect.fromRectAndCorners(
    //   rect,
    //   topRight: const Radius.circular(100.0),
    //   topLeft: const Radius.circular(40),
    //   bottomLeft: Radius.zero,
    //   bottomRight: const Radius.circular(100),
    // );

    // Draw the custom border using the paint and rrect
    // canvas.drawRRect(rrect, paint);

    // final Path path = Path()
    //   ..moveTo(rect.left, rect.bottom)
    //   ..lineTo(rect.left, rect.top + 40.0) 
    //   ..arcTo(
    //       Rect.fromLTWH(rect.left, rect.top, 80.0, 80.0), -pi, -pi / 2, false)
    //   ..lineTo(rect.right - 100.0, rect.top) 
    //   ..arcTo(Rect.fromLTWH(rect.right - 200.0, rect.top, 200.0, 200.0),
    //       -pi / 2, pi / 2, false)
    //   ..lineTo(rect.right, rect.bottom); 
    // canvas.drawPath(path, paint);
  }
}

See full error message:

     ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY
     ╞═════════════════════════════════════════════════════════
     The following assertion was thrown during paint():
     A borderRadius can only be given for a uniform Border.
     The following is not uniform:
     BorderSide.color
     BorderSide.width
     
     The relevant error-causing widget was:
       TabBar      TabBar:file:///Users...etc.
       0:14
    
     When the exception was thrown, this was the stack:
     #0      Border.paint.<anonymous closure> (package:flutter/src/painting/box_border.dart:550:9)
     #1      Border.paint (package:flutter/src/painting/box_border.dart:560:6)
     #2      _BoxDecorationPainter.paint (package:flutter/src/painting/box_decoration.dart:499:25)
     #3      _IndicatorPainter.paint (package:flutter/src/material/tabs.dart:445:15)
     #4      RenderCustomPaint._paintWithPainter
     (package:flutter/src/rendering/custom_paint.dart:571:13)
     #5      RenderCustomPaint.paint (package:flutter/src/rendering/custom_paint.dart:613:7)
     #6      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #7      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #8      RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #9      RenderDecoratedBox.paint (package:flutter/src/rendering/proxy_box.dart:2383:11)
     #10     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #11     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #12     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #13     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #14     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #15     RenderBoxContainerDefaultsMixin.defaultPaint
     (package:flutter/src/rendering/box.dart:2924:15)
     #16     RenderFlex.paint (package:flutter/src/rendering/flex.dart:1089:7)
     #17     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #18     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #19     RenderShiftedBox.paint (package:flutter/src/rendering/shifted_box.dart:74:15)
     #20     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #21     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #22     RenderShiftedBox.paint (package:flutter/src/rendering/shifted_box.dart:74:15)
     #23     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #24     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #25     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #26     _RenderInkFeatures.paint (package:flutter/src/material/material.dart:653:11)
     #27     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #28     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #29     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #30     RenderCustomPaint.paint (package:flutter/src/rendering/custom_paint.dart:616:11)
     #31     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #32     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #33     RenderClipPath.paint (package:flutter/src/rendering/proxy_box.dart:1852:17)
     #34     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #35     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #36     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #37     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #38     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #39     RenderBoxContainerDefaultsMixin.defaultPaint
     (package:flutter/src/rendering/box.dart:2924:15)
     #40     RenderStack.paintStack (package:flutter/src/rendering/stack.dart:654:5)
     #41     RenderStack.paint (package:flutter/src/rendering/stack.dart:670:7)
     #42     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #43     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #44     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #45     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #46     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #47     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #48     _RenderInkFeatures.paint (package:flutter/src/material/material.dart:653:11)
     #49     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #50     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #51     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #52     RenderPhysicalModel.paint.<anonymous closure>
     (package:flutter/src/rendering/proxy_box.dart:2110:15)
     #53     PaintingContext.pushClipRRect (package:flutter/src/rendering/object.dart:564:14)
     #54     RenderPhysicalModel.paint (package:flutter/src/rendering/proxy_box.dart:2097:21)
     #55     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #56     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #57     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #58     PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:474:12)
     #59     RenderAnnotatedRegion.paint (package:flutter/src/rendering/proxy_box.dart:5118:13)
     #60     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #61     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #62     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #63     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #64     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #65     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #66     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #67     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #68     RenderBoxContainerDefaultsMixin.defaultPaint
     (package:flutter/src/rendering/box.dart:2924:15)
     #69     RenderCustomMultiChildLayoutBox.paint
     (package:flutter/src/rendering/custom_layout.dart:415:5)
     #70     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #71     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #72     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #73     _RenderInkFeatures.paint (package:flutter/src/material/material.dart:653:11)
     #74     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #75     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #76     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #77     RenderPhysicalModel.paint.<anonymous closure>
     (package:flutter/src/rendering/proxy_box.dart:2110:15)
     #78     PaintingContext.pushClipRRect (package:flutter/src/rendering/object.dart:564:14)
     #79     RenderPhysicalModel.paint (package:flutter/src/rendering/proxy_box.dart:2097:21)
     #80     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #81     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #82     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #83     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #84     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #85     RenderBoxContainerDefaultsMixin.defaultPaint
     (package:flutter/src/rendering/box.dart:2924:15)
     #86     RenderStack.paintStack (package:flutter/src/rendering/stack.dart:654:5)
     #87     RenderStack.paint (package:flutter/src/rendering/stack.dart:670:7)
     #88     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #89     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #90     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #91     RenderDecoratedBox.paint (package:flutter/src/rendering/proxy_box.dart:2383:11)
     #92     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #93     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #94     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #95     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #96     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #97     RenderBoxContainerDefaultsMixin.defaultPaint
     (package:flutter/src/rendering/box.dart:2924:15)
     #98     RenderFlex.paint (package:flutter/src/rendering/flex.dart:1089:7)
     #99     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #100    PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #101    RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #102    RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #103    PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #104    RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
     #105    PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:474:12)
     #106    PaintingContext.pushOpacity (package:flutter/src/rendering/object.dart:707:5)
     #107    RenderOpacity.paint (package:flutter/src/rendering/proxy_box.dart:959:21)
     #108    RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #109    PaintingContext.paintChild (package:flutter/src/rendering/object.dart:253:13)
     #110    _RenderSingleChildViewport.paint.paintContents
     (package:flutter/src/widgets/single_child_scroll_view.dart:547:17)
     #111    PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:474:12)
     #112    PaintingContext.pushClipRect (package:flutter/src/rendering/object.dart:534:7)
     #113    _RenderSingleChildViewport.paint
     (package:flutter/src/widgets/single_child_scroll_view.dart:551:40)
     #114    RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2853:7)
     #115    PaintingContext._repaintCompositedChild
     (package:flutter/src/rendering/object.dart:169:11)
     #116    PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:112:5)
     #117    PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:1137:31)
     #118    RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:518:19)
     #119    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:865:13)
     #120    RendererBinding._handlePersistentFrameCallback
     (package:flutter/src/rendering/binding.dart:381:5)
     #121    SchedulerBinding._invokeFrameCallback
     (package:flutter/src/scheduler/binding.dart:1289:15)
     #122    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1218:9)
     #123    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1076:5)
     #124    _invoke (dart:ui/hooks.dart:145:13)
     #125    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:338:5)
     #126    _drawFrame (dart:ui/hooks.dart:112:31)
     
     The following RenderObject was being processed when the exception was fired:
     RenderCustomPaint#3fbf2 relayoutBoundary=up21:
       creator: CustomPaint ← TabBar ← DecoratedBox ← ConstrainedBox ← Container ← CustomTabBar ←
         PreferredSize ← Column ← MediaQuery ← Padding ← SafeArea ← Align ← ⋯
       parentData: <none> (can use size)
       constraints: BoxConstraints(0.0<=w<=375.0, h=52.0)
       size: Size(375.0, 52.0)
       painter: _IndicatorPainter#720cb(AnimationController#93cec(▶ 0.000; paused))
     This RenderObject had the following descendants (showing up to depth 5):
         child: _TabLabelBarRenderer#bc4e8 relayoutBoundary=up22 NEEDS-PAINT
           child 1: RenderSemanticsAnnotations#1b1e2 relayoutBoundary=up23 NEEDS-PAINT
             child: RenderMouseRegion#20cac relayoutBoundary=up24 NEEDS-PAINT
               child: RenderSemanticsAnnotations#6d346 relayoutBoundary=up25 NEEDS-PAINT
                 child: RenderPointerListener#cec33 relayoutBoundary=up26 NEEDS-PAINT
           child 2: RenderSemanticsAnnotations#9dba8 relayoutBoundary=up23 NEEDS-PAINT
             child: RenderMouseRegion#70120 relayoutBoundary=up24 NEEDS-PAINT
               child: RenderSemanticsAnnotations#634bd relayoutBoundary=up25 NEEDS-PAINT
                 child: RenderPointerListener#4b615 relayoutBoundary=up26 NEEDS-PAINT
           child 3: RenderSemanticsAnnotations#8fe1b relayoutBoundary=up23 NEEDS-PAINT
             child: RenderMouseRegion#3b987 relayoutBoundary=up24 NEEDS-PAINT
               child: RenderSemanticsAnnotations#aff03 relayoutBoundary=up25 NEEDS-PAINT
                 child: RenderPointerListener#ea8a1 relayoutBoundary=up26 NEEDS-PAINT
     ════════════════════════════════════════════════════════════════════════════════════════════════
     ════
     
     Another exception was thrown: A borderRadius can only be given for a uniform Border.
     
     Another exception was thrown: A borderRadius can only be given for a uniform Border.
     
     Another exception was thrown: A borderRadius can only be given for a uniform Border.
     
     Another exception was thrown: A borderRadius can only be given for a uniform Border.
     
     Another exception was thrown: A borderRadius can only be given for a uniform Border.
Texv
  • 1,225
  • 10
  • 14

2 Answers2

0

You need to use the Border.all() to set a uniform border style. So do set the border like this:

border: Border.all(
    color: const Color(0xFF2695F8),
    width: 4,
    style: BorderStyle.solid,
),

Finally your TabBar code shold be:

TabBar(
            indicator: BoxDecoration(
              gradient: LinearGradient(
                begin: Alignment.topCenter,
                end: Alignment.bottomCenter,
                colors: [
                  Theme.of(context).primaryColorLight.withOpacity(0.8),
                  Theme.of(context).primaryColorLight.withOpacity(0.8),
                  Theme.of(context).canvasColor.withOpacity(0.8),
                ],
              ),
              borderRadius: const BorderRadius.only(
                topRight: Radius.circular(100.0),
                topLeft: Radius.circular(100.0),
                bottomLeft: Radius.zero,
                bottomRight: Radius.circular(-100),
              ),
              border: Border.all(
                color: const Color(0xFF2695F8),
                width: 4,
                style: BorderStyle.solid,
              ),
            ),
            tabs: [
              for (int i = 0; i < widget.tabTitles.length; i++)
                Tab(
                  child: Text(
                    widget.tabTitles[i],
                    maxLines: null,
                    overflow: TextOverflow.ellipsis,
                    textAlign: TextAlign.center,
                    //style: kTSMainBody(context),
                  ),
                ),
            ],
          )
Waseem Abbas
  • 341
  • 1
  • 6
0

It's a little bit challenging... By the way, try this solution. Update your CustomTabBar widget and customize the border as you want.

class CustomTabBar extends StatelessWidget implements PreferredSizeWidget {
  final List<String> tabTitles;
  final TabController controller;

  const CustomTabBar(
      {super.key, required this.tabTitles, required this.controller});

  @override
  Size get preferredSize => const Size.fromHeight(52);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: preferredSize.height,
      // decoration: BoxDecoration(
      //   color: Theme.of(context).primaryColor.withOpacity(0.2),
      //   border: Border.all(color: Colors.black),
      //   borderRadius: BorderRadius.circular(100),
      // ),
      child: Stack(
        children: [
          TabBar(
            // padding: EdgeInsets.symmetric(horizontal: 8),
            indicatorPadding: const EdgeInsets.only(right: -24, left: -24),
            indicator: const BoxDecoration(
              border: Border(
                top: BorderSide(color: Color(0xFFF8EA00), width: 4),
                right: BorderSide(color: Color(0xFFF8EA00), width: 4),
                left: BorderSide(color: Color(0xFFF8EA00), width: 4),
                bottom: BorderSide(color: Colors.white, width: 4),
              ),
            ),
            indicatorColor: const Color(0xFFF8EA00),
            padding: EdgeInsets.zero,
            controller: controller,
            tabs: [
              for (int i = 0; i < tabTitles.length; i++)
                Tab(
                  child: Text(
                    tabTitles[i],
                    maxLines: null,
                    overflow: TextOverflow.ellipsis,
                    textAlign: TextAlign.center,
                  ),
                ),
            ],
          ),
          Align(
            alignment: Alignment.bottomLeft,
            child: Container(
              height: 3,
              color: Colors.grey, // Change the color as needed
            ),
          ),
        ],
      ),
    );
  }
}

Final result

  • I can't curve the edges with borderRadius though so this is still the same issue as mine, just with a differently designed borderSide with no borderRadius – Texv Aug 17 '23 at 07:03
  • I want the indicator (dark blue lines) to curve all around except the bottom side – Texv Aug 17 '23 at 07:04
  • Please can you check it again? I've updated my code for curve – Ashikul Islam Sawan Aug 17 '23 at 07:12
  • Thank you for your time but there are no borderSides around the indicator (selected tab). The Stack widget is useless here because it stacks TabBar and any other widgets behind or above the whole TabBar, but I only want borders around the selected tab only, plus the curve. See my pictures that I attached in my question, I want to achieve exactly that – Texv Aug 17 '23 at 08:18
  • @Texv I've updated my code again. Can you try this one? I hope you'll get at least hint – Ashikul Islam Sawan Aug 27 '23 at 01:32
  • Where's the borderRadius? The yellow borderSide is rectangular, I want it curved – Texv Aug 27 '23 at 02:21