mideveloper
mideveloper

Reputation: 417

Flutter how to create circular border around icon and align an image top of the circular border

I am trying to use the below code to create a circular border around an image and align an icon on top of the circular border. What I am looking at is as the image below:

enter image description here

And my code is as below but it didn't work out perfectly:

Stack(
  children: [
    CircleAvatar(
      radius: 60,
      backgroundColor: Colors.white,
      child: Container(
          padding: EdgeInsets.all(2),
          child: CircleAvatar(
            radius: 70,
            backgroundImage: AssetImage('assets/person_icon.png'),
            backgroundColor: Colors.white,
            //
          )),
    ),
    Positioned(
        bottom: 100,
        right: 50,
        child: InkWell(
          onTap: () {},
          child: Container(
            child: Padding(
              padding: const EdgeInsets.all(2.0),
              child: Icon(Icons.add_a_photo, color: colorBlue),
            ),
            decoration: BoxDecoration(
                border: Border.all(
                  width: 3,
                  color: Colors.white,
                ),
                borderRadius: BorderRadius.all(
                  Radius.circular(
                    50,
                  ),
                ),
                color: Colors.white,
                boxShadow: [
                  BoxShadow(
                    offset: Offset(2, 4),
                    color: Colors.black.withOpacity(
                      0.3,
                    ),
                    blurRadius: 3,
                  ),
                ]),
          ),
        )),
  ],
),

As you can above I am trying to use stack to lay each widget on top of each other but couldn't achieve that. I don't if anyone can help out where I missed it or give me a good idea of how to come about this.

Thanks in advance.

Upvotes: 0

Views: 4180

Answers (5)

mideveloper
mideveloper

Reputation: 417

Thanks all for the contribution but here is what works perfectly for what I'm looking at. I added clipBehavior and set Clip to noneclipBehavior: Clip.none, added ClipOval in a Container and set it margin and padding respectively to give the space between the green circular border and the profile image. I also, added another Container inside my ClipOval so as to add my image as a child to it. Find below my final code:


  Center(
                    child: Stack(
                      clipBehavior: Clip.none,
                      children: [
                        CircleAvatar(
                          radius: 60,
                          backgroundColor: colorGreen,

                          child:Container(
                              padding: EdgeInsets.all(4),
                              margin: EdgeInsets.all(3),
                              decoration: BoxDecoration(
                                color: Colors.white,
                                shape: BoxShape.circle,
                              ),
                              child: ClipOval(
                                child: Container(
                                  height: 250,
                                  width: 250,
                                  child: Image.network(
                                    'my image link',
                                    fit: BoxFit.cover,
                                  ),
                                ),
                              )
                        )),
                        Positioned(
                          bottom: 100,
                          right: 45,
                          child: InkWell(
                            onTap: () {},
                            child:  Center(
                              child: CircleAvatar(
                                backgroundColor: colorGreen,
                                radius: 15.0,
                                child: Icon(
                                  Icons.check,
                                  color: Colors.white,
                                  size: 25,
                                ),
                              ),
                            ),
                          ),
                        ),

                      ],
                    ),
                  ),


Upvotes: 0

ajees
ajees

Reputation: 11

user this below code to achieve

Center(
    child: Stack(
      children: [
        Container(
          height: 200,
          child: CircleAvatar(
            radius: 75,
            backgroundColor: Colors.green,
            child: CircleAvatar(
              radius: 70,
              backgroundColor: Colors.white,
              child: Container(
                  padding: EdgeInsets.all(2),
                  child: const CircleAvatar(
                    radius: 60,
                    backgroundImage: NetworkImage("https://helostatus.com/wp-content/uploads/2021/09/pic-for-WhatsApp-HD.jpg"),
                    backgroundColor: Colors.white,
                    //
                  )),
            ),
          ),
        ),
        Positioned(
          left: 16,
          right: 16,
          top: 8,
          child: InkWell(
              onTap: () {},
              child: const CircleAvatar(
                backgroundColor: Colors.green,
                radius: 16,
                child: Icon(
                  Icons.check,
                  color: Colors.white,
                ),
              )),
        ),
      ],
    ),
  )[enter image description here][1]

Upvotes: 0

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63829

Default clipBehavior on Stack is hardEdge.

  • Use clipBehavior: Clip.none on Stack.

