Flutter에서 사용자 입력을 어떻게 처리하나요?

질문

Flutter에서 사용자 입력을 어떻게 처리하나요?

답변

Flutter에서는 사용자 입력을 처리하기 위한 다양한 위젯과 기법을 제공합니다. 사용자 입력은 텍스트 입력, 제스처, 터치 이벤트 등 여러 형태로 발생할 수 있으며, 각 입력 유형에 맞는 적절한 처리 방법이 있습니다.

1. 텍스트 입력 처리

TextField 및 TextFormField 위젯

텍스트 입력을 위한 가장 기본적인 위젯은 TextFieldTextFormField입니다.

TextField 기본 사용법
TextField(
  decoration: InputDecoration(
    labelText: '이름',
    hintText: '이름을 입력하세요',
    border: OutlineInputBorder(),
  ),
  onChanged: (value) {
    // 텍스트가 변경될 때마다 호출
    print('입력된 텍스트: $value');
  },
  onSubmitted: (value) {
    // 제출(Enter 키)할 때 호출
    print('제출된 텍스트: $value');
  },
)
TextEditingController 사용

텍스트 입력에 대한 더 세밀한 제어를 위해 TextEditingController를 사용합니다:

class _MyFormState extends State<MyForm> {
  final TextEditingController _controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    // 초기값 설정
    _controller.text = '초기 텍스트';

    // 컨트롤러를 통한 변경 감지
    _controller.addListener(() {
      print('현재 텍스트: ${_controller.text}');
    });
  }

  @override
  void dispose() {
    // 컨트롤러 해제
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      decoration: InputDecoration(labelText: '이름'),
    );
  }
}
TextFormField를 이용한 유효성 검사

TextFormFieldTextField를 확장하여 폼 유효성 검사 기능을 추가합니다:

Form(
  key: _formKey,
  child: TextFormField(
    decoration: InputDecoration(labelText: '이메일'),
    validator: (value) {
      if (value == null || value.isEmpty) {
        return '이메일을 입력해주세요';
      }
      if (!value.contains('@')) {
        return '유효한 이메일 주소를 입력해주세요';
      }
      return null; // 유효성 검사 통과
    },
    onSaved: (value) {
      _email = value;
    },
  ),
)

다양한 키보드 유형 설정

입력 유형에 따라 적절한 키보드를 표시하려면 keyboardType 속성을 사용합니다:

TextField(
  keyboardType: TextInputType.emailAddress,
  decoration: InputDecoration(labelText: '이메일'),
)

TextField(
  keyboardType: TextInputType.number,
  decoration: InputDecoration(labelText: '나이'),
)

TextField(
  keyboardType: TextInputType.phone,
  decoration: InputDecoration(labelText: '전화번호'),
)

2. 버튼 처리

Flutter에서는 여러 종류의 버튼 위젯이 제공됩니다.

ElevatedButton

가장 기본적인 버튼 유형입니다:

ElevatedButton(
  onPressed: () {
    // 버튼 클릭 시 실행할 코드
    print('버튼이 클릭되었습니다!');
  },
  child: Text('클릭하세요'),
)

TextButton

텍스트만 있는 평면 버튼입니다:

TextButton(
  onPressed: () {
    print('텍스트 버튼 클릭');
  },
  child: Text('취소'),
)

IconButton

아이콘 형태의 버튼입니다:

IconButton(
  icon: Icon(Icons.favorite),
  onPressed: () {
    print('좋아요 버튼 클릭');
  },
)

비활성화 상태 처리

버튼을 비활성화하려면 onPressednull을 할당합니다:

ElevatedButton(
  onPressed: _isEnabled ? () {
    print('버튼 클릭');
  } : null, // null이면 버튼이 비활성화됨
  child: Text('제출'),
)

3. 제스처 감지

GestureDetector

다양한 제스처 이벤트를 감지할 수 있는 위젯입니다:

GestureDetector(
  onTap: () {
    print('한 번 탭했습니다');
  },
  onDoubleTap: () {
    print('두 번 탭했습니다');
  },
  onLongPress: () {
    print('길게 눌렀습니다');
  },
  onPanUpdate: (details) {
    print('드래그: ${details.delta.dx}, ${details.delta.dy}');
  },
  child: Container(
    width: 200,
    height: 200,
    color: Colors.blue,
    child: Center(child: Text('여기를 터치하세요')),
  ),
)

InkWell

Material Design 스타일의 물결 효과(ripple effect)가 있는 터치 감지 위젯입니다:

InkWell(
  onTap: () {
    print('탭 감지됨');
  },
  splashColor: Colors.red,
  child: Container(
    padding: EdgeInsets.all(12.0),
    child: Text('터치하세요'),
  ),
)

4. 드래그 & 드롭

Draggable과 DragTarget

드래그 앤 드롭 기능을 구현하려면 DraggableDragTarget 위젯을 사용합니다:

