Flutter Adaptive UI using Screenutil

Hi Guys,

I am using Flutter Screenutil for adaptive & responsive UI, but the issue that I am encouraging with images & icons (SVGs) stretching because I am using .w & .h to adapt the Widget.
So how to avoid stretching?

My standard response (already posted twice here, I think):

You don’t want pixel perfect. You want responsive. And Flutter has many amazing tools to make responsive layouts, like LayoutBuilder for breakpoints, and Flex (Row/Column) widgets for adaptive sizing. Figma and other mockup tools are generally very poor at representing this… the best tool to preview layout designs is Flutter itself (thanks to hot reload). Oh, and familiarize yourself with less-referenced layout widgets like FittedBox, FractionallySizedBox, AspectRatio, Spacer, Wrap, and learn when to use double.infinity for a width or height rather than querying with MediaQuery for the useless screen size. This is a great writeup from the author of Boxy on the fundamentals of Flutter layout including MediaQuery: MediaQuery - ping's notes.

1 Like

Images must obey the aspect ratio, so you can put it inside an AspectRatio(aspectRatio: imageWidth / imageHeight, child: Image()) or you can put it inside a SizedBox(width: imageWidth, height: imageHeight, child: Center(child: Image())).

Notice that you WILL NEED to calculate the new size of the image because you NEED to fill in the cacheWidth and cacheHeight, otherwise, you’ll waste a lot of memory (there are even a debug flag that will warn you of those issues: debugInvertOversizedImages = kDebugMode;)

To check the available space a Widget will have, you can use LayoutBuilder. From there, you know the available width and height your widget will have and then you can calculate the new image size, by using this example:

import 'package:flutter/material.dart';

class ResponsiveImage extends StatelessWidget {
  final String imageUrl = 'your_image_url_here'; // Replace with your image URL

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        // Original image size
        const double originalWidth = 200.0;
        const double originalHeight = 100.0;
        final double aspectRatio = originalWidth / originalHeight;

        // Calculate available width and height
        final double availableWidth = constraints.maxWidth;
        final double availableHeight = constraints.maxHeight;

        // Calculate width and height maintaining aspect ratio
        double width, height;
        if (availableWidth / availableHeight > aspectRatio) {
          // Constrain by height
          height = availableHeight;
          width = height * aspectRatio;
        } else {
          // Constrain by width
          width = availableWidth;
          height = width / aspectRatio;
        }

        // Get the device's pixel ratio
        final double devicePixelRatio = MediaQuery.of(context).devicePixelRatio;

        return Center(
          child: Image.network(
            imageUrl,
            width: width,
            height: height,
            cacheWidth: (width * devicePixelRatio).toInt(),
            cacheHeight: (height * devicePixelRatio).toInt(),
            fit: BoxFit.contain,
          ),
        );
      },
    );
  }
}
1 Like