Flutter

[Flutter] Callback 함수 - 자식 위젯 이벤트 처리

연화 2025. 1. 15. 18:05

Flutter에서 자식 위젯에서 발생한 이벤트를 부모 위젯이 처리하도록 만드는 방법은 여러 가지가 있습니다.
그중 하나는 콜백 함수를 사용하는 것입니다. 이번 포스팅에서는 콜백 함수를 통해 부모 위젯이 자식 위젯의 이벤트를 처리하는 방법을 단계별로 살펴보겠습니다.

 

1단계: 기본 구조 작성하기

우선, 부모 위젯과 자식 위젯의 기본 구조를 만듭니다. 자식 위젯에서 이벤트를 발생시키지만, 아직 부모 위젯과 연결되지는 않은 상태입니다.

class ParentsView extends StatefulWidget {
  const ParentsView({super.key});

  @override
  State<ParentsView> createState() => _ParentsViewState();
}

class _ParentsViewState extends State<ParentsView> {
  String displayText = '여기는 부모 위젯 변수야';

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Column(
          children: [
            Expanded(flex: 1, child: Center(child: Text(displayText))),
            Expanded(flex: 1, child: ChildA()),
            Expanded(flex: 1, child: ChildB()),
          ],
        ),
      ),
    );
  }
}

 

  • 부모 위젯의 displayText 변수는 텍스트를 표시합니다.
  • ChildA와 ChildB는 각각 이벤트를 발생시키는 자식 위젯입니다.
  • 아직 부모와 자식 간 상호작용이 없는 상태입니다.

 

2단계: 콜백 함수로 부모와 자식 연결하기

부모 위젯에 자식 이벤트를 처리할 콜백 메서드를 추가합니다.

void handleChildEvent() {
  setState(() {
    displayText = '어딘지는 모르겠지만 자식 위젯에서 이벤트 발생';
  });
}

 

부모에서 전달받은 콜백 함수를 호출하도록 구현합니다.

class ChildA extends StatelessWidget {
  final Function onCallbackReceived;

  const ChildA({required this.onCallbackReceived, super.key});

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        print('child a 에 이벤트 발생 ');
        onCallbackReceived(); // 콜백 함수 호출
      },
      child: Container(
        color: Colors.orange,
        child: Center(child: Text('CHILD A')),
      ),
    );
  }
}

 

3단계: 데이터 전달 기능 추가하기

마지막으로, 자식에서 데이터를 부모로 전달할 수 있도록 콜백 함수에 매개변수를 추가합니다.
부모위젯에 콜백 메서드가 데이터를 받을 수 있도록 매개변수를 추가합니다.

void handleChildEvent(String message) {
  setState(() {
    displayText = message; // 자식에서 받은 메시지를 표시
  });
}

자식 위젯에도 콜백 함수 호출 시 메시지를 전달하도록 수정합니다.

class ChildA extends StatelessWidget {
  final Function(String message) onCallbackReceived;

  const ChildA({required this.onCallbackReceived, super.key});

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        print('child a 에 이벤트 발생 ');
        onCallbackReceived('A가 연산한 데이터를 전달했음'); // 메시지 전달
      },
      child: Container(
        color: Colors.orange,
        child: Center(child: Text('CHILD A')),
      ),
    );
  }
}

 

최종코드
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ParentsView(),
    );
  }
}

// 부모 클래스
class ParentsView extends StatefulWidget {
  const ParentsView({super.key});

  @override
  State<ParentsView> createState() => _ParentsViewState();
}

class _ParentsViewState extends State<ParentsView> {
  String displayText = '여기는 부모 위젯 변수야';

  // 메서드를 선언해 보자
  void handleChildEvent(String message) {
    // build() 메서드 호출
    setState(() {
      displayText = message;
    });
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Column(
          children: [
            Expanded(flex: 1, child: Center(child: Text(displayText))),
            Expanded(
                flex: 1, child: ChildA(onCallbackReceived: handleChildEvent)),
            Expanded(
                flex: 1, child: ChildB(onCallbackReceived: handleChildEvent)),
          ],
        ),
      ),
    );
  }
}

// 자식 a
class ChildA extends StatelessWidget {
  const ChildA({required this.onCallbackReceived, super.key});

  final Function(String message) onCallbackReceived;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(30.0),
      child: InkWell(
        onTap: () {
          print('child a 에 이벤트 발생 ');
          // Fuction 데이터 타입
          // onCallbackReceived() ---> 호출
          onCallbackReceived('A가 연산한 데이터를 전달 했음');
        },
        child: Container(
          width: double.infinity,
          color: Colors.orange,
          child: Center(child: Text('CHILD A')),
        ),
      ),
    );
  }
}

// 자식 b
class ChildB extends StatelessWidget {
  const ChildB({required this.onCallbackReceived, super.key});

  final Function(String message) onCallbackReceived;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(30.0),
      child: InkWell(
        onTap: () {
          print('child b 에 이벤트 발생 ');
          onCallbackReceived('자식 b가 연산한 데이터 전달');
        },
        child: Container(
          width: double.infinity,
          color: Colors.red,
          child: Center(child: Text('CHILD B')),
        ),
      ),
    );
  }
}

 

 

오늘은 자식 위젯에서 발생한 이벤트를 부모 위젯이 콜백 함수로 처리하는 방법을 배웠습니다.
이 방식을 활용하면 위젯 간의 의존성을 줄이고 데이터 흐름을 효율적으로 관리할 수 있습니다.

Flutter의 위젯 구조를 활용한 콜백 함수는 이벤트 기반 설계에서 유용하다고 하니 다양한 상황에서 응용해보는 연습을 해야겠습니다.

다음에도 Flutter 관련 포스팅으로 찾아오도록 할게요. 감사합니다!

 

💡 콜백 함수가 뭔가요?

 

[JAVA] 디자인패턴 : 콜백(Callback) 패턴 알아보기

안녕하세요! 오늘은 디자인 패턴 중에서도 콜백 메서드라는 개념에 대해 알아보겠습니다. 콜백 메서드는 유연하고 확장 가능한 코드 설계를 가능하게 하며, 특히 비동기 처리나 이벤트 기반 시

dev-yeonwha.tistory.com