使用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 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!