And to have circle shape

  • use customBorder: CircleBorder(), on InkWell.

  • use shape: BoxShape.circle instead of circular radius on container.

For better alignment use

Positioned(
    top: -12,//half of icon size
    left: 0,
    right: 0,

Also better providing size on Stack like here.

/// fixing top widget size
SizedBox.square(
  dimension: squareSize,
  child: Stack(
    clipBehavior: Clip.none,
    children: [
      Positioned.fill(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Container(
            clipBehavior: Clip.hardEdge,
            decoration: const ShapeDecoration(
              shape: CircleBorder(),
            ),
            child: Image.asset(
              'assets/images/image01.png',
              fit: BoxFit.cover,
            ),
          ),
        ),
      ),

      ///background circle, you also do it on image widget
      Container(
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          border: Border.all(width: 5, color: Colors.green),
        ),
      ),

      Positioned(
        top: -12, // half of icon size
        left: 0,
        right: 0,
        child: InkWell(
          onTap: () {},
          customBorder: const CircleBorder(),
          child: Container(
            width: 24 + 12, //icon size+padding
            height: 24 + 12,
            alignment: Alignment.center,

            decoration: const ShapeDecoration(
              shape: CircleBorder(),
              color: Colors.green,
            ),
            child: Icon(
              Icons.add_a_photo,
              color: Colors.white,
            ),
          ),
        ),
      ),
    ],
  ),
)

Play with sizes and decoration

enter image description here

Upvotes: 2

Ravindra S. Patil
Ravindra S. Patil

Reputation: 14885

Try below code

Stack(
        children: <Widget>[
          Padding(
            padding: EdgeInsets.only(top: 25),
            child: Container(
              padding: EdgeInsets.all(8),
              height: 270,
              width: 270,
              decoration: BoxDecoration(
                color: Colors.green,
                shape: BoxShape.circle,
              ),
              child: Container(
                padding: EdgeInsets.all(8),
                decoration: BoxDecoration(
                  color: Colors.white,
                  shape: BoxShape.circle,
                ),
                child: ClipOval(
                  child: Container(
                    height: 250,
                    width: 250,
                    child: Image.network(
                      'https://miro.medium.com/max/1400/1*-6WdIcd88w3pfphHOYln3Q.png',
                      fit: BoxFit.cover,
                    ),
                  ),
                ),
              ),
            ),
          ),
          Positioned(
            top: 0,
            left: .0,
            right: .0,
            child: Center(
              child: CircleAvatar(
                backgroundColor: Colors.green,
                radius: 30.0,
                child: Icon(
                  Icons.check,
                  color: Colors.white,
                  size: 40,
                ),
              ),
            ),
          )
        ],
      ),

Result Screen-> image

Upvotes: 0

Tempelritter
Tempelritter

Reputation: 543

Just add to the Stack Widget the Property clipBehavior: Clip.none,.

The clipBehavior will befine how to handle the Clip of the Stack Widget. Standard is hardEdge and cuts your icon off.

So your finished working Code is import 'package:flutter/material.dart';

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Stack(
          clipBehavior: Clip.none,
          children: [
            CircleAvatar(
              radius: 60,
              backgroundColor: Colors.white,
              child: Container(
                padding: EdgeInsets.all(2),
                child: CircleAvatar(
                  radius: 70,
                  backgroundImage: AssetImage('assets/person_icon.png'),
                  backgroundColor: Colors.white,
                  //
                ),
              ),
            ),
            Positioned(
              bottom: 100,
              right: 50,
              child: InkWell(
                onTap: () {},
                child: Container(
                  child: Padding(
                    padding: const EdgeInsets.all(2.0),
                    child: Icon(Icons.add_a_photo, color: Colors.blue),
                  ),
                  decoration: BoxDecoration(
                    border: Border.all(
                      width: 3,
                      color: Colors.white,
                    ),
                    borderRadius: BorderRadius.all(
                      Radius.circular(
                        50,
                      ),
                    ),
                    color: Colors.white,
                    boxShadow: [
                      BoxShadow(
                        offset: Offset(2, 4),
                        color: Colors.black.withOpacity(
                          0.3,
                        ),
                        blurRadius: 3,
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(
    const MaterialApp(
      home: MyApp(),
    ),
  );
}

Upvotes: 0

Related Questions