Последнее обновление:

Виджет Wrap - наш незаменимый помощник

Flutter

В этой статье я покажу код и примеры работы с этим полезным виджетом. В конце статьи лежит код обучающего приложения. Поиграйте с ним самостоятельно, чтобы лучше понять, как работает виджет Wrap.

Основы

Обычно, когда вы хотите расположить несколько виджетов по горизонтали или вертикали, вы используете виджеты Row или Column.

Row(
  children: [
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
  ],
),
виджет Row
виджет Row

Но если места недостаточно, содержимое обрезается, и вы получаете желто-полосатое предупреждение о переполнении.

Row(
  children: [
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
  ],
),
строка переполнена
строка переполнена

Чтобы исправить это, можно использовать виджет Wrap вместо Row.

Wrap(
  children: [
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
  ],
),
виджет wrap
Не помещающиеся элементы переносятся на следующую строку

По умолчанию используется горизонтальный перенос строк, но если требуется вертикальное расположение, нужно установить direction.

Wrap(
  direction: Axis.vertical,
  children: [
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
  ],
),
вертикальное направление
direction: Axis.vertical

Вы также можете установить выравнивание и интервал между виджетами. spacing  - это пространство перед следующим виджетом. runSpacing - это пространство между строками или столбцами.

Wrap(
  direction: Axis.vertical,
  alignment: WrapAlignment.end,
  spacing: 10.0,
  runSpacing: 20.0,
  children: [
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
    MyWidget(),
  ],
),
увеличенные интервалы

Применение

Очень удобно использовать Wrap, при работе с кнопками:

Wrap(
  children: [
    MyButton('OK'),
    MyButton('Cancel'),
    MyButton('Remind me again tomorrow'),
  ],
),
wrap с кнопками
кнопки обернуты виджетом Wrap

Или, например, с чипсами:

Wrap(
  children: [
    MyChip('Andrew Brogdon'),
    MyChip('Emily Fortuna'),
    MyChip('Filip Hráček'),
  ],
),
чипсы с wrap
Чипсы обернуты в виджет Wrap

Погружаемся глубже

Вы можете заставить виджеты начинаться с любого угла и располагаться в любом направлении, играя со свойствами direction, verticalDirection и textDirection.

Wrap(
  direction: Axis.horizontal, // default
  children: [
    MyWidget('A'),
    MyWidget('B'),
    MyWidget('C'),
    MyWidget('D'),
    MyWidget('E'),
  ],
),
пример
direction: Axis.vertical,
пример 2
verticalDirection: VerticalDirection.up,
пример 3
direction: Axis.vertical,
verticalDirection: VerticalDirection.up,
пример 4
textDirection: TextDirection.rtl,
пример 5
textDirection: TextDirection.rtl,
direction: Axis.vertical,
пример 6
textDirection: TextDirection.rtl,
verticalDirection: VerticalDirection.up,
пример 7
textDirection: TextDirection.rtl,
direction: Axis.vertical,
verticalDirection: VerticalDirection.up,
пример 8

Выравнивание с помощью Wrap

В этом разделе показано, как выравнивание влияет на размещение элементов. Ширина и высота установлены в 280, что слишком мало для четырех предметов.

start

Wrap(
  alignment: WrapAlignment.start, // default
  children: [
    MyWidget('A'),
    MyWidget('B'),
    MyWidget('C'),
    MyWidget('D'),
    MyWidget('E'),
    //MyWidget('F'),
    //MyWidget('G'),
  ],
),
выравнивание start
alignment: WrapAlignment.start

end

alignment: WrapAlignment.end,
выравнивание end
alignment: WrapAlignment.end

center

alignment: WrapAlignment.center,
выравнивание center
alignment: WrapAlignment.center

spaceAround

alignment: WrapAlignment.spaceAround,
выравнивание spaceAround
alignment: WrapAlignment.spaceAround

spaceBetween

alignment: WrapAlignment.spaceBetween,
выравнивание spaceBetween
alignment: WrapAlignment.spaceBetween

spaceEvenly

alignment: WrapAlignment.spaceEvenly,
выравнивание spaceEvently
alignment: WrapAlignment.spaceEvenly

Еще немного про выравнивание

runAlignment влияет на выравнивание последовательных строк или столбцов.

start

Wrap(
  runAlignment: WrapAlignment.start, // default
  children: [
    MyWidget('A'),
    MyWidget('B'),
    MyWidget('C'),
    MyWidget('D'),
    MyWidget('E'),
  ],
),
start выравнивание

end

runAlignment: WrapAlignment.end,
end выравнивание

center

runAlignment: WrapAlignment.center,
center выравнивание

spaceAround

runAlignment: WrapAlignment.spaceAround,
spaceAround

spaceBetween

runAlignment: WrapAlignment.spaceBetween,
spaceBetween

spaceEvenly

runAlignment: WrapAlignment.spaceEvenly,
spaceEvently

Почему мои изменения не вступают в силу?

Одна из причин может заключаться в том, что ширина вашего виджета Wrap получается настолько узкой, насколько это возможно, и нет места для выравнивания. Это может произойти, если он находится внутри столбца. Если это так, попробуйте установить CrossAxisAlignment.stretch для столбца.

Простое приложение с примерами

Создайте во флаттере новый проект и замените весь код в main.dart на этот:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: WrapWidgetDemo(),
      ),
    );
  }
}

class WrapWidgetDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300,
        //height: 300,
        color: Colors.blue,
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.all(10),
        child:

      // Замените этот код примерами из статьи
        Wrap(
          children: [
            MyWidget(),
            MyWidget(),
            MyWidget(),
            MyWidget(),
            MyWidget(),
          ],
        ),
        
      ),
    );
  }
}

class MyWidget extends StatelessWidget {
  //final String text;
  //MyWidget(this.text);
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(10),
      width: 50,
      height: 50,
      color: Colors.yellow.shade700,
      //child: Center(child: Text(text)),
    );
  }
}

class MyButton extends StatelessWidget {
  final String text;
  MyButton(this.text);
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(5),
      child: RaisedButton(
        color: Colors.purple,
        textColor: Colors.white,
        child: Text(text),
        onPressed: () {},
      ),
    );
  }
}

class MyChip extends StatelessWidget {
  final String name;
  MyChip(this.name);
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 5),
      child: Chip(
        backgroundColor: Colors.lightGreenAccent,
        label: Text(name),
      ),
    );
  }
}

Комментарии