Итак, я пытаюсь добиться чего-то похожего на этот пример Flutter, представленный в документации.
Но я не хочу, чтобы он подчинялся кнопке, я хочу, чтобы он сам выполнял анимацию и делал это без остановок.
По крайней мере, мне нужен Tween для высоты, ширины и цвета, однако я нахожусь в запутанной ситуации с тем, как анимировать их все, я вроде как это сделал, но знаю, что мне не хватает свойства Animation в моем виджете. , это мой результат на данный момент:
Он совершает переходы между генерируемыми случайными значениями.
Это мой код:
class AnimatedSquare extends StatefulWidget {
const AnimatedSquare({super.key});
@override
State<AnimatedSquare> createState() => _AnimatedSquareState();
}
class _AnimatedSquareState extends State<AnimatedSquare>
with SingleTickerProviderStateMixin{
late final AnimationController controller;
late Tween<double> containerWidth;
late Tween<double> containerHeight;
late Tween<Color> containerColor;
Random random = Random();
@override
void initState() {
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 800)
)
..forward()
..addListener(() {
if (controller.isCompleted) {
setNewValues();
controller.forward();
}
});
containerWidth = Tween<double>(
begin: 250,
end: random.nextInt(300).toDouble()
);
containerHeight = Tween<double>(
begin: 250,
end: random.nextInt(300).toDouble()
);
containerColor = Tween(
begin: Colors.red,
end: Color.fromRGBO(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255),
1
)
);
super.initState();
}
void setNewValues() {
containerWidth.begin = containerWidth.end;
containerHeight.begin = containerHeight.end;
containerColor.begin = containerColor.end;
controller.reset();
containerWidth.end = random.nextInt(300).toDouble();
containerHeight.end = random.nextInt(300).toDouble();
containerColor.end = Color.fromRGBO(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255),
1
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Container(
height: containerHeight.begin,
width: containerWidth.begin,
decoration: BoxDecoration(
color: containerColor.begin
),
);
},
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
Может ли кто-нибудь помочь мне решить эту проблему? Я не смог найти много информации в Интернете, использовал этот вопрос в качестве последнего ресурса.
AnimatedContainer(
height: containerHeight.begin,
width: containerWidth.begin,
decoration: BoxDecoration(color: containerColor.begin),
duration: const Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
);
используйте это как возврат на AnimatedBuilder
Вам просто нужно использовать Animation
с Tween
для конкретного движения/действия.
Также вам нужно слушать addStatusListener
вместо прослушивателя анимации.
Это ваш код исправлен.
class _AnimatedSquareState extends State<AnimatedSquare>
with SingleTickerProviderStateMixin {
late final AnimationController controller;
late Animation<double> containerWidth;
late Animation<double> containerHeight;
late Animation<Color?> containerColor;
Random random = Random();
@override
void initState() {
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 800))
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
setNewValues();
controller.forward(from: 0);
}
})
..forward();
setNewValues();
super.initState();
}
void setNewValues() {
containerWidth =
Tween<double>(begin: 250, end: random.nextInt(300).toDouble()).animate(
controller,
);
containerHeight =
Tween<double>(begin: 250, end: random.nextInt(300).toDouble()).animate(
controller,
);
containerColor = ColorTween(
begin: Colors.red,
end: Color.fromRGBO(random.nextInt(255), random.nextInt(255),
random.nextInt(255), 1))
.animate(
controller,
);
}
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Container(
height: containerHeight.value,
width: containerWidth.value,
decoration: BoxDecoration(color: containerColor.value),
);
},
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
Метод setNewValues использовался для анимации от последних случайных значений к новым случайным значениям, без этого он получает странный скачок с самого начала. Как я могу получить свойства конца и начала, если переменные установлены как анимация? похоже, ты удалил эту часть
Неважно, я просто использовал часть вашего ответа, чтобы решить эту проблему, хотя это было полезно, спасибо!
Вы могли бы проголосовать за мой ответ, если бы он был полезен
По сути, я использовал часть ответа @diegoveloper, чтобы решить свою проблему. Я просто добавил переменную Animation для каждого Tween, так как мне нужно было получить свойства end и Begin в методе setNewValues().
Окончательный код:
class AnimatedSquare extends StatefulWidget {
const AnimatedSquare({super.key});
@override
State<AnimatedSquare> createState() => _AnimatedSquareState();
}
class _AnimatedSquareState extends State<AnimatedSquare>
with SingleTickerProviderStateMixin {
late final AnimationController controller;
late Tween<double> containerWidth;
late Tween<double> containerHeight;
late Tween<Color?> containerColor;
late Animation<double> animContainerWidth;
late Animation<double> animContainerHeight;
late Animation<Color?> animContainerColor;
Random random = Random();
@override
void initState() {
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 800)
)..addStatusListener((status) {
if (status == AnimationStatus.completed) {
setNewValues();
controller.forward(from: 0);
}
})..forward();
containerWidth = Tween<double>(
begin: 250,
end: random.nextInt(300).toDouble()
);
containerHeight = Tween<double>(
begin: 250,
end: random.nextInt(300).toDouble()
);
containerColor = ColorTween(
begin: Colors.red,
end: Color.fromRGBO(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255),
1
)
);
animContainerWidth = containerWidth.animate(CurvedAnimation(
parent: controller,
curve: Curves.fastOutSlowIn
));
animContainerHeight = containerHeight.animate(CurvedAnimation(
parent: controller,
curve: Curves.fastOutSlowIn
));
animContainerColor = containerColor.animate(CurvedAnimation(
parent: controller,
curve: Curves.fastOutSlowIn
));
super.initState();
}
void setNewValues() {
containerWidth.begin = containerWidth.end;
containerHeight.begin = containerHeight.end;
containerColor.begin = containerColor.end;
controller.reset();
containerWidth.end = random.nextInt(300).toDouble();
containerHeight.end = random.nextInt(300).toDouble();
containerColor.end = Color.fromRGBO(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255),
1
);
}
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Container(
height: animContainerHeight.value,
width: animContainerWidth.value,
decoration: BoxDecoration(
color: animContainerColor.value,
borderRadius: BorderRadius.circular(30)
),
);
},
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
Большое спасибо!
вместо этих
Tween
,AnimatedBuilder
,AnimationController
, слушателей и т. д., почему бы вам просто не использоватьAnimatedContainer
(сonEnd: ...
для повторения анимации)? подробнее здесь: api.flutter.dev/flutter/widgets/AnimatedContainer-class.html - в документации говорится: «Анимированная версия Container, которая постепенно меняет свои значения с течением времени. AnimatedContainer будет автоматически анимироваться между старыми и новые значения свойств, когда они изменяются с использованием предоставленной кривой и продолжительности. Свойства, имеющие значение null, не анимируются. Его дочерние элементы и потомки не анимируются.