skip to Main Content

I’m building an App I have to build UI like below but I don’t have any idea that how to create UI like this. Kindly guide me through this.

enter image description here

3

Answers


  1.  var listImages = [
      "https://source.unsplash.com/random/200x200?sig=1",
      "https://source.unsplash.com/random/200x200?sig=2",
      "https://source.unsplash.com/random/200x200?sig=3",
      "https://source.unsplash.com/random/200x200?sig=4",
      "https://source.unsplash.com/random/200x200?sig=5"
    ];
    
    
     Padding(
            padding: const EdgeInsets.all(8.0),
            child: Stack(
              children: [
                for (int i = 0; i < (listImages.length>=4?4:listImages.length); i++)
                  Transform.translate(
                    offset: Offset(i == 0 ? 0.0 : i * 44, 0),
                    child: Container(
                      height: 70,
                      width: 70,
                      alignment: Alignment.center,
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(25),
                        color: Colors.black87,
                      ),
                      clipBehavior: Clip.hardEdge,
                      child: (i+1)>=4?Text("+ ${listImages.length-3}",style:const TextStyle(color: Colors.green),):Image.network(listImages[i]),
                    ),
                  )
              ],
            ),
          )
    
    Login or Signup to reply.
  2. The point is using Stack and Positioned to positiond widgets.
    (index to padding, maxPerson to set maximum widget to show)

    https://dartpad.dev/ example

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      final colors = const [
        Colors.yellow,
        Colors.green,
        Colors.blue,
        Colors.orange,
        Colors.cyan,
        Colors.brown,
      ];
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: PersonStacker(colors: colors),
          ),
        );
      }
    }
    
    class PersonStacker extends StatelessWidget {
      final List<Color> colors;
      final int maxPerson;
    
      const PersonStacker({required this.colors, this.maxPerson = 3});
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: [
            ...colors
                .getRange(0, maxPerson)
                .toList()
                .asMap()
                .map((index, color) => MapEntry(index, Person(index, color: color)))
                .values
                .toList(),
            ...colors.length > maxPerson
                ? [Person(maxPerson, plus: colors.length - maxPerson)]
                : []
          ],
        );
      }
    }
    
    class Person extends StatelessWidget {
      final int index;
      final Color color;
      final Color colorBorder;
      final double size = 100;
      final double offset = 30;
      final int? plus;
    
      const Person(this.index,
          {this.plus, this.color = Colors.black, this.colorBorder = Colors.black});
    
      Widget renderChild() => plus != null
          ? Center(
              child: Text(
                "+$plus",
                style: const TextStyle(color: Colors.white, fontSize: 20),
              ),
            )
          : Container();
    
      @override
      Widget build(BuildContext context) {
        return Positioned(
          left: index * offset,
          child: Container(
            width: size,
            height: size,
            decoration: BoxDecoration(
              color: color,
              border: Border.all(width: 2, color: colorBorder),
              borderRadius: BorderRadius.circular(size),
            ),
            child: renderChild(),
          ),
        );
      }
    }
    

    Result

    enter image description here

    Login or Signup to reply.
  3. Below are the methods used to prepare the layout

    // this method return the layout as per your expectations, here images are the // list of items you want to use and max count are the list of max item you want // to show except the count tile.
    
     Widget getItems(List<String> images, int maxCount) =>
        Stack(
          children: List.generate(images.length <= maxCount ? images.length : maxCount+1, (index) {
            if(index == maxCount){
              return  Positioned(
                left: index * 60,
                child: Container(
                  padding: const EdgeInsets.all(2), // Border width
                  decoration: BoxDecoration(
                      border: Border.all(
                        color: Colors.grey,
                        width: 2,
                      ),
                      color: Colors.black,
                      borderRadius: BorderRadius.circular(40)),
                  child: SizedBox.fromSize(
                    size: const Size.fromRadius(48), // Image radius
                    child: Center(
                      child: Text(
                        style: const TextStyle(
                          color: Color(0xff58D56D),
                          fontSize: 30
                        ),
                        "+${images.length-maxCount}"
                      ),
                    ),
                  ),
                ),
              );
            }
            else {
              return Positioned(
                  left: index * 60, child: getItemWidget(images[index]));
            }
          }),
        );
      
    // pass the image url you want to show.
      Widget getItemWidget(String imageUrl) =>  Stack(
        children: [
          Container(
            padding: const EdgeInsets.all(2), // Border width
            decoration: BoxDecoration(
                color: Colors.black,
                borderRadius: BorderRadius.circular(40)),
            child: ClipRRect(
              borderRadius: BorderRadius.circular(40),
    
              child: SizedBox.fromSize(
                size: Size.fromRadius(48), // Image radius
                child: Image.network(
                  imageUrl,
                  fit: BoxFit.fill,
                ),
              ),
            ),
          ),
          Positioned(
            bottom: 0,
            left: 0,
            child: Container(
              padding: const EdgeInsets.all(2), // Border width
              decoration: const BoxDecoration(
                color: Colors.black,
                shape: BoxShape.circle,
              ),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(100),
                child: SizedBox.fromSize(
                  size: Size.fromRadius(20), // Image radius
                  child: Image.network(
                    "https://play-lh.googleusercontent.com/STIZ_iftiehDCSynHXQaLqiL-F4kbZwasXOB2nae5pXTOpNKz8XSd7_VCF1Zgc3Z8Q",
                    fit: BoxFit.contain,
                  ),
                ),
              ),
            ),
          )
        ],
      );
    

    Below code is used to show the items

    getItems(["https://cdn.pixabay.com/photo/2013/07/13/10/07/man-156584__340.png",
              "https://static.vecteezy.com/system/resources/thumbnails/001/993/889/small/beautiful-latin-woman-avatar-character-icon-free-vector.jpg",
              "https://static.toiimg.com/thumb/resizemode-4,msid-76729536,width-1200,height-900/76729536.jpg",
              "https://www.nj.com/resizer/zovGSasCaR41h_yUGYHXbVTQW2A=/1280x0/smart/cloudfront-us-east-1.images.arcpublishing.com/advancelocal/SJGKVE5UNVESVCW7BBOHKQCZVE.jpg",
              "https://i.kinja-img.com/gawker-media/image/upload/t_original/ijsi5fzb1nbkbhxa2gc1.png"], 3),
          )
    

    Output:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search