Flutter screen adaptation

At present, there are many mobile devices, and different devices have different phone screens.

At present, mobile terminal development must be adapted to different devices, whether it is mobile native development, small programs, H5 pages.

How does the Flutter adapt to different phone screens? Let’s talk about that.

One. Flutter unit

1.1. Units in Flutter

When developing a Flutter, we usually do not need to pass in units of size. What units are used for Flutter?

  • Flutter uses a point similar to the point pt, or point, in iOS.
  • So we often say the iPhone6 is 375×667, but its resolution is actually 750×1334.
  • The iPhone6 has a DPR of 2.0 and the iPhone6plus has a DPR of 3.0
IPhone Device Parameters

In Flutter development, we used the corresponding logical resolution

1.2. Information about the Flutter device

To get some information on the screen, MediaQuery:

// 1. Media query information
final mediaQueryData = MediaQuery.of(context);

// 2. Get the width and height
final screenWidth = mediaQueryData.size.width;
final screenHeight = mediaQueryData.size.height; final physicalWidth = window.physicalSize.width; final physicalHeight = window.physicalSize.height; final dpr = window.devicePixelRatio; print("The screen width:$screenWidth height:$screenHeight"); print("Resolution:$physicalWidth - $physicalHeight"); print("dpr: $dpr");  // 3. Status bar height // Screen with bangs :44 screen without bangs: 20 final statusBarHeight = mediaQueryData.padding.top; // Screen with bangs :34 screen 0 without bangs final bottomHeight = mediaQueryData.padding.bottom; print("Status bar height:$statusBarHeightBottom height:$bottomHeight"); Copy the code

To obtain some device-related information, you can use one of the official libraries:

dependencies:
  device_info: ^0.42.+1
Copy the code

Two. Adaptation scheme

2.1. Adaptation Overview

Suppose we have code like this:

  • Display a 200 x 200 Container in the middle of the screen
  • There is a paragraph in the Container that says 30
class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
 title: Text("Home page"),  ),  body: Center(  child: Container(  width: 200. height: 200. color: Colors.red,  alignment: Alignment.center,  child: Text("Hello World", style: TextStyle(fontSize: 30, color: Colors.white),),  ),  ),  );  } } Copy the code

The code above will behave differently on different screens:

  • Obviously, if you follow the rules above, it’s too big on the iPhone5 and too small on the iPhone6plus

  • During development, we should be able to scale for different screens

Different screen performance

In front-end development, there are several common adaptation schemes for different screens:

  • Rem:
    • Rem sets a font size for the root tag (HTML tag);
    • But different screen animation to set different font size (can be queried through media, can also be dynamic calculation through JS);
    • All other units use rem units (relative to the root tag);
  • Vw, wh:
    • Vw and VH divide the screen (viewport) into 100 equal parts, a 1vw is 1% of the size;
    • All other units use VW or WH units;
  • The RPX:
    • RPX is a fit in the applet, it uses 750px as the design, 1rpx= screen width /750;
    • All other units use RPX;

Here I use RPX of the applet to complete the fit of the Flutter

2.2. The RPX adaptation

What is the principle of RPX in applets?

  • Whatever screen it is, 750 pieces
  • On iPhone5:1rpx = 320/750 = 0.4266 ≈ 0.42px
  • On iPhone6:1rpx = 375/750 = 0.5px
  • On iPhone6plus: 1rpx = 414/750 = 0.552px
The correspondence of RPX

You can multiply your size by the units of RPX:

  • For example, the width of 100px: 100 * 2 * RPX
  • On the iPhone5, the result is 84px
  • On the iPhone6, the result is 100px
  • On the iPhone6plus, the result is 110.4px

Let’s wrap a utility class ourselves:

  • The utility class needs to initialize, pass in the context
    • You can use a media query to get the width and height of the screen by passing in the context
    • You can also pass in an optional parameter, what size is the draft
class HYSizeFit {
  static MediaQueryData _mediaQueryData;
  static double screenWidth;
  static double screenHeight;
  static double rpx;
 static double px;   static void initialize(BuildContext context, {double standardWidth = 750{}) _mediaQueryData = MediaQuery.of(context);  screenWidth = _mediaQueryData.size.width;  screenHeight = _mediaQueryData.size.height;  rpx = screenWidth / standardWidth;  px = screenWidth / standardWidth * 2;  }   // Set by pixel  static double setPx(double size) {  return HYSizeFit.rpx * size * 2;  }   // Set to RXP  static double setRpx(double size) {  return HYSizeFit.rpx * size;  } } Copy the code

Initialize the HYSizeFit class properties:

  • Note: Context must be used in the Widget that already has the MaterialApp, otherwise it is invalid
class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Initialize HYSizeFit
    HYSizeFit.initialize(context);
 return null;  } } Copy the code

Use RPX for screen adaptation:

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    HYSizeFit.initialize(context);
    return Scaffold(
 appBar: AppBar(  title: Text("Home page"),  ),  body: Center(  child: Container(  width: HYSizeFit.setPx(200),  height: HYSizeFit.setRpx(400),  color: Colors.red,  alignment: Alignment.center,  child: Text("Hello World", style: TextStyle(fontSize: HYSizeFit.setPx(30), color: Colors.white),),  ),  ),  );  } } Copy the code

Let’s look at the implementation:

RPX adaptation scheme

2.3. Best practices

It would obviously be a lot of trouble to use hysizefit.setpx (200) or hysizefit.setrpx (400) every time we needed to change the current width or height.

Is there a better way to do this? Like 200.px or 400. RPX, very clean and concise

Sure, we need to rely on a feature of the Dart language: Extension

  • Dart starts with 2.7.0 and can be extended with Extension to existing classes (in fact, Swift also has it).
  • Existing classes include: custom classes, third-party library classes, system classes

For example, we now extend String:

  • Parse (this) extends a parseInt method, of course calling int.parse(this) internally, but the caller becomes the String itself
// Step 1: Extend the code
extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }
 / /... }  // Step 2: Call the code // Import the module corresponding to the extension class import 'string_apis.dart'; // use the inside method print(The '42'.padLeft(5)); // Use the same method as String print(The '42'.parseInt()); // Use the String extension method Copy the code

Obviously, numbers (e.g. 200, 200.0) have corresponding wrapper classes int, double, which we can extend:

1. Extend to int

import '.. /shared/size_fit.dart';

extension IntFit on int {
  double get px {
    return HYSizeFit.setPx(this.toDouble());
 }   double get rpx {  return HYSizeFit.setRpx(this.toDouble());  } } Copy the code

2. Extend to double

import '.. /shared/size_fit.dart';

extension DoubleFit on double {
  double get px {
    return HYSizeFit.setPx(this);
 }   double get rpx {  return HYSizeFit.setRpx(this);  } } Copy the code

How is it used?

import './extension/double_extension.dart';
import './extension/int_extension.dart';

print(200.px); // 200px is different under different screens
print(400.rpx); 400rpx is different on different screens
Copy the code

Note: All content will be published on our official website. Later, Flutter will also update other technical articles, including TypeScript, React, Node, Uniapp, MPvue, data structures and algorithms, etc. We will also update some of our own learning experiences

The public,