Roman Ismagilov 공부회. flutter tap effect native인척하기. 자연스러운 버튼!
https://medium.com/@pomis172/making-flutter-apps-look-more-native-part-1-tap-effects-48a59cb158bf
Making Flutter apps look more native. Part 1: tap effects
By default, if you are using InkWells to handle tap events in your UI, a ripple effect will be applied. The issue here is that while the…
medium.com
InkWells쓰면 리플효과가 있다. 리플 효과는 안드로이드 디자인에서는 필수적인 요소이지만, iOS에서는 다소 어색하게 보일 수 있다는 점이다.
대신 ios는 버튼을 탭할 때 리플 효과 대신 콘텐츠가 부드럽게 페이드 아웃(fade out)되는 효과가 더 일반적이다. 리플효과는 물결처럼 퍼지는것~
자 그럼 플러터에서 inkwell로 안드로이드 버튼효과를 줄수 있다.
IOS는? 다르게 적용되어야겠다.
함께 보자,
class TapArea extends StatefulWidget {
final Widget child;
final GestureTapCallback? onTap;
final GestureTapCallback? onLongTap;
final double borderRadius;
final EdgeInsets? padding;
const TapArea({
super.key,
required this.child,
required this.onTap,
this.onLongTap,
this.padding,
this.borderRadius = 0,
});
@override
State<TapArea> createState() => defaultTargetPlatform == TargetPlatform.iOS
? _TapAreaIosState()
: _TapAreaAndroidState();
}
이걸 보면 Inkwell대신 쓰일 TapArea라는위젯이 있다.
defaultTargetPlatform을 확인하여 플랫폼별로 다른 적용을 할 수 있다.
안드로이드 타겟 위젯
class _TapAreaAndroidState extends State<TapArea> {
@override
Widget build(BuildContext context) {
final content = Padding(
padding: widget.padding ?? EdgeInsets.zero,
child: widget.child,
);
if (widget.onTap == null && widget.onLongTap == null) return content;
return Material(
color: Colors.transparent,
clipBehavior: Clip.none,
borderRadius: BorderRadius.circular(widget.borderRadius),
child: InkWell(
borderRadius: BorderRadius.circular(widget.borderRadius),
onTap: widget.onTap,
onLongPress: widget.onLongTap,
child: content,
),
);
}
}
IOS타겟위젯은 Inkwell 대신 GestureDetector을 사용한다.
class _TapAreaIosState extends State<TapArea> {
bool _isDown = false;
@override
Widget build(BuildContext context) {
final content = Padding(
padding: widget.padding ?? EdgeInsets.zero,
child: widget.child,
);
if (widget.onTap == null && widget.onLongTap == null) return content;
return GestureDetector(
onTapDown: (_) {
setState(() {
_isDown = true;
});
},
onTapCancel: () {
setState(() {
_isDown = false;
});
},
onTap: () {
setState(() {
_isDown = false;
});
widget.onTap!();
},
onLongPress: widget.onLongTap,
child: Focus(
child: Opacity(
opacity: _isDown ? 0.7 : 1.0,
child: content,
),
),
);
}
}
둘다 터치시 이벤트로 다른 처리를 하는걸 볼 수 있다.
결론: 플러터는 크로스플랫폼이어서 범용적 코드작성이 필요한데 그런점에서 native UI에대한 이해를 가지고 커스텀 위젯을 만드는게 좋은것같다.
=> 내부적으로 플랫폼 타고 들어가서 안드로이드는 InkWell, IOS는 GestureDetector을 사용하도록 연결해주면 범용적인 커스텀 위젯이 된다.
활용예제 :
TapArea(
onTap: () {
print("버튼 클릭됨!");
},
borderRadius: BorderRadius.only( // 🎯 각 모서리 다르게 설정 가능!
topLeft: Radius.circular(20),
bottomRight: Radius.circular(10),
),
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.only( // 🎯 컨테이너도 동일한 radius 적용!
topLeft: Radius.circular(20),
bottomRight: Radius.circular(10),
),
),
child: Text(
"클릭하세요!",
style: TextStyle(color: Colors.white),
),
),
)