skip to Main Content

For example in the following code if I am resizing the window vertically my icons of button and containers holding the icon button scales properly and never having any pixel overflow but if i do it horizontally it overflows after a certain length. on my 1080p 27 inch monitor when window width less than 265 it overflows.
I was wondering what adaptive rescaling can I use so that when horizontally it cannot fit the icons it also rescales ensuring no pixel overflow?
for rectangular stuffs its easy because you can set both width and height but for circular or square shapes I am having a hard time.

import "dart:ffi" as ffi;
import "package:flutter/material.dart";

const Color appBarColor = Color(0xFF1B5E20);
const Color white = Color(0xFFFFFFFF);

void main() {
  runApp(const CalcWidget());
}

class CalcWidget extends StatelessWidget {
    const CalcWidget({super.key});
    @override
    Widget build(BuildContext context) {
        final Size scrnSize = MediaQuery.sizeOf(context);
        return getMaterialApp(scrnSize);
    }
}

MaterialApp getMaterialApp(Size scrnSize) {
    final Scaffold home = Scaffold (
        backgroundColor : Colors.white38,
        body: SafeArea(
            child: Column (
                children: <Widget>[
                getAppBar(scrnSize),
                ],
            ),
        )
    );
    return MaterialApp (home : home);
}

Container getAppBar(Size scrnSize) {
    final double h = scrnSize.height * 0.08;
    final double subContainerSz = h - (h * 0.08);
    return Container(
        width: scrnSize.width,
        height: h,
        decoration: const BoxDecoration (
            color: appBarColor,
            shape: BoxShape.rectangle
        ),
        child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
                Row (
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: <Widget> [
                        const SizedBox(width: 4),
                        createIconButtonContainer(Icons.menu, subContainerSz, (){})
                    ]
                ),
                const Text (
                    "Calculator",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                        color: white,
                        fontWeight: FontWeight.bold
                    )
                ),
                Row (
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                        createIconButtonContainer(Icons.arrow_upward, subContainerSz, (){}),
                        const SizedBox(width: 4),
                        createIconButtonContainer(Icons.arrow_downward, subContainerSz, (){}),
                        const SizedBox(width: 4)
                    ],
                )
            ],
        ),
    );
}

Container createIconButtonContainer(IconData icon, double containerSz, Function() onPress) {
    final Container ibc = Container(
        width: containerSz,
        height: containerSz,
        alignment: Alignment.center,
        decoration: BoxDecoration(
            color: appBarColor.withOpacity(0.5),
            shape: BoxShape.circle,
            border: Border.all(color: appBarColor, width: 2),
            boxShadow: <BoxShadow>[
                BoxShadow(
                    color: const Color(0xFF000000).withOpacity(0.35),
                    spreadRadius: 1,
                    blurRadius: 5,
                    offset: const Offset(0, 3),
                )
            ]
        ),
        child: Center(
            child : IconButton(
                padding: EdgeInsets.zero,
                icon: Icon (
                    icon,
                    color: white,
                    size: containerSz*0.6,
                ),
                onPressed: onPress,
            )
        )
    );
    return ibc;
}

3

