How can I add Shades to the edges of an Image in flutter, so that white overlayed text would be readable? I want it to look just like in the Contacts app: Shaded edges

I've already checked the Image class, but all I see there is color and colorBlendMode, which wouldn't be the easiest way of doing this, im sure.


Solution 1: Ian Rehwinkel

I solved my issue using following code. (When doing this, dont use box-shadow. It leads to everything being dark):

Stack(
  children: <Widget>[
    Image(
      fit: BoxFit.cover,
      image: AssetImage("assets/test.jpg"),
      height: MediaQuery.of(context).size.width * 0.8,
      width: MediaQuery.of(context).size.width,
    ),
    Container(
      height: MediaQuery.of(context).size.width * 0.8,
      width: MediaQuery.of(context).size.width,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          colors: [
            const Color(0xCC000000),
            const Color(0x00000000),
            const Color(0x00000000),
            const Color(0xCC000000),
          ],
        ),
      ),
    ),
    new Padding(
      padding: const EdgeInsets.all(16.0),
      child: Text("TXT", style: Theme.of(context).primaryTextTheme.title,),
    ),
  ],
),


Solution 2: The Vinh Luong

The accepted answer is working fine for me. But in my case the image is loaded via network so the dark edge is visible even when image is not shown yet, which is wrong to me. So I have another approach by using frameBuilder - which is one of Image's property itself. Another plus for this method is we don't need to use Stack:

Image.network(
        "https://foo.com/bar.jpg",
        width: double.infinity,
        height: expandedHeight,
        fit: BoxFit.fitWidth,
        frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
          if (wasSynchronouslyLoaded || frame != null) {
            return Container(
              child:child,
              foregroundDecoration: BoxDecoration(
                  gradient: LinearGradient(
                      begin: Alignment.topCenter,
                      end: Alignment.bottomCenter,
                      colors: [
                        const Color(0xCC000000),
                        const Color(0x00000000),
                        const Color(0x00000000),
                        const Color(0xCC000000),                ]
                  )
              ),
              height: expandedHeight,
              width: double.infinity,
            );
          } else {
            return Container(
              child: CircularProgressIndicator(
                  value: null,
                  backgroundColor: Colors.white),
              alignment: Alignment(0, 0),
              constraints: BoxConstraints.expand(),
            );
          }
        },
      ),

By using this snippet of code I was able to delay the displaying of the dark edge until image is shown. If wasSynchronouslyLoaded is true then that mean the image can be loaded instantly, if it is false then we have to rely on frame to tell if image is available for display or not. If image is not available yet then it will display a CircularProgressIndicator as a place holder for image.