유튜브 제임쓰님의 최근 영상에 플러터가 제공하는 위젯 없이 랜더 오브젝트를 활용하여 드랍다운을 구현한 예제가 있어 내부적으로 어떻게 돌아가는지 분석해 보았다.
NavigatorState navigator = Navigator.of(context);
final RenderBox itemBox = context.findRenderObject()! as RenderBox;
final Rect itemRect = itemBox.localToGlobal(
Offset.zero, ancestor: navigator.context.findRenderObject()) & itemBox.size;
await navigator.push(
// MaterialPageRouter 대신 사용
PageRouteBuilder(
barrierDismissible: true,
opaque: false,
pageBuilder: (context, anim1, anim2) => Container(
child: DefaultTextStyle(
style: TextStyle(color: Colors.black),
// Stack 사용
child: Stack(
children: [
Positioned(
// 부모위젯의 위치에 부모위젯의 크기만큼을 더해 포지셔닝
top: itemRect.top+itemBox.size.height,
// 아래로 내려갈거니까 부모위젯의 위치만큼 좌측에 띄워 포지셔닝
left: itemRect.left,
width: itemBox.size.width,
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
border: Border.all(color: Colors.black)
),
child: this.widget.scrollCheck
? Container(
height: this.widget.itemHeight,
child: ListView(
padding: EdgeInsets.zero,
children: this.widget.items.map<Widget>(
(String e) => GestureDetector(
onTap: () => this.widget.onTap(e),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.black)
),
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0),
margin: EdgeInsets.all(10.0),
child: Text(e)
),
)
).toList(),
),
)
: Column(
children: this.widget.items.map<Widget>(
(String e) => GestureDetector(
onTap: () => this.widget.onTap(e),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.black)
),
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0),
margin: EdgeInsets.all(10.0),
child: Text(e)
),
)
).toList(),
),
),
)
],
🤩 👍