Flutter屏幕适配

我们可以根据下面有适配属性的Widget来进行屏幕适配

1.MediaQuery

通过它可以直接获得屏幕的大小(宽度 / 高度)和方向(纵向 / 横向)

Size screenSize = MediaQuery.of(context).size;
double width = screenSize.width;
double height = screenSize.height;
Orientation orientation = MediaQuery.of(context).orientation;
//横向:orientation==Orientation.portrait
//纵向:orientation==Orientation.landscape

实例代码

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
  
class HomePage11 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Size screenSize = MediaQuery.of(context).size;
    Orientation orientation = MediaQuery.of(context).orientation;
    return Scaffold(
      body: Container(
        color: Colors.pink,
        child: Center(
          child: Text(
            'View\n\n' +
                '[整个屏幕的宽]: ${screenSize.width.toStringAsFixed(2)}\n\n' +
                '[整个屏幕的高]: ${screenSize.height.toStringAsFixed(2)}\n\n'
                    '[MediaQuery orientation]: $orientation',
            style: TextStyle(color: Colors.white, fontSize: 18),
          ),
        ),
      ),
    );
  }
}

2. LayoutBuilder

使用 LayoutBuilder 组件,可以获得一个 BoxConstraints 对象,通过该对象我们就可以拿到 Widget 的 maxWidth(最大宽度) 和maxHeight(最大高度)

import 'package:flutter/material.dart';
 
class HomePage11 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Size screenSize = MediaQuery.of(context).size;
    return Scaffold(
      body: Row(
        children: [
          Expanded(
            flex: 2,
            child: LayoutBuilder(
              builder: (context, constraints) => Container(
                color: Colors.pink,
                child: Center(
                  child: Text(
                    'View 1\n\n' +
                        '[MediaQuery]:\n ${screenSize.width.toStringAsFixed(2)}\n\n' +
                        '[LayoutBuilder]:\n${constraints.maxWidth.toStringAsFixed(2)}',
                    style: TextStyle(color: Colors.white, fontSize: 18),
                  ),
                ),
              ),
            ),
          ),
          Expanded(
            flex: 3,
            child: LayoutBuilder(
              builder: (context, constraints) => Container(
                color: Colors.white,
                child: Center(
                  child: Text(
                    'View 2\n\n' +
                        '[MediaQuery]:\n ${screenSize.width.toStringAsFixed(2)}\n\n' +
                        '[LayoutBuilder]:\n${constraints.maxWidth.toStringAsFixed(2)}',
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

3. OrientationBuilder

要确定当前 Widget 的方向,可以使用 OrientationBuilder 组件。这里的方向与 MediaQuery 提供的设备方向不同。如下这个示例:

import 'package:flutter/material.dart';
 
class HomePage11 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Orientation deviceOrientation = MediaQuery.of(context).orientation;
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            flex: 2,
            child: Container(
              color: Colors.pink,
              child: OrientationBuilder(
                builder: (context, orientation) => Center(
                  child: Text(
                    'View 1\n\n' +
                        '[MediaQuery orientation]:\n$deviceOrientation\n\n' +
                        '[OrientationBuilder]:\n$orientation',
                    style: TextStyle(color: Colors.white, fontSize: 18),
                  ),
                ),
              ),
            ),
          ),
          Expanded(
            flex: 3,
            child: OrientationBuilder(
              builder: (context, orientation) => Container(
                color: Colors.white,
                child: Center(
                  child: Text(
                    'View 2\n\n' +
                        '[MediaQuery orientation]:\n$deviceOrientation\n\n' +
                        '[OrientationBuilder]:\n$orientation',
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

4. Expanded 和 Flexible

Expanded 和 Flexible 这两个组件可以和 Column/Row 搭配使用,来实现非常完美的自适应效果。Expanded 可以用来拓展 Row, 、Column 和 Flex,从而让子组件填充可用空间,Flexible 功能类似但并不一定能填充全部可用空间。

下面这个例子演示了混合使用 Expanded 和 Flexible 的各种方式:

import 'package:flutter/material.dart';
 
class HomePage11 extends StatelessWidget {
  const HomePage11({super.key});
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: SafeArea(
        child: Column(
          children: [
            Row(
              children: [
                ExpandedWidget(),
                FlexibleWidget(),
              ],
            ),
            Row(
              children: [
                ExpandedWidget(),
                ExpandedWidget(),
              ],
            ),
            Row(
              children: [
                FlexibleWidget(),
                FlexibleWidget(),
              ],
            ),
            Row(
              children: [
                FlexibleWidget(),
                ExpandedWidget(),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
 
class ExpandedWidget extends StatelessWidget {
  const ExpandedWidget({super.key});
 
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.pink,
          border: Border.all(color: Colors.white),
        ),
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Text(
            'Expanded',
            style: TextStyle(color: Colors.white, fontSize: 24),
          ),
        ),
      ),
    );
  }
}
 
class FlexibleWidget extends StatelessWidget {
  const FlexibleWidget({super.key});
 
  @override
  Widget build(BuildContext context) {
    return Flexible(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.amber,
          border: Border.all(color: Colors.white),
        ),
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Text(
            'Flexible',
            style: TextStyle(color: Colors.blue, fontSize: 24),
          ),
        ),
      ),
    );
  }
}

5. FractionallySizedBox

FractionallySizedBox 组件可以使子组件填充部分可用空间,该特性在 Expanded 或 Flexible 中特别有用。示例如下:

import 'package:flutter/material.dart';
 
class HomePage11 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                FractionallySizedWidget(widthFactor: 0.4),
              ],
            ),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                FractionallySizedWidget(widthFactor: 0.6),
              ],
            ),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                FractionallySizedWidget(widthFactor: 0.8),
              ],
            ),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                FractionallySizedWidget(widthFactor: 1.0),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
 
class FractionallySizedWidget extends StatelessWidget {
  final double widthFactor;
  FractionallySizedWidget({required this.widthFactor});
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: FractionallySizedBox(
        alignment: Alignment.centerLeft,
        widthFactor: widthFactor,
        child: Container(
          decoration: BoxDecoration(
            color: Colors.pink,
            border: Border.all(color: Colors.white),
          ),
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Text(
              '${widthFactor * 100}%',
              style: TextStyle(color: Colors.white, fontSize: 24),
            ),
          ),
        ),
      ),
    );
  }
}

6. AspectRatio

AspectRatio 组件可以直接指定子组件的固定宽高比例,使用时,我们可以使用布局约束的最大宽度,并给定一个宽高比自适应其高度,如下示例:

import 'package:flutter/material.dart';
import 'package:fraction/fraction.dart';
 
class HomePage11 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: SafeArea(
        child: Column(
          children: [
            AspectRatioWidget(ratio: '16 / 9'),
            AspectRatioWidget(ratio: '3 / 2'),
          ],
        ),
      ),
    );
  }
}
 
