[목표]
이런 파동 ? 파장 웨이브를 구현 해보려고 한다
[패키지]
너무 고맙게도 누가 미리 구현 해줘서 그대로 쓰면 되지만 사실 내가 원하는 느낌과는 사뭇 다른 느낌인거 아시자나여
[커스텀]
패키지 써보면 알겠지만 조금 요란한 웨이브라 살짝 커스텀해서 써보았습니다.
import 'package:flutter/material.dart';
import 'dart:math' as math show sin, pi;
class RippleWave extends StatefulWidget {
const RippleWave({
Key? key,
this.color = Colors.teal,
this.duration = const Duration(milliseconds: 1500),
this.repeat = true,
required this.child,
this.childTween,
this.animationController,
this.waveCount = 3,
}) : super(key: key);
final Color color; // 웨이브 색상
final Widget child; // 웨이브 위에 위치할 자식 위젯
final Tween<double>? childTween; // 자식 위젯의 애니메이션 효과
final Duration duration; // 애니메이션 지속 시간
final bool repeat; // 애니메이션 반복 여부
final AnimationController? animationController; // 애니메이션 컨트롤러
final int waveCount; // 웨이브의 개수
@override
RippleWaveState createState() => RippleWaveState();
}
class RippleWaveState extends State<RippleWave> with TickerProviderStateMixin {
late AnimationController _controller; // 애니메이션 컨트롤러 변수
@override
void initState() {
super.initState();
_controller = widget.animationController ??
AnimationController(
duration: widget.duration,
vsync: this,
);
if (widget.repeat) {
_controller.repeat();
} else if (widget.animationController == null) {
_controller.forward();
Future.delayed(widget.duration).then((value) => _controller.stop());
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: _RipplePainter(
_controller,
widget.waveCount,
color: widget.color,
),
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(100),
child: DecoratedBox(
decoration: BoxDecoration(
gradient: RadialGradient(
colors: <Color>[
widget.color,
Colors.transparent,
],
),
),
child: ScaleTransition(
scale: widget.childTween != null
? widget.childTween!.animate(
CurvedAnimation(
parent: _controller,
curve: _CurveWave(),
),
)
: Tween(begin: 0.9, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve: _CurveWave(),
),
),
child: widget.child,
),
),
),
),
);
}
}
class _CurveWave extends Curve {
@override
double transform(double t) {
if (t == 0 || t == 1) {
return t; // t가 0 또는 1일 때는 그대로 반환
}
return math.sin(t * math.pi); // 사인 곡선으로 애니메이션 곡선 생성
}
}
class _RipplePainter extends CustomPainter {
_RipplePainter(
this.animation,
this.waveCount, {
required this.color,
}) : super(repaint: animation); // 애니메이션 값 변경 시 다시 그리기
final Color color;
final Animation<double> animation;
final int waveCount;
void circle(Canvas canvas, Rect rect, double value) {
final double maxRadius = 167 / 2; // 최대 반지름설정, maxRadius는 최대 반지름의 절반
final double normalizedValue = value / (waveCount + 1); // 값 정규화
final double scaleFactor = 1.0; // 반지름 축소 비율 (기본값은 1.0)
final double radius =
maxRadius * normalizedValue * scaleFactor; // 축소된 반지름 계산
final double opacity = (1.0 - normalizedValue)
.clamp(0.0, 1.0);
final Color newColor = color.withOpacity(opacity);
final Paint paint = Paint()..color = newColor;
canvas.drawCircle(
rect.center, // 원의 중심
radius, // 원의 반지름
paint, // 페인트
);
}
@override
void paint(Canvas canvas, Size size) {
final Rect rect = Rect.fromLTRB(
0.0,
0.0,
size.width,
size.height,
); // 전체 영역 설정
for (int wave = 0; wave <= waveCount; wave++) {
circle(canvas, rect, wave + animation.value); // 각 웨이브를 그리기
}
}
@override
bool shouldRepaint(_RipplePainter oldDelegate) => true;
}
[사용]
사용은 이렇게 하면 됩니다!
RippleWave(
childTween: Tween(begin: 0.9, end: 1.0),
color: Color(0xff373430),
repeat: true,
waveCount: 3,
animationController: AnimationController(
vsync: TestVSync(),
duration: Duration(seconds: 1),
),
child: Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: Colors.black,
borderRadius:
BorderRadius.all(Radius.circular(50)),
),
child: Image.asset(
'assets/images/mic.png',
width: 32,
height: 32,
),
),
)
'Flutter' 카테고리의 다른 글
Flutter API 통신을 간편하게 해주는 dio 라이브러리 (0) | 2024.09.20 |
---|---|
ModalBarrier 활용하기 (0) | 2024.09.02 |
Flutter 모달창이 끝난 후 함수 실행하기 (0) | 2024.08.21 |
Flutter 깜박임 없이 서서히 페이지 이동하기 (0) | 2024.08.12 |
Flutter 현재 위치 불러오기 (0) | 2024.08.06 |