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),
            ),
          ),
        ),
      ),
    );
  }
}
相关推荐
小纯洁w7 分钟前
el-tree 中:lazy=“true“ 模式下使用双击展开节点而不是单击
javascript·vue.js·elementui
anyup_前端梦工厂32 分钟前
JS设计模式之组合模式:打造灵活高效的对象层次结构
javascript·设计模式·组合模式
知识的宝藏36 分钟前
内部css应该放在HTML什么位置
前端·css·html
今天吃了嘛o36 分钟前
Vue3中使用tailwindcss插件
前端·css·postcss
边中之城39 分钟前
js替换css主题变量并切换iconfont文件
开发语言·javascript·css
墨·殇42 分钟前
css实现四角边框
前端·css
深情废杨杨1 小时前
前端vue-ref与document.querySelector的对比
前端·javascript·vue.js
液态不合群1 小时前
JavaScript中if嵌套assert的方法
开发语言·javascript·ecmascript
且行且知1 小时前
前端Vue 基础学习1
前端·vue.js·学习
小于负无穷1 小时前
前端面试题(八)
前端