2

If I just throw together an image and some text in a rounded-corner rectangle, the user will not know that they can "click here". But I don't have to bake my own solution. InkWell covers this scenario, complete with a nice shadow.

I am positioning a custom clickable icon using the InkWell class, itself requiring to be inside an Ink instance.

shadow in front

import 'package:flutter/material.dart';

const boat_url = ('https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/'
    'Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG/'
    '182px-Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG');

void main() {
  runApp(MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Image',
      home: Scaffold(
        backgroundColor: Colors.grey,
        body: MyImage(),
      )));
}

class MyImage extends StatelessWidget {
  MyImage({Key key,});

  @override
  Widget build(BuildContext context) {
    Size sz = MediaQuery.of(context).size * 0.4;
    double border = 4;

    return Stack(children: [
      Positioned(
          top: 100,
          left: 100,
          width: sz.width,
          height: sz.height,
          child: Material(
            child: Ink(
              decoration: BoxDecoration(
                boxShadow: <BoxShadow>[
                  new BoxShadow(
                    color: Colors.red,
                    blurRadius: 10.0,
                    offset: new Offset(30.0, 20.0),
                  ),
                ],
                border: Border.all(
                  color: Colors.blue,
                  width: border,
                ),
                borderRadius: BorderRadius.circular(40),
              ),
              child: InkWell(
                onTap: (){/*..*/},
                child: Column(
                    children: [
                      Container(
                        height: 4 * (sz.height - 2 * border) / 5,
                        alignment: Alignment.center,
                        child: Image.network(boat_url),
                      ),
                      Container(
                        height: (sz.height - 2 * border) / 5,
                        child: FittedBox(
                            clipBehavior: Clip.antiAlias,
                            alignment: Alignment.centerLeft,
                            fit: BoxFit.fitHeight,
                            child: Text('A long descriptive sentence')),
                      )
                    ],
                  )),
            ),
          )),
    ]);
  }
}

1- I'm not actually using Colors.white, and the Scaffold itself has backgroundColor: Colors.grey. Where is the white background coming from?

2- When we talk of a "shadow", I'm expecting the shadow to be behind the ink/inkwell object. Why does the shadow appear in front?

Related: 1

1
  • I updated the post to include both the elevation and the radius. Commented Mar 30, 2021 at 16:22

2 Answers 2

1

That white color is from the Material widget, to remove that you can use type param.

Material(
      type: MaterialType.transparency,
      child: Container(),
    );

Here is code to achieve the custom button

Video link

Scaffold(
          backgroundColor: Colors.blueGrey,
          body: SafeArea(
            child: Container(
              decoration: BoxDecoration(
                  color: Colors.green.shade200,
                  border: Border.all(color: Colors.green),
                  borderRadius: BorderRadius.circular(5),
                  boxShadow: [
                    BoxShadow(
                      blurRadius: 5,
                      spreadRadius: 2,
                      color: Colors.black26,
                    )
                  ]),
              margin: const EdgeInsets.all(20),
              child: Material(
                type: MaterialType.transparency,
                child: InkWell(
                  onTap: () {},
                  splashColor: Colors.black26,
                  child: IntrinsicHeight(
                    child: Padding(
                      padding: const EdgeInsets.all(12.0),
                      child: Column(mainAxisSize: MainAxisSize.min, children: [
                        Image.asset(
                          'assets/images/marked_tyre_base.png',
                          fit: BoxFit.cover,
                          width: 80,
                          height: 80,
                        ),
                        const SizedBox(
                          height: 10,
                        ),
                        Text(
                          'Tyre 1',
                          style: TextStyle(color: Colors.white),
                        )
                      ]),
                    ),
                  ),
                ),
              ),
            ),
          ),
        );

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

1

Screenshot:

enter image description here


Create a class, ImageTextButton:

class ImageTextButton extends StatelessWidget {
  final VoidCallback onPressed;
  final ImageProvider image;
  final double imageHeight;
  final double radius;
  final Widget text;

  ImageTextButton({
    @required this.onPressed,
    @required this.image,
    this.imageHeight = 200,
    this.radius = 28,
    @required this.text,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 8,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius)),
      clipBehavior: Clip.hardEdge,
      child: InkWell(
        onTap: onPressed,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Ink.image(
              image: image,
              height: imageHeight,
              fit: BoxFit.cover,
            ),
            SizedBox(height: 6),
            text,
            SizedBox(height: 6),
          ],
        ),
      ),
    );
  }
}

Usage:

ImageTextButton(
  onPressed: () {},
  image: AssetImage('chocolate_image'),
  text: Text('Chocolate'),
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.