> Frontend/Flutter

Flutter_11. App bar & Modal &Text Field (Input tag)

Janku 2023. 5. 4. 23:59

 

 

 

0. 배운 내용

   - App Bar (상단 바)

   - Modal 창

   - Text Field Widget (JS 의 input tag 와 비슷) 사용하여 input value 받기.

 

 

1. App Bar. (상단)

 

Flutter -  App bar 의 상단 / 중단 / 하단

 

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text("Flutter Expense Tracker"), // 제목
      actions: [
        IconButton(onPressed: () {
          return _openAddExpenseOverlay();
        }, icon: const Icon(Icons.add)),
      ], // actions: typically used to display buttons in top app bar's right hand side.
    ),
    
    .. 생략

 

 

  •     title은 AppBar의 중앙에 위치할 내용
  •    actions는 주로 icon 이 들어가며, AppBar의 오른쪽 부분에 들어간다. IconButton 이 클릭 되면 _openAddExpenseOverlay를 실행할 수 있도록, pointing 해준다. 
  •   _openAddExpenseOverlay의 ShowModalBottomSheet 은 사용자가 버튼을 클릭하면 뒤에 있는 내용을 가리며 나타나는 모달
void _openAddExpenseOverlay() {
  showModalBottomSheet(
      context: context, // context ,which is full of meta-data, holds information about expenses widget in the end and its position in the widget tree
      builder: (builderContext) { // builder basically means that you must provide a function as a value. (return a widget that should basically be displayed when Flutter renders this mbs is opening up)
        return const NewExpense();
      } //
  ); //
}

 

 

 

2. showModalBottomSheet

 

  • 필수로 필요한 2가지 속성 : 
  1.  context(BuildContext): 가져올 위젯을 결정하고 위젯 트리에서 가져올 위젯의 위치를 결정하는 데 도움을 줍니다.
  2.  builder(WidgetBuilder) : 위젯을 리턴

<- 이외에 왼쪽과 같은 속성을 가질 수 있음. 

 

 

 

 

 

 

 

 

 

 

3. 모달창에 들어갈 내용 (new_expense.dart)

 

import 'package:flutter/material.dart';

class NewExpense extends StatefulWidget {
  const NewExpense({Key? key}) : super(key: key);

  @override
  State<NewExpense> createState() => _NewExpenseState();
}

class _NewExpenseState extends State<NewExpense> {
  var _enteredTitle = '';

  void _saveTitleInput(String inputValue) {
    _enteredTitle = inputValue; // since there is no change in UI, no need to use setState.
  }

  final _titleController = TextEditingController(); // need to tell Flutter to delete when this modal is closed => otherwise, way of wasting memory.

  @override
  void dispose() {
    // dispose is a part of StatefulWidget lifecycle. called when widget is destroyed.
    _titleController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          TextField(
            // onChanged: _saveTitleInput, // first way of storing text value => onChanged
            controller: _titleController,
            // second way of storing text value => controller
            maxLength: 50,
            keyboardType: TextInputType.text,
            // input tag type in JS
            decoration: const InputDecoration(
                label: Text('Title')), // title of input (Text Field)
          ),
          Row(
            children: [
              ElevatedButton(
                  onPressed: () {
                    print(_titleController.text);
                  },
                  child: const Text('Save Expense'))
            ],
          )
        ],
      ),
    );
  }
}
  • Stateful widget으로 작성된 NewExpense는 ShowModalBottomSheet에서 보여짐.

 

4. TextField Widget (NewExpense)

 

TextField(
  // onChanged: _saveTitleInput, // first way of storing text value => onChanged
  controller: _titleController,
  // second way of storing text value => controller
  maxLength: 50,
  keyboardType: TextInputType.text,
  // input tag type in JS
  decoration: const InputDecoration(
      label: Text('Title')), // title of input (Text Field)
),

 

ㅇ



  • TextField는 JS의 Input tag 와 비슷하며, 유저가 작성가능한 widget을 의미
  • maxLength는 입력 가능한 최대값
  • keyboardType은 입력할 키보드의 종류 input tag의 type와 비슷)
  • decoration은 제목을 주거나 style을 주기위한 속성

 

 

 

 

 

 

 

 

 

  • 하단에 보이는 [Save Expense] 버튼을 누른 경우, 유저가 입력한 값을 받기 위해서는 두가지 방법이 있다. 
  1. onChanged
  2. Controller
  • onChanged
child: Column(
  children: [
    TextField(
      onChanged: _saveTitleInput, // first way of storing text value => onChanged
  • TextField 값이 변경 되었을 때, _saveTitleInput 을 실행
var _enteredTitle = '';

void _saveTitleInput(String inputValue) {
  _enteredTitle = inputValue; // since there is no change in UI, no need to use setState.
}
  • _saveTitleInput는 inputValue값을 받고, 해당 값을 _enteredTitle에 저장
children: [
  ElevatedButton(
      onPressed: () {
        print(_enteredTitle);
      },
  • 후에,  Save Expense 버튼을 누르면, 내용 노출 
  • Controller
controller: _titleController,
  • onChanged 대신에, 위와 같이 작성
final _titleController = TextEditingController(); // need to tell Flutter to delete when this modal is closed => otherwise, way of wasting memory.

@override
void dispose() {
  // dispose is a part of StatefulWidget lifecycle. called when widget is destroyed.
  _titleController.dispose();
  super.dispose();
}
  • TextEditingController : 편집이 가능한 TextField에 입력된 값을 가져오거나 / TextField에 입력된 값이 변경될때 사용 하는 클래스
  • 해당 클라스는 modal이 닫혀도 남아있기 때문에, dispose를 통해, unmounted 될때, 삭제. 
onPressed: () {
  print(_titleController.text);
},
  • onChanged와 동일하게, 버튼이 클릭되면, _titleController.text값을 가져오게 할 수 있다.