Хотите создать настраиваемый пользовательский интерфейс с потрясающей анимацией? Не бойтесь, Flutter CustomPaint Widget поможет вам
В этой статье мы рассмотрим как явную анимацию, так и то, как работать с виджетом CustomPaint
во флаттере.
Вы можете ознакомиться с образцом кода в моем GitHub Repository.
Пользовательская краска: виджет, предоставляющий холст для рисования на этапе рисования.
Просто добавьте виджет CustomPaint
в дерево виджетов и предоставьте ему painter
, который является подклассом абстрактного класса CustomPainter
.
Поскольку CustomPainter
является абстрактным классом, это заставляет нас реализовать два важных метода, то есть paint()
и shouldRepaint()
. size
задает размер нарисованного виджета. Запачкаем руки:
Метод paint()
предоставляет нам два важных параметра:
Canvas
: Холст — это область экрана, где мы рисуем наш виджет. Он имеет различные методы рисования пользовательского виджета. Вот некоторые из них:canvas.drawLine()
,canvas.drawCircle()
,canvas.drawArc()
,canvas.drawOval()
и т. д.Size
: Насколько большим должен быть рисунок. По умолчанию он принимает размер виджета-оболочки, то есть виджета, обертывающего наш виджетCustomPaint
. Кроме того, мы можем предоставить параметры размера внутри нашего виджетаCustomPaint
. Поскольку мы хотим нарисовать круг, мы передали одно и то же значение ширины и высоты.
Метод shouldRepaint()
вызывается всякий раз, когда нужно перестроить CustomPainter
. Это станет ясно, когда мы реализуем наш проект.
Теперь, когда мы разобрались с классом CustomPainter
, давайте нарисуем что-нибудь на холсте. Наша цель — нарисовать круг с некоторой шириной штриха.
Давайте посмотрим, как мы это делаем:
Поскольку мы хотим нарисовать круг, мы использовали предварительно созданный метод canvas.drawCircle() the
, который ожидает три параметра, то есть центр круга, радиус круга и объект рисования. Мы рассчитали центр и радиус круга по size
параметру. Класс Paint()
предоставляет нам различные свойства, такие как цвет paint
, storkeWidth
, style
краски, т. е. должен ли он быть обведен или заполнен. Текущая реализация приведет к следующему:
Наша следующая цель — нарисовать дугу над тем же кругом, который будет анимироваться вокруг обводки. Для этого:
Поскольку мы хотим нарисовать дугу, мы использовали метод canvas.drawArc()
, который ожидает пять параметров, то есть Rect object
, startAngle
в радианах, sweepAngle
в radian
, useCenter
логическое значение и объект рисования.
Кроме того, мы хотим нарисовать дугу вокруг круга, поэтому мы использовали Rect.fromCircle()
метод в качестве первого параметра. Второй параметр — это начальный угол, который мы применили к -pi/2, так как мы хотим, чтобы угол начинался с вершины круга.
Угол развертки указывает, где должна заканчиваться дуга, и мы применили 40% от общего угла, т.е. наша дуга будет рисовать от -pi/2 до 40% от общих 360 радиан.
Если useCenter
boolean равно true, дуга замыкается обратно к центру, образуя круговой сектор. В противном случае дуга не замыкается, образуя сегмент окружности. И последний аргумент — это наш объект рисования, с которым мы уже знакомы.
Текущая реализация с useCenter
, установленным в true, приведет к следующему:
Но нам не нужен этот круговой сектор, поэтому установка для него значения false приведет к следующему:
Вы можете настроить startAngle
, endAngle
, чтобы увидеть различные эффекты.
Теперь мы почти приблизились к тому, чего хотим достичь. Осталась только анимация прогресса. Чтобы сделать это, мы должны использовать явную анимацию, то есть мы должны создать AnimationController
и передать его значение классу RingPainter
:
Различные вещи, которые мы сделали сейчас:
- Преобразовали наш виджет
RingPainter
StatelessWidget
в виджет с отслеживанием состояния, чтобы перестраивать пользовательский интерфейс всякий раз, когда изменяется значение анимации. - Создал
AnimationController
_controller, смешав наш класс_RingPainterState
сSingleTickerProviderStateMixin
и инициализировав его в методеinitState()
. - Начал анимацию с
_controller.forward()
- Добавлен слушатель к контроллеру, и вызывается
setState((){})
, так что весь наш пользовательский интерфейс перестраивается всякий раз, когда значение нашего_controller
изменяется. - Теперь наш класс
MyPainter
ожидает три обязательных аргумента:progress
,defaultColor
обводки круга и цвета заливки. Это сделано для того, чтобы передавать различные значения из-за пределов этого класса и сделать этот компонент многоразовым. Обратите внимание, что методshouldRepaint()
обновлен таким образом, что нашCircle
следует рисовать только тогда, когда значение прогресса отличается от предыдущего значения. - Наконец, передал эти три аргумента классу
MyPainter
со значением прогресса, являющимся текущим значением анимации.
С текущей реализацией нам удалось добиться этого:
Ура, мы почти до конца! Осталось только добавить значок в середине круга и изменить его цвет в зависимости от того, завершена анимация или нет.
Чтобы добиться этого, обновите метод сборки следующим образом:
Следующая реализация приведет к этому:
Так что теперь успешно добились желаемого.
Надеюсь, вы узнали что-то о виджете CustomPaint
. Теперь вы можете исследовать самостоятельно, чтобы добиться различных других эффектов.
Спасибо за прочтение.