// 드래그 가능한 항목
Draggable<String>(
  data: 'dragged-item',
  child: Container(
    height: 100.0,
    width: 100.0,
    color: Colors.blue,
    child: Center(child: Text('드래그 미')),
  ),
  feedback: Container(
    height: 100.0,
    width: 100.0,
    color: Colors.blue.withOpacity(0.5),
    child: Center(child: Text('드래그 중')),
  ),
  childWhenDragging: Container(
    height: 100.0,
    width: 100.0,
    color: Colors.grey,
  ),
)

// 드롭 대상
DragTarget<String>(
  builder: (context, candidateData, rejectedData) {
    return Container(
      height: 100.0,
      width: 100.0,
      color: candidateData.isNotEmpty ? Colors.green : Colors.red,
      child: Center(child: Text('여기에 드롭')),
    );
  },
  onAccept: (data) {
    print('$data가 드롭되었습니다');
  },
)

5. 스크롤 이벤트 처리

스크롤 이벤트를 감지하고 처리하려면 ScrollController를 사용합니다:

class _MyScrollViewState extends State<MyScrollView> {
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_scrollListener);
  }

  void _scrollListener() {
    if (_scrollController.offset >= _scrollController.position.maxScrollExtent &&
        !_scrollController.position.outOfRange) {
      print("스크롤이 맨 아래에 도달했습니다");
      // 여기서 추가 데이터 로드 등의 작업 수행
    }
    if (_scrollController.offset <= _scrollController.position.minScrollExtent &&
        !_scrollController.position.outOfRange) {
      print("스크롤이 맨 위에 도달했습니다");
    }
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      controller: _scrollController,
      itemCount: 50,
      itemBuilder: (context, index) {
        return ListTile(title: Text('항목 $index'));
      },
    );
  }
}

6. Focus 관리

TextField 간 포커스 이동을 제어하려면 FocusNodeFocusScope를 사용합니다:

class _MyFormState extends State<MyForm> {
  final FocusNode _emailFocus = FocusNode();
  final FocusNode _passwordFocus = FocusNode();

  @override
  void dispose() {
    _emailFocus.dispose();
    _passwordFocus.dispose();
    super.dispose();
  }

  void _nextField() {
    // 이메일 필드에서 비밀번호 필드로 포커스 이동
    FocusScope.of(context).requestFocus(_passwordFocus);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          focusNode: _emailFocus,
          decoration: InputDecoration(labelText: '이메일'),
          textInputAction: TextInputAction.next,
          onSubmitted: (_) => _nextField(),
        ),
        TextField(
          focusNode: _passwordFocus,
          decoration: InputDecoration(labelText: '비밀번호'),
          obscureText: true,
          textInputAction: TextInputAction.done,
          onSubmitted: (_) {
            // 로그인 처리 등
            print('폼 제출');
          },
        ),
      ],
    );
  }
}

7. 폼 제출 처리

전체 폼을 관리하려면 Form 위젯과 GlobalKey를 사용합니다:

class _LoginFormState extends State<LoginForm> {
  final _formKey = GlobalKey<FormState>();
  String _email = '';
  String _password = '';

  void _submit() {
    if (_formKey.currentState!.validate()) {
      _formKey.currentState!.save();
      // 폼 데이터로 로그인 처리
      print('로그인: 이메일=$_email, 비밀번호=$_password');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            decoration: InputDecoration(labelText: '이메일'),
            validator: (value) {
              if (value == null || value.isEmpty || !value.contains('@')) {
                return '유효한 이메일을 입력하세요';
              }
              return null;
            },
            onSaved: (value) => _email = value!,
          ),
          TextFormField(
            decoration: InputDecoration(labelText: '비밀번호'),
            obscureText: true,
            validator: (value) {
              if (value == null || value.length < 6) {
                return '비밀번호는 6자 이상이어야 합니다';
              }
              return null;
            },
            onSaved: (value) => _password = value!,
          ),
          ElevatedButton(
            onPressed: _submit,
            child: Text('로그인'),
          ),
        ],
      ),
    );
  }
}

요약

Flutter에서 사용자 입력 처리는 다음과 같은 다양한 방법을 통해 이루어집니다:

  1. 텍스트 입력: TextField, TextFormField, TextEditingController
  2. 버튼 입력: ElevatedButton, TextButton, IconButton
  3. 제스처 처리: GestureDetector, InkWell
  4. 드래그 앤 드롭: Draggable, DragTarget
  5. 스크롤 이벤트: ScrollController
  6. 포커스 관리: FocusNode, FocusScope
  7. 폼 관리: Form, GlobalKey<FormState>

이러한 다양한 입력 처리 방법을 적절히 조합하여 사용하면 직관적이고 반응성이 뛰어난 사용자 인터페이스를 구축할 수 있습니다.

results matching ""

    No results matching ""