📜  使用Flutter构建响应式 UI

📅  最后修改于: 2022-05-13 01:55:18.621000             🧑  作者: Mango

使用Flutter构建响应式 UI

在本文中,我们将介绍可以使用Flutter构建响应式应用程序的不同小部件。

1. 布局构建器:

构建一个可以依赖于父小部件大小的小部件树。如果我们想根据父级大小更改或隐藏某些内容,这很有用。

Dart
LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
            
         // constraints provide us with maxWidth,maxHeight etc, using 
         // which we can show different widgets accordingly
         if (constraints.maxWidth > 600) {
             
            // as the width is greater than 600px,
            // we'll show wide screen container
            return _buildWideScreenContainers();
          } else {
            return _buildPortraitContainer();
          }
        },
),


Dart
import 'package:flutter/material.dart';
  
void main() => runApp(const MyApp());
  
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}
  
class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:
          AppBar(title: Text("Geeks for Geeks"), backgroundColor: Colors.green),
      body: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
            
          // constraints provide us with maxWidth,maxHeight etc, using
          // which we can show different widgets accordingly
            
          if (constraints.maxWidth > 600) {
            // as the width is greater than 600px, we'll show wide screen container
            // with two containers in a row
              
            return _buildWideScreenContainers();
          } else {
            return _buildPortraitContainer();
          }
        },
      ),
    );
  }
  
  Widget _buildPortraitContainer() {
      
// here we're returning a single container since the phone
// doesn't has the required width (600px)
    return Center(
      child: Container(
        height: 100.0,
        width: 100.0,
        color: Colors.red,
      ),
    );
  }
  
  Widget _buildWideScreenContainers() {
      
// here we're returning double containers since the phone
// has the required width (600px)
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Container(
            height: 100.0,
            width: 100.0,
            color: Colors.red,
          ),
          Container(
            height: 100.0,
            width: 100.0,
            color: Colors.yellow,
          ),
        ],
      ),
    );
  }
}


Dart
class MediaQueryExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenW = MediaQuery.of(context).size.width;
    print(screenW);
  
    return Scaffold(
        
      // when screen's width is less than 600px, 
      // it shows a appbar, when it's over 600px,
      // it hides it.
      appBar: screenW <= 600
          ? AppBar(
              title: Text("Geeks for Geeks"), backgroundColor: Colors.green)
          : null,
      body: Center(
        child: Text("Mediaquery example"),
      ),
    );
  }
}


Dart
class ResponsiveWidget extends StatelessWidget {
  const ResponsiveWidget({
    Key? key,
    required this.mobileBody,
    this.tabletBody,
    this.desktopBody,
  }) : super(key: key);
  
  final Widget mobileBody;
  final Widget? tabletBody;
  final Widget? desktopBody;
  
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, dimens) {
          
        // check if the device is a phone
        if (dimens.maxWidth < kTabletBreakpoint) {
          return mobileBody;
        } else if (dimens.maxWidth >= kTabletBreakpoint && dimens.maxWidth < kDesktopBreakPoint)
        {
         // returns mobileBody if tabletBody is null
          return tabletBody ?? mobileBody;
        } else {
            
          // returns mobileBody if desktopBody is null
          return desktopBody ?? mobileBody;
        }
      },
    );
  }
}


让我们在实际的用户界面中看到这一点。

Dart



import 'package:flutter/material.dart';
  
void main() => runApp(const MyApp());
  
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}
  
class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:
          AppBar(title: Text("Geeks for Geeks"), backgroundColor: Colors.green),
      body: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
            
          // constraints provide us with maxWidth,maxHeight etc, using
          // which we can show different widgets accordingly
            
          if (constraints.maxWidth > 600) {
            // as the width is greater than 600px, we'll show wide screen container
            // with two containers in a row
              
            return _buildWideScreenContainers();
          } else {
            return _buildPortraitContainer();
          }
        },
      ),
    );
  }
  
  Widget _buildPortraitContainer() {
      
// here we're returning a single container since the phone
// doesn't has the required width (600px)
    return Center(
      child: Container(
        height: 100.0,
        width: 100.0,
        color: Colors.red,
      ),
    );
  }
  
  Widget _buildWideScreenContainers() {
      
// here we're returning double containers since the phone
// has the required width (600px)
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Container(
            height: 100.0,
            width: 100.0,
            color: Colors.red,
          ),
          Container(
            height: 100.0,
            width: 100.0,
            color: Colors.yellow,
          ),
        ],
      ),
    );
  }
}

当我们运行上面编写的代码时,这就是我们得到的。

请注意我们在纵向模式下如何看到单个框,在旋转手机时如何看到双框。

2. 媒体查询

MediaQuery 也让我们有约束。 MediaQuery 不会从父小部件中获取约束,而是从整个布局中获取它。让我们看一个使用 MediaQuery() 的例子,我们根据屏幕宽度隐藏 AppBar()。

Dart

class MediaQueryExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenW = MediaQuery.of(context).size.width;
    print(screenW);
  
    return Scaffold(
        
      // when screen's width is less than 600px, 
      // it shows a appbar, when it's over 600px,
      // it hides it.
      appBar: screenW <= 600
          ? AppBar(
              title: Text("Geeks for Geeks"), backgroundColor: Colors.green)
          : null,
      body: Center(
        child: Text("Mediaquery example"),
      ),
    );
  }
}

使用 MediaQuery(),我们可以获得屏幕尺寸、纵横比和其他有用的数据。

final query = MediaQuery.of(context); // provide us with the query
    print(query.size.aspectRatio); //aspect ratio
    print(query.size.height);//screen height
    print(query.size.width);//screen width

3.断点

BreakPoint 还可用于在flutter应用程序中开发响应式 UI。



const kTabletBreakpoint = 768.0; //breakpoint for a tablet (a tablet's width is 768 px)
const kDesktopBreakPoint = 1440.0;  //breakpoint for desktop (a desktop screen's width is 1440 px)

const kSideMenuWidth = 300.0; // for sidemenu
const kNavigationRailWidth = 72.0; // for navigation rail

const kMaxWidth = 1180.0; // maximum width

我们可以使用上面写的断点来为不同的设备显示不同的 UI。例如,

Dart

class ResponsiveWidget extends StatelessWidget {
  const ResponsiveWidget({
    Key? key,
    required this.mobileBody,
    this.tabletBody,
    this.desktopBody,
  }) : super(key: key);
  
  final Widget mobileBody;
  final Widget? tabletBody;
  final Widget? desktopBody;
  
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, dimens) {
          
        // check if the device is a phone
        if (dimens.maxWidth < kTabletBreakpoint) {
          return mobileBody;
        } else if (dimens.maxWidth >= kTabletBreakpoint && dimens.maxWidth < kDesktopBreakPoint)
        {
         // returns mobileBody if tabletBody is null
          return tabletBody ?? mobileBody;
        } else {
            
          // returns mobileBody if desktopBody is null
          return desktopBody ?? mobileBody;
        }
      },
    );
  }
}

输出:

使用 MedaQuery() 根据屏幕的宽度显示和隐藏 AppBar。

使用 LayoutBuilder() 根据父级的宽度显示和隐藏 AppBar。

有关为不同设备处理不同 UI 的更多信息,请阅读本文。就是这样。这就是我们开始使用flutter构建响应式应用程序所需的全部内容。

想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!