Answers


  1. Chosen as BEST ANSWER

    I was kinda looking for something like this! Where the components changes dynamically without having to set layout. I dont know how practical it is to do this but I will see that in the future.

    import "dart:ffi" as ffi;
    import "package:flutter/material.dart";
    
    const Color appBarColor = Color(0xFF1B5E20);
    const Color white = Color(0xFFFFFFFF);
    
    void main() {
      runApp(const CalcWidget());
    }
    
    class CalcWidget extends StatelessWidget {
        const CalcWidget({super.key});
        @override
        Widget build(BuildContext context) {
            final Size scrnSize = MediaQuery.sizeOf(context);
            return getMaterialApp(scrnSize);
        }
    }
    
    MaterialApp getMaterialApp(Size scrnSize) {
        final Scaffold home = Scaffold (
            backgroundColor : Colors.white38,
            body: SafeArea(
                child: Column (
                    children: <Widget>[
                        getAppBar(scrnSize),
                    ],
                ),
            )
        );
        return MaterialApp (home : home);
    }
    
    Container getAppBar(Size scrnSize) {
        TextStyle getTextStyle(double factor) {
            return TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
                fontSize: (factor/2.5), // Adjust font size as needed
            );
        }
        final double h = scrnSize.height * 0.08;
        double scaleFactor = h;
        double subContainerSz = scaleFactor - (scaleFactor * 0.08);
        const String title = "Calculator";
        TextStyle textStyle = getTextStyle(scaleFactor);
        TextSpan textSpan = TextSpan(text: title, style: textStyle);
        TextPainter textPainter = TextPainter(
          text: textSpan,
          textDirection: TextDirection.ltr,
        );
        textPainter.layout();
        double textWidth = textPainter.size.width;
        double textheight = textPainter.size.height;
        final double barWidth = 3*subContainerSz + textWidth + 12 + 10; //+10 extra and +12 sizedbox
        if(barWidth > scrnSize.width) {
            scaleFactor = scaleFactor * 0.3;
            textStyle = getTextStyle(scaleFactor);
            textSpan = TextSpan(text: title, style: textStyle);
            textPainter = TextPainter(
                text: textSpan,
                textDirection: TextDirection.ltr,
            );
            textPainter.layout();
            textWidth = textPainter.size.width;
            textheight = textPainter.size.height;
            subContainerSz = (scrnSize.width - textWidth - 12 -10)/3;
        }
        return Container(
            width: scrnSize.width,
            height: h,
            decoration: const BoxDecoration (
                color: appBarColor,
                shape: BoxShape.rectangle
            ),
            child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                    Row (
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget> [
                            const SizedBox(width: 4),
                            createIconButtonContainer(Icons.menu, subContainerSz, scrnSize.width, (){})
                        ]
                    ),
                    CustomPaint(
                        size: Size(textWidth, textheight), // Size based on text width and height
                        painter: TextPainterWidget(textPainter),
                    ),
                    Row (
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget> [
                            createIconButtonContainer(Icons.arrow_upward, subContainerSz, scrnSize.width, (){}),
                            const SizedBox(width: 4),
                            createIconButtonContainer(Icons.arrow_downward, subContainerSz, scrnSize.width, (){}),
                            const SizedBox(width: 4)
                        ],
                    )
                ],
            ),
        );
    }
    
    class TextPainterWidget extends CustomPainter {
        final TextPainter textPainter;
        TextPainterWidget(this.textPainter);
    
        @override
        void paint(Canvas canvas, Size size) {
            textPainter.paint(canvas, Offset.zero);
        }
    
        @override
        bool shouldRepaint(covariant CustomPainter oldDelegate) {
            return false;
        }
    }
    
    Container createIconButtonContainer(IconData icon, double containerSz, double width, Function() onPress) {
        final Container ibc = Container(
            width: containerSz,
            height: containerSz,
            alignment: Alignment.center,
            decoration: BoxDecoration(
                color: appBarColor.withOpacity(0.5),
                shape: BoxShape.circle,
                border: Border.all(color: appBarColor, width: 2),
                boxShadow: <BoxShadow>[
                    BoxShadow(
                        color: const Color(0xFF000000).withOpacity(0.35),
                        spreadRadius: 1,
                        blurRadius: 5,
                        offset: const Offset(0, 3),
                    )
                ]
            ),
            child: Center(
                child : IconButton(
                    padding: EdgeInsets.zero,
                    icon: Icon (
                        icon,
                        color: white,
                        size: containerSz * 0.6,
                    ),
                    onPressed: onPress,
                )
            )
        );
        return ibc;
    }
    

  2. You can use a LayoutBuilder, it’s a widget that allows to choose what to display depending on the available space.

    Below an example of a LayoutBuilder that displays a container of width 265 (check the variable _whicheverWidthYouWant) if available space is more than 265 and a container whose width is the available space if available space is less:

    class LayoutBuilderExample extends StatelessWidget {
      const LayoutBuilderExample({super.key});
      final _whicheverWidthYouWant = 265.0;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('LayoutBuilder Example')),
          body: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              if (constraints.maxWidth > _whicheverWidthYouWant) {
                return Container(
                  height: 100,
                  width: _whicheverWidthYouWant,
                  color: Colors.red,
                );
              } else {
                return Container(
                  height: 100,
                  width: constraints.maxWidth,
                  color: Colors.red,
                );
              }
            },
          ),
        );
      }
    

    For more info: https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html

    Login or Signup to reply.
  3. Option 1: Use can improve the responsiveness of the Icon Button based on the width and height of the device screen using Media query.

    double width = MediaQuery.of(context).size.width;
    double height = MediaQuery.of(context).size.height;

    Now you can modify the width and height of the button/icon?

    Option 2: Using LayoutBuilder you can maintain a button that can depend on the parent widget’s size.

    Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('LayoutBuilder Example')),
          body: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              if (constraints.maxWidth > 600) {
                return _buildWideContainers();
              } else {
                return _buildNormalContainer();
              }
            },
          ),
        );
      }
    

    Example:

    body: LayoutBuilder(
              builder: (context, constraints) {
                // Find the smallest size to maintain the aspect ratio
                var size = constraints.biggest.shortestSide * 0.3; // 30% of the shortest side
                return Center(
                  child: Wrap(
                    spacing: 10,
                    runSpacing: 10,
                    children: [
                      SquareCircleContainer(size: size, icon: Icons.home),
                      SquareCircleContainer(size: size, icon: Icons.settings),
                      SquareCircleContainer(size: size, icon: Icons.camera),
                    ],
                  ),
                );
              },
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search