SaFi Bank Space : Screen Util - Pixel Matching

Screen util is used to set the widget size to match the UI design. UI design should have a base device and follows the constraint. Base device width and height should be set as defaultWidth and defaultHeight or defined on init.

import 'dart:math';

import 'package:flutter/material.dart';

class ScreenUtil {
  static final ScreenUtil _instance = ScreenUtil._();
  static const int defaultWidth = 375;
  static const int defaultHeight = 667;

  /// Size of the phone in UI Design , px
  late final num uiWidthPx;
  late final num uiHeightPx;
  late final BuildContext rootContext;

  /// allowFontScaling Specifies whether fonts should scale
  /// to respect Text Size accessibility settings. The default is false.
  late bool allowFontScaling;

  static late MediaQueryData _mediaQueryData;

  factory ScreenUtil() {
    return _instance;
  }

  ScreenUtil._();

  ///
  /// This should be called once at app init
  /// * `width` the UI design width
  /// * `height` the UI design height
  ///
  static void init(
    BuildContext context, {
    num width = defaultWidth,
    num height = defaultHeight,
    bool allowFontScaling = false,
  }) {
    _instance;
    _instance.uiWidthPx = width;
    _instance.uiHeightPx = height;
    _instance.allowFontScaling = allowFontScaling;
    _instance.rootContext = context;

    _mediaQueryData = MediaQuery.of(context);
  }

  /// The number of font pixels for each logical pixel.
  static double get textScaleFactor => _mediaQueryData.textScaleFactor;

  /// The size of the media in logical pixels (e.g, the size of the screen).
  static double get pixelRatio => _mediaQueryData.devicePixelRatio;

  /// The horizontal extent of this size.
  static double get screenWidthDp => _mediaQueryData.size.width;

  ///The vertical extent of this size. dp
  static double get screenHeightDp => _mediaQueryData.size.height;

  /// The vertical extent of this size. px
  static double get screenWidth => screenHeightDp * pixelRatio;

  /// The vertical extent of this size. px
  static double get screenHeight => screenHeightDp * pixelRatio;

  /// The offset from the top
  static double get statusBarHeight => _mediaQueryData.padding.top;

  /// The offset from the bottom.
  static double get bottomBarHeight => _mediaQueryData.padding.bottom;

  /// The ratio of the actual dp to the design draft px
  double get scaleWidth => screenWidthDp / uiWidthPx;

  double get scaleHeight =>
      (screenHeightDp - statusBarHeight - bottomBarHeight) / uiHeightPx;

  double get scaleText => scaleWidth;

  double get minimumScale => min(scaleWidth, scaleHeight);

  /// Adapted to the device width of the UI Design.
  /// Height can also be adapted according to this to ensure no deformation ,
  /// if you want a square
  num setWidth(num width) => width * scaleWidth;

  /// Highly adaptable to the device according to UI Design
  /// It is recommended to use this method to
  /// achieve a high degree of adaptation
  /// when it is found that one screen in the UI design
  /// does not match the current style effect,
  ///  or if there is a difference in shape.
  num setHeight(num height) => height * scaleHeight;

  ///Font size adaptation method
  num setSp(num fontSize, {bool allowFontScalingSelf = false}) =>
      (allowFontScaling || allowFontScalingSelf)
          ? (fontSize * scaleText)
          : (fontSize * scaleText) / textScaleFactor;

  num setMinSp(num fontSize) => fontSize * minimumScale;
}

extension ScreenUtilExt on num {
  num get h => ScreenUtil().setHeight(this);
  num get w => ScreenUtil().setWidth(this);
  num get sp => ScreenUtil().setSp(this);
}

To use the screen utils, we need to call ScreenUtil.init in app.dart at MaterialApp builder.

MaterialApp(
  builder: (context, widget) {
     ScreenUtil.init(context);
     return MyScreen();
  },
  ...
)

Once it is initiated, we can use ScreenUtil().setHeight(num), ScreenUtil().setWidth(num), ScreenUtil().setSp(num). Or we can use the extension by importing the ScreenUtils, example:

import 'package:generic_ui/utils/screen_utils.dart'
.....
Widget build(BuildContext context) {
  return SizedBox(
    height: 100.h,
    width: 50.w,
  ) 
}