2024. 6. 12. 15:59ㆍIT/Flutter
사내에서 인스타 라이브의 좋아요 인터렉션을 응용하면 구현이 가능할만한 인터렉션 요소를 개발해달라는 요구가 들어와서 한번 공유해보고자 한다.
먼저 맨 아래의 [인스타 라이브의 좋아요 인터렉션] 블로그 글을 참고하면 이해하는데 더욱 도움이 될 것 같다.
구현 프로세스
1. 아이콘 터치
2. 터치 위치에 인터렉션 요소를 가진 아이템 추가
3. 애니메이션 종료
4. 아이템 삭제
* 터치 및 해당 위치에 인터렉션 요소를 가진 아이템 추가
터치 위치값을 알기 위해선 GestureDetector 의 onTapDown 콜백 메서드를 활용할 수 있다.
localPostion 과 globalPosition 을 가져올 수 있는데,
globalPostion - 전체 스크린 영역에서 절대위치 값
localPosition - 탭 한 위젯 내에서의 상대적인 위치 값
정도로 이해할 수 있다.
어떤 position 을 사용해서 구현해도 무방하지만 나는 커다란 코인버튼 영역 내에서 생성되기를 원했기 때문에 localPosition을 이용하여 구현하였다.
onTapDown: (details) {
final localPosition = details.localPosition;
addTouchInteractionIcon(localPosition);
widget.onTap.call();
setState(() {});
},
void addTouchInteractionIcon(Offset tapPosition) {
touchInteractionIcons = [
...touchInteractionIcons,
_TouchInteractionIcon(
key: UniqueKey(),
tapPosition: tapPosition,
onAnimationEnd: () {
_removeTouchInteractionIcon(touchInteractionIcons);
},
)
];
}
이렇게 position 값을 얻어왔다면 해당 위치에 인터렉션 아이콘을 삽입해준다.
여기서 주의할 점은 Flutter 프레임워크가 새로 추가된 인터렉션 아이템의 renderobject 를 재사용하게 하면 안된다는 것이다.
해당 인터렉션 아이템은 생성되는 즉시 TransForm 위젯을 이용하여 위치를 이동하고 transition, opacity, scale 등의 애니메이션을 animationController 을 통해 수행하게 되는데, 재사용을 하게되면 원치않는 인터렉션이 생길수가있다.
Flutter 프레임워크에서 트리내의 위젯의 재사용을 결정하는 방식은 크게 두가지가 있는데,
먼저 key 가 주어지지 않은 경우 해당 위치의 위젯의 Type 을 이용하여 비교한다.
만약 key가 주어진다면 type과 함께 key를 이용하여 비교한다.
따라서 Type 은 같을 수 밖에 없으므로 프레임워크 내부적으로 중복되지않는 키값을 생성해주는 UniqueKey() 메서드를 이용하여 key를 넘겨주게 되면 위와같은 현상을 방지할 수 있다.
* 인터렉션 아이템
class _TouchInteractionIcon extends HookWidget {
const _TouchInteractionIcon({required this.tapPosition, required this.onAnimationEnd, super.key});
final VoidCallback onAnimationEnd;
final Offset tapPosition;
@override
Widget build(BuildContext context) {
final animationController = useAnimationController(
duration: const Duration(milliseconds: 1000),
);
final initialRotationAngle = useState(_getRotationAngle());
final initialScale = useState(_getInitialScale());
final initialXPosition = useState(tapPosition.dx + Random().nextInt(20) - 58.w);
useEffect(() {
Future.microtask(() {
animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
onAnimationEnd.call();
}
});
animationController.forward();
});
() => null;
}, []);
return AnimatedBuilder(
animation: animationController,
builder: (context, child) {
return Opacity(
opacity: _getOpacity(animationController.value),
child: Transform(
transform: Matrix4.translationValues(
...)
인터렉션 아이템 내부에서는 생성과 동시에 초기 위치, 스케일 등의 인터렉션에 필요한 요소들을 초기화해주고, 애니메이션을 실행하며 Transform 으로 위치를 이동시키고 있다.
이에 더하여 원하는 애니메이션 요소들을 추가해주면 더욱 더 멋진 인터렉션을 만들 수 있을것이다.
* 참고
'IT > Flutter' 카테고리의 다른 글
Flutter 에서 Element 와 RenderObject 를 재사용하는 방법 (0) | 2024.02.24 |
---|---|
[Flutter] Vertical scroll tabbar 을 만들어보자 (0) | 2023.06.05 |
[Flutter] Expandable bottom sheet dialog 를 직접 만들어보자 (0) | 2023.06.01 |
[Flutter] ios 빌드 시 Module "** *" not found 에러를 만날때 (0) | 2023.05.15 |
[Flutter] RxDart 공식문서 보기 - 1 (0) | 2023.01.03 |