웹 페이지의 검색 입력 창을 클릭하면 아래와 같은 화면이 표출된다. 표출되는 걸 검색 바(이전 검색 창) 등 다양한 명칭으로 불려진다. 사용자 입장에서 이전 검색 목록을 표출하면 좋다. 이걸 Flutter로 구현할 일이 있어서 관련 자료를 찾았다.
조건은 아래와 같았다.
먼저 Flutter의 플러그인을 조회할 수 있는 pub.dev 에서 TextField와 관련된 플러그인 조회했다.
4가지가 검색이 됐다. 위의 플러그인은 모두 잘 만들어졌다. suggestion_textfield는 제대로 작동이 안되는 단점이 있다. 그래도 플러그인의 기능을 파악해서 커스텀하여 개발하면 사용할 수 있어서 플러그인을 설치 후 사용했다.
위의 플러그인은 TextField가 한 줄인 경우 표시가 잘 됐다. TextField가 한 줄이 아닌 TextField 속성 중 maxLines에 값을 지정해줘서 웹 페이지의 <textarea> 태그처럼 TextField의 height 조정이 쉽지 않았다. 플러그인의 구현된 로직을 정리하다가 Overlay 위젯이 자주 보였다.
Overlay라는 단어가 '위에 까는 것'이란 의미를 지녔기 때문에 이 이름으로 된 위젯이 Dialog 화면 처럼 작동되는 지 공식 문서를 찾았다.
Overlay 위젯을 사용하면 독립적인 하위 위젯을 오버레이의 Stack에 삽입하여 다른 위젯 위에 시각적 요소를 '부동'할 수 있다고 적혀 있었다.
import 'package:flutter/material.dart';
void main() => runApp(MyHome());
class MyHome extends StatelessWidget{
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(
width:1000,
height: 1000,
child: Column(
children: [
CountriesField(),
SizedBox(height: 16.0,),
TextFormField(
decoration: InputDecoration(
labelText: 'City'
),
),
SizedBox(height: 16.0,),
TextFormField(
decoration: InputDecoration(
labelText: 'Address'
),
),
SizedBox(height: 16.0,),
RaisedButton(
child: Text('SUBMIT'),
onPressed: () {
// submit the form
},
)
],
),
),
),
),
);
}
}
class CountriesField extends StatefulWidget {
@override
_CountriesFieldState createState() => _CountriesFieldState();
}
class _CountriesFieldState extends State<CountriesField> {
final FocusNode _focusNode = FocusNode();
OverlayEntry _overlayEntry;
@override
void initState() {
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
this._overlayEntry = this._createOverlayEntry();
Overlay.of(context).insert(this._overlayEntry);
} else {
this._overlayEntry.remove();
}
});
}
OverlayEntry _createOverlayEntry() {
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
var offset = renderBox.localToGlobal(Offset.zero);
return OverlayEntry(
builder: (context) => Positioned(
left: offset.dx,
top: offset.dy + size.height + 5.0,
width: size.width,
child: Material(
elevation: 4.0,
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: <Widget>[
ListTile(
title: Text('Syria'),
),
ListTile(
title: Text('Lebanon'),
)
],
),
),
)
);
}
@override
Widget build(BuildContext context) {
return TextFormField(
focusNode: this._focusNode,
decoration: InputDecoration(
labelText: 'Country'
),
);
}
}
1. OverlayEntry에 그리는 위젯 함수를 초기화 한다.
2. TextFormField에 초기화 된 _focusNode의 이벤트가 작동되면 오버레이할 함수를 그린다.
3. _focusNode.hasFocus 는 TextFormField 포커스가 (TextFormField 터치되었을 때) 잡혔을 때 값을 true로 뱉는다.
[Flutter] VlcPlayer 플러그인 상태 값 (0) | 2021.07.14 |
---|---|
[Flutter] VlcPlayer 무한 영상 재생 (0) | 2021.07.13 |
[Flutter] 탭 메뉴(Tab Menu) 만들기 (0) | 2021.06.24 |
[Flutter] ListView의 자동 스크롤 (0) | 2021.06.19 |
[JAVA] RSA 방식을 이용한 전자 서명 (0) | 2021.06.05 |
댓글 영역