관리 메뉴

Bull

[Flutter] copyWith 메소드의 역할 본문

Software Framework/Flutter

[Flutter] copyWith 메소드의 역할

Bull_ 2024. 8. 6. 09:19

copyWith 의미

copyWith 메소드는 Flutter에서 Immutable 클래스를 복사하면서 특정 속성들을 변경할 수 있도록 해주는 메소드입니다. 주로 StatefulWidget의 상태를 관리할 때 많이 사용됩니다.

copyWith 예제

예를 들어, 다음과 같은 Person 클래스를 생각해봅시다.

class Person {
  final String name;
  final int age;

  Person({required this.name, required this.age});

  Person copyWith({String? name, int? age}) {
    return Person(
      name: name ?? this.name,
      age: age ?? this.age,
    );
  }
}

위의 Person 클래스는 copyWith 메소드를 포함하고 있습니다. 이 메소드는 새로운 Person 객체를 생성하되, 주어진 속성 값이 있으면 그 값으로, 없으면 기존 객체의 값을 사용합니다.

void main() {
  Person person1 = Person(name: "Alice", age: 30);
  Person person2 = person1.copyWith(age: 31);

  print(person1.name); // Alice
  print(person1.age);  // 30

  print(person2.name); // Alice
  print(person2.age);  // 31
}

Person 클래스를 통해 만들어진 person1의 인스턴스를 copyWith메소드를 사용하여 age 만 다른 person2 인스턴스를 만들어줄 수 있습니다.

 

copyWith 메소드를 사용하면 특정 필드만 변경하면서 나머지 필드는 그대로 유지하는 새로운 객체를 쉽게 만들 수 있습니다. Flutter에서 State를 업데이트할 때 매우 유용합니다. 예를 들어, State 객체가 여러 속성을 가지고 있을 때, 특정 속성만 변경하고 나머지 속성은 그대로 유지한 상태로 업데이트를 할 수 있습니다.

 

copyWith 메소드는 Dart의 패턴 중 하나로, 클래스의 인스턴스를 복사하면서 일부 속성만 변경하고자 할 때 많이 사용됩니다. 이 패턴은 Immutable 객체를 효율적으로 다루기 위해 널리 사용됩니다.

자주 등장하는 Theme 에서의 copyWith

copyWith 를 직접 구현하여 사용할 수도 있지만 Flutter의 Theme, --Style 등의 위젯에서 자주 사용됩니다. 기본 예제를 통해 copyWith가 무엇인지 알았으니 Flutter의 Theme 에서도 다뤄보겠습니다.

// class MyApp extends StatelessWidget
MaterialApp(
      theme: ThemeData(
        textTheme: TextTheme(
          bodyLarge: TextStyle(fontSize: 18.0, color: Colors.black),
          titleLarge: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold, color: Colors.black),
        ),
        home: MyHomePage(),
    ),
)

ThemeData 를 통하여 textTheme의 테마만 정해보겠습니다.

Flutter 3.0부터 TextTheme 클래스가 Material 3 디자인 사양에 맞춰 업데이트되었습니다. 따라서 스타일에 관한 프로퍼티에 혼동 없으시길 바랍니다.

[cf.] bodyLarge의 Material 2 버전은 bodyText1 이었습니다.

// class MyHomePage extends StatelessWidget
TextStyle baseBodyStyle = Theme.of(context).textTheme.bodyLarge!;
TextStyle baseTitleStyle = Theme.of(context).textTheme.titleLarge!;

테마에 대한 스타일을 인스턴스로 생성하였습니다.

Text(
    'Hello, Flutter! (copyWith)',
    style: baseBodyStyle.copyWith(color: Colors.blue),
),

bodyLarge 테마에 지정한 스타일은 유지하되, color만 blue로 바꿔줍니다.

Text(
    'Welcome to Flutter! (copyWith)',
    style: baseTitleStyle.copyWith(color: Colors.red, fontSize: 26.0),
),

titleLarge에 지정한 스타일은 유지하되, color를 red로 바꾸고 fontSize는 26.0으로 변경해줍니다.

전체 CODE

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        textTheme: TextTheme(
          bodyLarge: TextStyle(fontSize: 18.0, color: Colors.black),
          titleLarge: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold, color: Colors.black),
        ),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    TextStyle baseBodyStyle = Theme.of(context).textTheme.bodyLarge!;
    TextStyle baseTitleStyle = Theme.of(context).textTheme.titleLarge!;

    return Scaffold(
      appBar: AppBar(title: Text('copyWith Example')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Hello, Flutter!',
              style: baseBodyStyle,
            ),
            Text(
              'Hello, Flutter! (copyWith)',
              style: baseBodyStyle.copyWith(color: Colors.blue),
            ),
            SizedBox(height: 16.0),          
            Text(
              'Welcome to Flutter!',
              style: baseTitleStyle,
            ),
            Text(
              'Welcome to Flutter! (copyWith)',
              style: baseTitleStyle.copyWith(color: Colors.red, fontSize: 26.0),
            ),
          ],
        ),
      ),
    );
  }
}