Does anyone know how to add a gradient background to CupertinoSliverAppBar?

1,943

This is actually a bit difficult - as you mentioned the CupertinoSliverAppBar doesn't support 'flexibleSpace' or anything like it, so you're stuck with trying to use the backgroundColor which doesn't do what you need either.

I'd recommend opening an issue on the Flutter repo stating that it isn't possible and why you'd like to do it. They probably won't take action on it right away but if they're aware that people would like to do it it, it might happen.

Not all hope is lost for an immediate fix though, we can cheat! (although I'm hoping you'll use a less terifyingly ugly gradient when you write your version)

screenshot showing cupertinoappbar with gradientscreenshot showing cupertionoappbar collapsed with gradient

What I've done is subclassed Border, and then overridden what it draws so that it draws a gradient you pass in before drawing the actual border. This works because it's given a paint context that covers the entire app bar, and draws over the background of the appbar but below its content (hopefully - it seems to be below the title at least so I assume it's below everything else too). The background color is still drawn under the appbar so if your gradient is somewhat transparent you'll probably want to set the backgroundColor to Colors.transparent.

Here's the code:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(GradientAppBar());

class GradientCheatingBorder extends Border {
  const GradientCheatingBorder({
    this.gradient,
    BorderSide top = BorderSide.none,
    BorderSide right = BorderSide.none,
    BorderSide bottom = BorderSide.none,
    BorderSide left = BorderSide.none,
  }) : super(top: top, right: right, bottom: bottom, left: left);

  const GradientCheatingBorder.fromBorderSide(BorderSide side, {this.gradient})
      : super.fromBorderSide(side);

  factory GradientCheatingBorder.all({
    Color color = const Color(0xFF000000),
    double width = 1.0,
    BorderStyle style = BorderStyle.solid,
    Gradient gradient,
  }) {
    final BorderSide side =
        BorderSide(color: color, width: width, style: style);
    return GradientCheatingBorder.fromBorderSide(side, gradient: gradient);
  }

  final Gradient gradient;

  @override
  void paint(
    Canvas canvas,
    Rect rect, {
    TextDirection textDirection,
    BoxShape shape = BoxShape.rectangle,
    BorderRadius borderRadius,
  }) {
    if (gradient != null) {
      canvas.drawRect(
        rect,
        Paint()
          ..shader = gradient.createShader(rect)
          ..style = PaintingStyle.fill,
      );
    }

    super.paint(
      canvas,
      rect,
      textDirection: textDirection,
      shape: shape,
      borderRadius: borderRadius,
    );
  }
}

class GradientAppBar extends StatefulWidget {
  @override
  _GradientAppBarState createState() => _GradientAppBarState();
}

class _GradientAppBarState extends State<GradientAppBar> {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CustomScrollView(
        slivers: <Widget>[
          CupertinoSliverNavigationBar(
            largeTitle: Text("Title"),
            border: GradientCheatingBorder.fromBorderSide(
              BorderSide.none,
              gradient: LinearGradient(colors: [Colors.black, Colors.white]),
            ),
          ),
          SliverList(
            delegate: SliverChildListDelegate(
              [
                Container(
                  color: Colors.blue,
                  height: 500,
                ),
                Divider(),
                Container(
                  color: Colors.black12,
                  height: 500,
                ),
                Divider(),
                Container(
                  color: Colors.lightBlue,
                  height: 500,
                ),
                Divider(),
                Container(
                  color: Colors.lightGreen,
                  height: 500,
                ),
                Divider(),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
Share:
1,943
Benjamin
Author by

Benjamin

Currently a freelance mobile &amp; frontend developer, I have worked on a great variety of projects over the past decade. Always curious about the latest technological trends, I follow the cutting edge innovations and strive to stay up to date. I love a challenge and live by the motto difficult takes a day. Impossible takes a week.

Updated on December 11, 2022

Comments

  • Benjamin
    Benjamin over 1 year

    I am trying to add a gradient background to a CupertinoSliverAppBar in a Flutter app but I cannot seem to figure out how to do it. The SliverAppBar has a flexibleSpace property that would accept a gradient but the CupertinoSliverAppBar only has a backgroundColor property.

    Alternatively, if it were possible to move the title in the flexibleSpace more to the left, I could go with that. But I cannot figure that out either.

    I read these:

    And this issue opened on the Flutter repository: https://github.com/flutter/flutter/issues/25144

    @rmtmckenzie does the trick! It is worth noting this also works with CupertinoSliverNavigationBar. Also, all transition animations are preserved except for that of the background for which you will bee seeing the backgroundColor property being animated. You can cheat by using one of the gradient's colors as the backgroundColor but it is not perfect. The gradient is indeed rendered below the content. See below:

    enter image description here

    • Benjamin
      Benjamin about 5 years
      @rmtmckenzie any ideas ?
    • Hussnain Haidar
      Hussnain Haidar about 4 years
      pub.dev/packages/gradientscaffoldwidget CupertinoPageGradientScaffold method.
    • Nithin Sai
      Nithin Sai about 4 years
      Also, I wanted to know if we can add an image background to Cupertino sliver nav bar?? Anyone?
    • Benjamin
      Benjamin about 4 years
      @NithinSai I have created a PR for that (and gradient): github.com/flutter/flutter/pull/33177. It still needs a little cleanup to pass the tests
    • Nithin Sai
      Nithin Sai about 4 years
      @Benjamin that's a great idea! Thanks
  • Benjamin
    Benjamin about 5 years
    It may be ugly, but it is damn clever! Thank you!
  • Benjamin
    Benjamin about 5 years
    there is no flexibleSpace in the CupertinoSliverNavigationBar.