위와 같은 UI를 만들어야 하게 되었다.
StackOverflow 검색해보면 Stack 안에 Positioned를 써서 만드는 방법이 나오는데, 대략 다음과 같다.
Widget getModalBottomSheet(context, Article event) {
return Stack(
clipBehavior: Clip.none,
alignment: Alignment.topCenter,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color(0xff888888),
blurRadius: 8.0,
spreadRadius: 2.0,
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 42.0),
Padding(
padding: EdgeInsets.symmetric(horizontal: 41.5),
child: Text('테스트 이벤트'),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 41.5),
child: Text('이것은 테스트 이벤트 입니다. 신나죠?'),
),
// 하단 검은 줄은 코드 생략
//.........
],
),
),
// center X
Positioned(
top: -20,
child: Container(
width: 40,
height: 40,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(19.75),
),
child: GestureDetector(
onTap: () => Get.back(),
child: SvgPicture.asset(
ImageAssets.iconX,
color: Colors.white,
),
),
),
)
],
);
}
......
showModalBottomSheet(context: context, builder: (BuildContext context) {
return getModalBottomSheet(context);
});
중요한 부분은 showModalBottomSheet()의 builder 에 필요한 위젯을 Stack으로 만들어주는 것이고,
이 Stack의 clipBehavior 프로퍼티를 Clip.none 으로 설정하고, 버튼을 Positioned(top: -20) (버튼 높이의 1/2) 로 감싸주는 것이다.
이렇게 하면 모양은 원하는대로 나오지만, 약간 문제가 있는데, X 버튼의 하단(Stack에 포함되어 있는 부분)을 터치하면 제대로 동작하는데, Stack 범위에 포함되어 있지 않은 상단 반을 터치했을 때 이벤트가 발생하지 않는다.
이것은 아래와 같이 Stack 에는 top margin을 버튼 높이의 1/2만큼 준 Container와 버튼을 넣어주어서 해결한다.
Widget getModalBottomSheet(context, Article event) {
return Container(
alignment: Alignment.bottomCenter,
=
child: Stack(
alignment: Alignment.topCenter,
children: [
// top margin을 가진 Container
Container(
margin: EdgeInsets.only(top: 20),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color(0xff888888),
blurRadius: 8.0,
spreadRadius: 2.0,
),
],
),
width: MySizerUtil.screenWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 42.0),
Padding(
padding: EdgeInsets.symmetric(horizontal: 41.5),
child: Text('테스트 이벤트'),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 41.5),
child: Text('이것은 테스트 이벤트 입니다. 신나죠?'),
),
],
),
),
// Positioned를 제거해도 된다.
Container(
width: 39.5,
height: 39.5,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(19.75),
),
child: GestureDetector(
onTap: () => closeBottomNotice(event.id.toString()),
child: SvgPicture.asset(
ImageAssets.iconX,
color: Colors.white,
),
),
),
],
),
);
}
}
이렇게 하면 아래 그림처럼 상단에 흰 여백이 생기는데, showModalBottomSheet() 호출할 때 backgroundColor 파라미터를 주면 해결된다.
showModalBottomSheet(context: context,
backgroundColor: Colors.transparent, // 이게 중요하다.
builder: (BuildContext context) {
return getModalBottomSheet(context);
});