티스토리 뷰

반응형

 

안녕하세요 :) Zedd입니다.

저번글에서는 정말 아주아주아주아주 간단하게만 StatelessWidget를 살펴봤습니다.

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

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

class ZeddApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(home: Scaffold());
  }
}

이렇게요. 

오늘은 StatelessWidget에 대해서 좀 더 자세하게 살펴볼려고 합니다.

 

StatelessWidget


StatelessWidget은 정말 말 그대로 상태가 없는 Widget입니다.

좀 더 풀어서 말하면 변경 가능한 상태가 필요하지 않은 Widget입니다.

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

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

class ZeddApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(home: Scaffold());
  }
}

자..저번에 만든 StatelessWidget입니다.

만약 이런게 아니라..

내가 어떤 Widget을 만들고싶은데, 그 Widget에 Color와 Text가 각각 달라야합니다. 

그럼 내가 해당 Widget을 만들 때 Colors와 Text를 넣어주면 되겠죠?

 

예를 하나 들어보겠습니다.  

class ZeddApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(home: Scaffold(
        appBar: CupertinoNavigationBar(middle: Text("Hello, Zedd!")),
        body: Center(
            child: Column(
            children: [
              DecoratedBox(decoration: BoxDecoration(color: Colors.blue), child: Text("Hello")),,
              DecoratedBox(decoration: BoxDecoration(color: Colors.blue), child: Text("world")),
              DecoratedBox(decoration: BoxDecoration(color: Colors.blue), child: Text("Dart"))
            ]
            )
        )
    )
    );
  }
}

자..진짜 좀 복잡한데...뭐 Center니 Column이니 몰라도 됩니다. 대충

이런 화면이 나오게 되는 코드에요. 

우리가 주의깊게 봐야할 부분은 

children: [
    DecoratedBox(decoration: BoxDecoration(color: Colors.blue), child: Text("Hello")),,
    DecoratedBox(decoration: BoxDecoration(color: Colors.blue), child: Text("world")),
    DecoratedBox(decoration: BoxDecoration(color: Colors.blue), child: Text("Dart"))
]

여기입니다. 뭔가 코드가 중복도 있어보이고.. Text만 다르네요.

이 부분은 따로 Widget을 만들면 좋을 것 같죠? 그리고 Color와 Text를 입력받을 수 있게 하면 좋을 것 같습니다.

ZeddBox(Colors.blue, "Hello")

최종적으로 이렇게 넣어주면 좋을 것 같아요! 

 

상태가 딱히 필요한게 아니니 StatelessWidget으로 만들어주겠습니다.

// DecoratedBox(decoration: BoxDecoration(color: Colors.blue), child: Text("Hello"))
class ZeddBox extends StatelessWidget {
 
  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
        decoration: BoxDecoration(color: this.color),
        child:  Text(this.text)
    );
  }
}

자..이렇게 만들었는데요, 그냥 우리가 만들어야 하는 저 코드를 return쪽에 쓴거에요! 

그리고 color와 text를 이 클래스의 프로퍼티를 사용하도록 하면 될 것 같아요. 

ZeddBox(Colors.blue, "Hello")

즉 이렇게 내가 넘긴 값을 사용 할 수 있도록 생성자를 만들어주겠습니다.

class ZeddBox extends StatelessWidget {
  Color color;
  String text;

  ZeddBox(this.color, this.text);

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
        decoration: BoxDecoration(color: this.color),
        child:  Text(this.text)
    );
  }
}

최종 코드에요! 

이렇게 하면 동작에는 문제가 없습니다.

하지만 IDE에서 warning이 뜨고 있을겁니다.

This class (or a class that this class inherits from) is marked as '@immutable', but one or more of its instance fields aren't final: ZeddBox.color, ZeddBox.text

StatelessWidget이므로 상태가 변하지 않는 Widget이잖아요?

이 상태가 변경되는것을 막기 위해 이 친구들을 전부 final로 선언하라는 이야기입니다.

다시한번 말하지만, 동작에는 아무 이상은 없습니다.

냥 맥락상..final인게 맞으니 final로 선언해줍시다.

class ZeddBox extends StatelessWidget {
  final Color color;
  final String text;

  const ZeddBox(this.color, this.text);

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
        decoration: BoxDecoration(color: this.color),
        child:  Text(this.text)
    );
  }
}

이렇게 해줍니다. final로 선언되었으니 생성자도 const로 만들어줍니다.

⚠️ 생성자는 꼭 const로 안만들어도 됩니다!

 

자, 이제 ZeddBox를 사용하도록 만들어보겠습니다.

class ZeddApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(home: Scaffold(
        appBar: CupertinoNavigationBar(middle: Text("Hello, Zedd!")),
        body: Center(
            child: Column(
            children: [
                ZeddBox(Colors.blue, "Hello"),
                ZeddBox(Colors.pink, "world"),
                ZeddBox(Colors.amberAccent, "Dart")
            ]
            )
        )
    )
    );
  }
}

이렇게 나오게 됩니다!! 

 

개선(안봐도 됨)


class ZeddBox extends StatelessWidget {
  final Color color;
  final String text;

  const ZeddBox(this.color, this.text);

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
        decoration: BoxDecoration(color: this.color),
        child:  Text(this.text)
    );
  }
}

조금 더 개선해보자면..생성자를 named parameter를 사용하도록 바꿔보겠습니다.

class ZeddBox extends StatelessWidget {
  final Color color;
  final String text;

  const ZeddBox({this.color, this.text}); ‼️

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
        decoration: BoxDecoration(color: this.color),
        child:  Text(this.text)
    );
  }
}

이렇게요. {}로 묶어준거 보이시죠!? 

ZeddBox(this.color, this.text); // before

ZeddBox({this.color, this.text}); // after

 

 

이렇게 해주면 호출하는 쪽에서 파라미터 이름을 꼭 같이 넣어줘야합니다.

// before
ZeddBox(Colors.blue, "Hello"),
ZeddBox(Colors.pink, "world"),
ZeddBox(Colors.amberAccent, "Dart")

// after
ZeddBox(color: Colors.blue, text: "Hello"),
ZeddBox(color: Colors.pink, text: "world"),
ZeddBox(color: Colors.amberAccent, text: "Dart")

이렇게요.

파라미터 이름을 자동완성으로 뜨게 하고 싶다면

const ZeddBox({@required this.color, @required this.text});

@required를 붙혀주면 됩니다.

그럼 이렇게 자동완성 된 걸 선택했을 시

자동으로 파라미터 이름들이 나오게 됩니다.

@required를 안넣으면 그냥 자동완성 된거 엔터치면..

이렇게 밖에 안뜹니다..!!! 

 

요약

- StatelessWidget는 상태가 없는 Widget. 한번 그리고 다시 그려야 할 필요가 없을 땐 StatelessWidget을 사용.

- StatelessWidget의 필드들은 final로 선언이 되어야 한다. 

 

다음글 : StatefulWidget 자세히 살펴보기

 

참고 

api.flutter.dev/flutter/widgets/StatelessWidget-class.html

 

StatelessWidget class - widgets library - Dart API

A widget that does not require mutable state. A stateless widget is a widget that describes part of the user interface by building a constellation of other widgets that describe the user interface more concretely. The building process continues recursively

api.flutter.dev

반응형