class AspectRatioWidget extends StatelessWidget {
  final String ratio;
  AspectRatioWidget({required this.ratio});
  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: Fraction.fromString(ratio).toDouble(),
      child: Container(
        decoration: BoxDecoration(
          color: Colors.orange,
          border: Border.all(color: Colors.white),
        ),
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(
            child: Text(
              'AspectRatio - $ratio',
              style: TextStyle(color: Colors.white, fontSize: 24),
            ),
          ),
        ),
      ),
    );
  }
}
相关推荐
木子七2 分钟前
vue2-路由Router
前端·vue
未 顾20 分钟前
HTML-CSS-JS-day01:html常见的标签
javascript·css·html
tao_sc24 分钟前
stm32启动过程解析startup启动文件
javascript·stm32·嵌入式硬件
知野小兔24 分钟前
【Angular】eventDispatcher详解
前端·javascript·angular.js
苦逼的猿宝39 分钟前
Echarts中柱状图完成横向布局
前端·javascript·echarts
禾戊之昂41 分钟前
【Electron学习笔记(一)】Electron基本介绍和环境搭建
前端·javascript·electron·node.js
加班是不可能的,除非双倍日工资1 小时前
js 原生拖拽排序功能 简单实现
前端·javascript
放逐者-保持本心,方可放逐1 小时前
dom 元素应用 + for 循环应用
前端·javascript·for
冰冻果冻1 小时前
vue--制作购物车
前端·javascript·vue.js
前端设计诗1 小时前
CSS clamp() 函数:构建更智能的响应式设计
前端·css·less·css3·html5