[Project] 2차 프로젝트 - Floating버튼 만들기

김호정's avatar
Oct 25, 2024
[Project] 2차 프로젝트 - Floating버튼 만들기

버튼 통합

위에 Dialog창 만들고 반납, 연장 버튼으로 다이얼로그창을 연결했는데
대여중 화면의 경우 책의 정보, 연장, 반납 이렇게 3가지 버튼이 필요하다.
 
조그만 폰 화면인데 책 1권당 버튼 3개는 보기에도 좋지 않다.
그래서 플로팅 버튼을 만들어서 거기에 다 넣는 쪽으로 하는 것이 괜찮을 것 같다.
 
 

Floating 버튼

 
FloatingActionButton을 사용해서 이 버튼을 눌렀을 때 showModalBottomSheet 을 통해 화면 하단부에서 창이 뜨게 할 것이다. 한 줄 한 줄 요소는 customFloatingButton을 호출해서 actions: [ ] 내부에 ListTile 을 넣어주면 된다.
Floating 버튼 커스텀을 위해서 SizedBox에 감싸서 너비, 높이, 배경색, 투명도, 테두리설정, 아이콘설정을
넣어줬고 ListTile을 담은 actions를 제외하고는 값을 보내지 않으면 기본값들이 적용된다.
 
참고로 하단에 뜨는 showModalBottomSheet를 닫기 위해서는 창 바깥쪽을 터치하거나
Navigator.pop(context); 를 통해 닫아준다.
 
아래는 코드 전문이다.
 
notion image
 
 
ui/_components/custom_floating_btn.dart
import 'package:flutter/material.dart'; class CustomFloatingButton extends StatelessWidget { final List<ListTile> actions; final double width; final double height; final Color backgroundColor; final double opacity; // 투명도 설정 -> 기본 0.3 final double borderRadius; // 모서리 둥글기 추가 final Widget icon; // 아이콘을 커스터마이징할 수 있도록 필드 추가 CustomFloatingButton({ required this.actions, this.width = 30.0, this.height = 30.0, this.backgroundColor = const Color(0xFF7AB6FA), this.opacity = 0.3, this.borderRadius = 8.0, // 기본값으로 약간 둥글게 설정 this.icon = const Icon(Icons.more_vert), // 기본 아이콘 설정 }); @override Widget build(BuildContext context) { return SizedBox( width: width, height: height, child: FloatingActionButton( onPressed: () { showModalBottomSheet( useSafeArea: true, // 안전 영역을 고려 context: context, builder: (context) { return Wrap( children: actions, ); }, ); }, backgroundColor: backgroundColor.withOpacity(opacity), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(borderRadius), // 모서리 반경 설정 ), child: Icon(Icons.more_vert), ), ); } }

Floating 버튼의 위치 설정

Floating 버튼은 부모에게 부착된다.
예를들어 어떤 Column이 있는데(사진 + 글 등) 이 컬럼의 특정 위치에 Floating 버튼을 부착하고 싶다면
Column 밖에 Floating 버튼을 배치해야된다. (안 그러면 Column의 크기에 따라 위치가 동적으로 변하기 때문)
 
이때 Floating은 부모에게 부착되므로 Column과 Floating을 Stack 위젯으로 감싼다.
Stack 안에 있는 모든 자식 위젯들은 서로 겹칠 수 있기 때문에 이를 이용해서 Floating버튼을
Column의 어딘가에 겹쳐서 붙일 것인데 그러려면 위치 조정이 필수적일 것이다.
 
Floating 버튼이 Stack위젯 내부에서 위치변경을 하려면 Positioned 위젯으로 감싸준다.
positioned으로 top 혹은 bottom // left 혹은 right 옵션으로 부모를 기준으로 배치할 위치를 설정해주면 된다.
그러면 Stack 내부에서 자유로이 위치 변경을 할 수 있다.
 
즉 Stack이 Column과 Floating 버튼을 감싸면 이 둘은 겹칠 수 있게 되는데
이 내부에서 Floating버튼의 위치를 조절하고 싶다면 Floating버튼을 Positioned로 감싸서 조정해주면 된다.
Floating버튼이 부모인 Positioned에 달라붙고 Positioned도 부모인 Stack내부에서 위치조정을 통해
Column 과 겹쳐져서 Column위에서 원하는 곳으로 이동할 수 있게 되는 것이다.
 
그림을 그려보자면
notion image
 
이런식으로 Stack 내부에 주요 컨텐츠는 Column이고 여기에 floating 버튼을 positioned로 감싸서
부모인 Stack 내부에서 Stack내부에 함께 존재하는 Column과 겹쳐져서 위치조정이 가능하다.
 
예시 코드
Stack( children: [ Column( children: [ // Column 내부의 위젯들 ], ), Positioned( bottom: 16.0, // 화면 하단에 배치 right: 16.0, // 화면 오른쪽에 배치 child: FloatingActionButton( onPressed: () { // 버튼 동작 }, child: Icon(Icons.add), ), ), ], )
 
 
커스텀 플로팅 버튼 예시코드
Stack( children: [ InkWell( onTap: () { print('책 클릭 $index'); }, child: Column(children: [ CustomCardItem( imageUrl: "https://picsum.photos/id/${index + 10}/200/280", // 이미지 URL title: "책 제목\n2줄일 때", // 책 제 ), Text( '기한: 24-10-20', style: TextStyle(fontSize: 12), ), ]), ), Positioned( right: -5, top: 0, child: CustomFloatingButton( actions: [ ListTile(title: Text('책 이름 $index')), _bookInfo(context), _lendExtend(context, index), _lendReturn(context, index), ], ), ), ], );
책 사진과 제목 등의 정보를 Column 내부에 넣었고 이를 InkWell로 버튼을 만든 상태이다.
이 Column과 Positioned로 감싼 커스텀 플로팅 버튼을 Stack으로 묶었다.
커스텀 플로팅 버튼은 내부에 ListTile을 리스트로 받으므로 여러 개를 넣을 수 있고
여기에 ListTile을 4개 넣어서 플로팅 버튼을 누르면 각각의 ListTile이 출력되고
또한 각각의 ListTile마다 개별적인 Text 설정 이름과(책이름, 정보, 반납, 대여 등) 각각에 대한 익명함수가 설정이 돼있기 때문에 여러가지 로직을 실행시킬 수 있다.
 
notion image
 
Share article

keepgoing