макет
Гибкая компоновка
Макет Flex во Flutter похож на макет Flex в CSS для Интернета.
Существуют элементы управления Row, Column, Expanded, Flexible, Spacer, Flex для управления макетом Flex во Flutter.
горизонтальное расположение строк
Имя свойства | Типы | По умолчанию | иллюстрировать |
---|---|---|---|
mainAxisAlignment | MainAxisAlignment | MainAxisAlignment.start | Расположение шпинделей |
mainAxisSize | MainAxisSize | MainAxisSize.max | Размер пространства, занимаемого шпинделем |
crossAxisAlignment | CrossAxisAlignment | CrossAxisAlignment.center | Расположение вторичной оси |
textDirection | TextDirection | null | Определить порядок размещения детей в горизонтальном направлении. |
verticalDirection | VerticalDirection | VerticalDirection.down | Определить порядок размещения детей по вертикали. |
textBaseline | TextBaseline | null | выравнивание текста |
Сначала создадим три контейнера разного размера.
class LyoutRowDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("水平布局"),
),
body: Container(
child: Row(
children: <Widget>[
Container(
height: 100,
width: 50,
color: Colors.redAccent,
),
Container(
height: 50,
width: 50,
color: Colors.blueAccent,
),
Container(
color: Colors.black,
height: 75,
width: 75,
)
],
),
));
}
}
Расположение шпинделя
Расположение дочерних элементов определяется этими двумя свойствами, textDirection и verticalDirection. textDirection определяет горизонтальное расположениеTextDirection.ltr
Расположите слева направо (используйте левую в качестве начальной позиции),TextDirection.rtl
Расположите справа налево (используйте право как исходное положение). Горизонтальное расположение verticalDirection. Когда значение уменьшается (упорядочить вниз), начальная позиция находится вверху. Когда значение вверх (упорядочить вверх), начальная позиция находится внизу.
-
запуск (по умолчанию) Упорядочивает направление в соответствии со свойством textDirection.
Дети, помещенные в начальную точку веретена
Правильное изображение, когда значение атрибута textDirection равно rtl
-
end
Упорядочивает направление в соответствии со свойством textDirection.
поместите потомков в конец главной оси
Правильное изображение, когда значение атрибута textDirection равно rtl
-
center
Упорядочивает направление в соответствии со свойством textDirection.
поместите детей в центр главной оси
Правильное изображение, когда значение атрибута textDirection равно rtl
-
spaceBetween
Упорядочивает направление в соответствии со свойством textDirection.
Средняя пустая область в направлении основных осей, так что пустая область равна детям, ребенок близок к концу до конца, без разрыва
Правильное изображение, когда значение атрибута textDirection равно rtl
-
spaceAround
Упорядочивает направление в соответствии со свойством textDirection.
Разделите пустую область в направлении главной оси так, чтобы пустая область между дочерними элементами была одинаковой, а пустая область в начале и в конце составляла половину
Правильное изображение, когда значение атрибута textDirection равно rtl
-
spaceEvenly
Упорядочить направление в соответствии со свойством textDirection
Разделите пустые области в направлении главной оси так, чтобы пустые области между дочерними элементами были равны, включая пустые области в начале и в конце.
Правильное изображение, когда значение атрибута textDirection равно rtl
Расположение поперечной оси crossAxisAlignment
оба сmainAxisAlignment: MainAxisAlignment.start
Например
-
start
Выравнивание дочерних элементов по поперечной оси. Установите для verticalDirection значение VerticalDirection.up справа.
-
end
Выровняйте дочерние элементы по концу поперечной оси. Установите для verticalDirection значение VerticalDirection.up справа.
-
center
По центру дочерние элементы выравниваются по поперечной оси. Параметр verticalDirection не изменился.
-
strentch
Растянуть дочерние элементы по поперечной оси
-
baseline
Базовые линии применяются к тексту, мы сначала создаем начало текста. Используйте базовые показатели. Свойство textBaseline должно быть установлено. Текстовые базовые линии для разных текстов. В основном базовые линии буквенных символов (например, английского) и идеографических символов (например, китайского) различаются. Вы должны сообщить Flutter, какой текст вы используете.
Row( crossAxisAlignment: CrossAxisAlignment.start, textBaseline: TextBaseline.alphabetic, children: [ Text( 'Flutter', style: TextStyle( color: Colors.yellow, fontSize: 30.0 ), ), Text( 'Flutter', style: TextStyle( color: Colors.blue, fontSize: 20.0 ), ), ], );
установить выравнивание по базовой линии
Пространство, занимаемое главной осью mainAxisSize
mainAxisSize имеет только два значения: одно минимальное, а другое максимальное. По умолчанию макс.
При значении мин. Шпиндель затянут до минимума.
Как показано на рисунке: даже тогда mainAxisAlignment: является MainAxisAlignment.spaceAround. Длина главного вала по-прежнему находится в минимальном состоянии
Вертикальное расположение столбцов
Свойства и методы вертикальной компоновки и горизонтальной компоновки одинаковы, единственное, на что стоит обратить внимание, это textDirection (горизонтальное расположение) и verticalDirection (вертикальное расположение)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "垂直布局",
home: Scaffold(
appBar: AppBar(title: Text("垂直布局")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text("1",style: TextStyle(fontSize: 100),),
Expanded(
child: Text("2"),
),
Text("33333"),
Text("4")
],
),
)));
}
}
Для удобства просмотра мы расширили 1
Гибкая компоновка
Мы смотрим на следующий исходный код для легкого понимания
можно увидетьRow
а такжеColumn
как унаследованные, так иFlex
.
class Row extends Flex
class Column extends Flex
а такжеRow
Необязательные именованные параметры конструктора (т.е.{}
Параметры пакета) есть 8.
передается родителюsuper
Конструкторов 9, а есть и большеdirection: Axis.horizontal
.
Row({
Key key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline textBaseline,
List<Widget> children = const <Widget>[],
}) : super(
children: children,
key: key,
direction: Axis.horizontal,
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
textDirection: textDirection,
verticalDirection: verticalDirection,
textBaseline: textBaseline,
);
}
Свойства во Flexdirection
Собственно направление главной оси. и был@required
вызывать. Требуется.
Flex({
Key key,
@required this.direction,
this.mainAxisAlignment = MainAxisAlignment.start,
this.mainAxisSize = MainAxisSize.max,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
this.textBaseline,
List<Widget> children = const <Widget>[],
}) : assert(direction != null),
assert(mainAxisAlignment != null),
assert(mainAxisSize != null),
assert(crossAxisAlignment != null),
assert(verticalDirection != null),
assert(crossAxisAlignment != CrossAxisAlignment.baseline || textBaseline != null),
super(key: key, children: children);
Expanded
В приведенном выше примере мы сталкиваемся с виджетом, которого раньше никогда не видели. Это легко увидеть. Расширенный игнорирует размер дочерних элементов и принудительно автоматически расширяет основную ось.ОтецДоступное пустое место. Expanded должен быть потомком Row, Column и Flex.
Следующие два примера предназначены для лучшего понимания:
//当子元素只有一个Expanded时
class LyoutExpanded extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Expanded"),
),
body: Center(
child: Container(
child: Column(
children: <Widget>[
Expanded(
child: Container(
color: Colors.blue,
width: 100,//这个被忽略掉了
),
),
],
),
),
),
);
}
}
class LyoutExpanded extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Expanded"),
),
body: Center(
child: Container(
height: 50,//填充使主轴扩展至父级高度
child: Column(
children: <Widget>[
Expanded(
child: Container(
color: Colors.blue,
height: 100,//
width: 100,
),
),
],
),
),
),
);
}
}
Expanden также обладает свойствомflex
Значение по умолчанию — 1. представляет вес. Когда дочерние элементы имеют несколько Expanden. Занять высоту родителя в соответствии со значением веса (ширина по горизонтали при строке)
<Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
width: 100,
),
),
Expanded(
child: Container(
color: Colors.red,
width: 100,
),
),
Expanded(
child: Container(
color: Colors.yellow,
width: 100,
),
),
],
Мы видим, что синие блоки в два раза больше красных и желтых.
Flexible
Гибкие компоненты могут заставлять Row, Column, Flex и другие подкомпоненты заполнять доступное пространство в направлении главной оси.способность(например, строка горизонтальна, а столбец вертикальна), но, в отличие от расширенных компонентов, он не заставляет дочерние компоненты заполнять доступное пространство. Точно так же гибкие компоненты должны быть дочерними элементами таких компонентов, как Row, Column и Flex.
Гибкость имеет свойстваfit
Когда значение свойства равно FlexFit.tight. Нет никакой разницы между гибким и расширенным.
Из исходного кода видно, что расширенное наследование и гибкое
И значение, переданное для соответствия конструктору верхнего уровня, — FlexFit.tight.
class Expanded extends Flexible
//省区其他源码
const Expanded({
Key key,
int flex = 1,
@required Widget child,
}) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);
}
Пройдите в детей Колонки. Подходящий атрибут: FlexFit.tight, заполните пустую область в соответствии с весом.
<Widget>[
Flexible(
fit: FlexFit.tight,
child: Container(
color: Colors.blue,
height: 100,
width: 100,
),
),
Flexible(
fit: FlexFit.tight,
flex: 2,
child: Container(
color: Colors.yellow,
height: 100,
width: 100,
),
),
],
Как только значение fit равно FlexFit.loose (по умолчанию)Сначала определите размер главной оси в соответствии со значением flex, а затем отрегулируйте высоту элемента дочерним элементом. Нет принудительной растяжки
Например, первый — жесткое принудительное расширение. Второй сыпучий не форсирует расширение.
<Widget>[
Flexible(
fit: FlexFit.tight,
child: Container(
color: Colors.blue,
height: 100,
width: 100,
),
),
Flexible(
fit: FlexFit.loose,
flex: 2,
child: Container(
color: Colors.yellow,
height: 100,
width: 100,
),
),
],
Поскольку второй контейнер свободен, высота желтого контейнера равна 100. Значение подгонки синего контейнера плотное, а его размер такой же, как и в предыдущем примере.
Spacer
Spacer создает регулируемое пустое пространство, которое можно использовать для настройки интервала между виджетами во гибком контейнере (строка или столбец).
После того, как дети содержат Spacer.mainAxisAlignment
Стоимость свойства будетне работает. Spacer занял все дополнительное пространство, поэтому места для перераспределения не осталось.
Row(
mainAxisAlignment: MainAxisAlignment.end,//起不到作用
children: <Widget>[
Container(
height: 100,
width: 50,
color: Colors.redAccent,
),
Spacer(),
Container(
height: 50,
width: 50,
color: Colors.blueAccent,
),
Container(
color: Colors.black,
height: 75,
width: 75,
)
],
),
Увеличить макет
Подавляющее большинство флаттер-виджетов представляют собой коробки. Их можно штабелировать, штабелировать, вкладывать друг в друга.
Мы можем иерархически вкладывать ящики, но если ящик не подходит (не подходит размер) другой ящик. Как решить?
Чтобы решить эту проблему, Flutter предоставляет FittedBox, аналогичный ImageView для мобильных устройств.
Функция, которую он реализует, состоит в том, чтобы сделать дочерний элемент масштабируемым (подходящим) или отрегулировать положение (выравнивание).
- BoxFit.contain (по умолчанию) пропорционально расширяется или сжимается, но содержимое не выходит за рамки контейнера.
- BoxFit.cover постепенно расширяется, чтобы пропорционально заполнить контейнер, и содержимое может выходить за пределы контейнера. Когда дочерний масштаб отличается от контейнера, либо высота переполняет контейнер, либо ширина переполняет контейнер.
- BoxFit.fill не сохраняет пропорции и заставляет контейнер с наполнителем растягиваться (сжиматься).
- BoxFit.fitHeight поддерживает пропорции, чтобы гарантировать полное отображение высоты в контейнере.
- BoxFit.fitWidth поддерживает соотношение, чтобы гарантировать полное отображение ширины в контейнере.
- BoxFit.none выравнивает дочерний элемент в целевом поле (при воспроизведении по умолчанию) и отбрасывает часть за пределами поля, исходный файл не увеличивается и не сжимается.
- BoxFit.scaleDown выравнивает дочерний элемент в целевом поле (при воспроизведении по умолчанию), когда дочерний элемент больше контейнера, он согласуется с контейнером. Если дочерний элемент меньше контейнера, он не совместим ни с одним
Для того, чтобы облегчить понимание, мы можем найти картинку для тестирования
class Lyoutfitdemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("data")),
body: Container(
height: 250,
width: 250,
color: Colors.indigo[200],
child: FittedBox(
child: Image.asset('images/fittedbox.png')),
),
);
}
}
- BoxFit.contain
- BoxFit.cover
- BoxFit.fill
- BoxFit.fitHeight
5.BoxFit.fitWidth
- BoxFit.none
- BoxFit.scaleDown
Примечание. Нет необходимости создавать FittedBox, изображение содержит атрибут fit. Эффект значения такой же, как у FittedBox.
Компоновка с накоплением
Стек похож на веб-модель компоновки абсолютного позиционирования. Стопки не выкладываются в ряды или столбцы, а складываются в определенном порядке и положении. можно использоватьPositioned
а такжеAlign
Позиционирование как стек.
Пример: реализация эффекта градиента изображения с использованием каскадного макета
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "渐变状态栏",
home: Scaffold(
body: Container(
height: 400,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(
'images/Stack.png',
fit: BoxFit.cover,
),
const DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment(0.0, -1.0),
end: Alignment(0.0, -0.4),
colors: <Color>[Color(0x90000000), Color(0x00000000)],
),
),
),
],
),
),
),
);
}
}
эффект градиента изображения
Вот пример двух элементов управления, расположенных друг над другом. Конечно, дочерние виджеты могут появляться где угодно внутри родителя. Управление положением реализовано через два виджета.
Выровнять макет
Align — компонент выравнивания, установленныйchildВыравнивание родителя (например, контейнера, стека и т. д.) и настройка его размера в соответствии с размером дочернего элемента.
Родительский контейнер этой статьи выбирает стек
Alignment
Среди них такие свойства
topLeft (вверху слева), topCenter (вверху в центре), topRight (вверху справа), centerLeft, center, centerRight, bottomLeft, bottomCenter, bottomRight
class LayoutAlignDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("align部件"),
),
body: Stack(
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
],
));
}
}
Alignment.lerp(Alignment a, Alignment b, double t)
Метод lerp имеет три параметра, первые два параметра относятся к типу Alignment, а третий параметр является десятичным.
Когда t равно 0, значение, возвращаемое этим методом, равно a.
Когда t равно 1, вернуть значение b.
Когда t равно 0,5, позиция виджета находится в середине позиции, указанной a и b.
Так что это t является смещением. Задается как смещение между a и b.
//在Stack children中添加一个align
Align(
alignment: Alignment.lerp(Alignment.bottomCenter, Alignment.center,0.5),//位于Alignment.bottomCenter和Alignment.center的中央
child: Container(
width: 100,
height: 100,
color: Colors.yellow,
),
),
выравнивание со смещением
Пары смещений по отношению к их путям a и b описаны выше.
FractionalOffset — это еще один метод смещения, представляющий собой смещение относительно левого верхнего угла родительского виджета.
Создайте смещение FractionalOffset (dx,dy). Значения dx и dy равны 0~1. В верхнем левом положении dx и dy равны 0.
Align(
alignment: FractionalOffset(0, 0.5),
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
Также в исходном коде:
class FractionalOffset extends Alignment
FractionalOffset
Унаследовано от Alignment, поэтому можно использовать свойства Alignment, чтобы мы могли использовать виджет в верхнем левом углу.FractionalOffset.topLeft
class LayoutAlignDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("align部件"),
),
body: Stack(
children: <Widget>[
Align(
alignment: FractionalOffset(0, 0),
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
Align(
alignment: FractionalOffset(0, 0.5),
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
Align(
alignment: FractionalOffset(0, 1),
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
Align(
alignment: Alignment.lerp(Alignment.bottomCenter, Alignment.center,0.5),
child: Container(
width: 100,
height: 100,
color: Colors.yellow,
),
),
Align(
alignment: FractionalOffset.topRight,
child: Container(
width: 100,
height: 100,
color: Colors.yellow,
),
),
],
));
}
}
Как и в случае с Alignment(dx, dy), источником системы координат является центр родительского контейнера. Диапазон значений dx составляет -1~1, а диапазон значений dy составляет -1~1. Устанавливает положение дочернего элемента.
Positioned
Позиционированные виджеты могут управлятьStack
Положение нейтронного элемента. Разница между Positioned и Align заключается в том, что Position должен быть дочерним элементом стека.
ПозицияДаtop
,bottom
,left
,right
,height
,width
.
top
,bottom
,left
,right
Эти величины представляют собой расстояния между границей дочернего элемента и одной из границ родительского элемента.
То есть, когдаФиксированная высота и длинаКонтейнеры, как только мы определяем количество для левого или правого и количество для нижнего или верхнего, можно определить его положение.
часть кода
Stack(
children: <Widget>[
Positioned(
top: 100,
right: 100,
width: 100,
height: 100,
child: Container(
color: Colors.red,
),
),
],
)
Анализ исходного кода
const Positioned({
Key key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
@required Widget child,
}) : assert(left == null || right == null || width == null),
assert(top == null || bottom == null || height == null),
super(key: key, child: child);
В горизонтальном направлении, если assert(false) выдаст ошибку
В скобках указано значениеleft == null || right == null || width == null
Если хотя бы одно из значений left, right и width равно null, программа не сообщит об ошибке.
То есть, когда ширина не указана (пусто), левое и правое могут существовать одновременно. В это время ширина контейнера будет автоматически регулироваться в соответствии с расстоянием (слева и справа) от границы.
Stack(
children: <Widget>[
Positioned(
top: 100,
right: 100,
left: 100,
// width: 100,
height: 100,
child: Container(
color: Colors.red,
),
),
],
)
IndexedStack
IndexedStack наследуется от Stack
class IndexedStack extends Stack
У него и у стека другой индекс свойства, значит только первый из нескольких элементов.
IndexedStack(
index: 1,//只显示第二个
children: <Widget>[
Positioned(
top: 100,
right: 100,
left: 100,
height: 100,
child: Container(
color: Colors.red,
),
),
Positioned(
top: 500,
right: 100,
left: 100,
height: 100,
child: Container(
color: Colors.red,
),
),
],
)
Компоновка контейнера
Контейнер может создать прямоугольный элемент. Можно украсить BoxDecoration. Фон, граница, тень.
class LyoutContainerdemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Container容器"),
),
body: Container(
height: 200,
width: 200,
child: Text("这是一个Container容器"),
decoration: BoxDecoration(
color: Colors.red[200],
// shape: BoxShape.circle, //形状
border: Border.all(width: 10.0),
boxShadow: [
BoxShadow(
offset: Offset(0.0, 100.0), //模糊偏移量
color: Color.fromRGBO(16, 20, 188, 1.0), //颜色
blurRadius: 10, //模糊
spreadRadius: -9.0, //在应用模糊之前阴影的膨胀量
),
],
),
),
);
}
}
Чтобы продемонстрировать функцию, эффект этой картинки преувеличен.
Добавьте красивый эффект
Подобно макету поля Css, мы также можем установить поля для поля через Margin.
Container(
margin: EdgeInsets.all(50.0),//外边距50.0
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.red[600],
border: Border.all(width: 2.0),
boxShadow: [
BoxShadow(
offset: Offset(2.0, 9.0), //偏移量
color: Colors.red[200], //颜色
blurRadius: 10, //模糊
spreadRadius: -1.0, //在应用模糊之前阴影的膨胀量
),
],
),
),
Макет заполнения
Используется для обработки расстояния между контейнером и дочерними элементами. Свойству Padding соответствует свойство margin. поля используются для обработки расстояний от других компонентов. Эффект компонента padding и свойства padding в контейнере на самом деле одинаков.Когда они появляются одновременно, реальным дополнением будет их сложение.
class LayoutPaddingDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Padding 布局"),
),
body: Container(
padding: EdgeInsets.all(20.0),//#1这两处的属性效果是一致的
decoration: BoxDecoration(
color: Colors.yellow,
border: Border.all(color: Colors.white, width: 8.0)),//白色边框
child: Padding(
child: Container(
decoration: BoxDecoration(
color: Colors.red,
border: Border.all(color: Colors.white, width: 8.0)),//白色边框
),
padding: EdgeInsets.all(10.0),//#1这两处的属性效果是一致的
),
),
);
}
}
написать на обороте
Во Flutter задействовано более 30 видов виджетов, и существует множество способов добиться такого же эффекта пользовательского интерфейса. В этой статье основное внимание уделяется нескольким часто используемым компонентам.