티스토리 뷰

다소 밋밋한 앱을 꾸밀 차례입니다. 본격적으로 스타일링 작업을 시작하겠습니다

여태껏 위젯 안에 위젯을 넣으면서 widget tree를 만들었었지요?

        body: Column(
          children: [
            Text(questions[questionIndex]),
            RaisedButton(
              onPressed: answerQuestion,
              child: Text("빨강"),
            ),
            RaisedButton(
              onPressed: answerQuestion,
              child: Text("파랑"),
            ),
            RaisedButton(
              onPressed: answerQuestion,
              child: Text("검정"),
            ),
          ],
        ),
      ),

물론 지금은 앱이 크게 복잡하지 않아서 와 닿지 않을 수 있기는 한데,

        body: Column(
          children: [
            Question(),
            Answers(),
          ],
        ),
      ),

이렇게 위젯트리가 구성되어있으면 조금 더 깔끔해 보이겠죠?

플러터에서는 가독성성능 향상을 위해서 위젯을 잘 분리시켜주는 게 매우 중요합니다

Question 위젯 분리하기

먼저 질문에 해당하는 친구를 따로 위젯으로 빼놓을게요

일반적으로 파일 하나에 위젯 하나가 원칙입니다.

새로운 파일을 만들어서 question.dart를 만들어줄 거예요

그리고 빈 파일에다 stl을 적어보면 이렇게 자동완성 snippet을 볼 수 있어요! 저희는 stateful이 아닌 stateless 위젯을 만들거에요

그리고 클래스명은 Question으로 할게요

근데 아직 빨간 밑줄이 보이네요. import가 안돼서 에러가 나는 거였네요. 후딱 import도 해줍시다!

플러터는 이렇게 자동완성 기능이 매우 편합니다. 많이 많이 애용해주세요

우선 Question이 간단한 text 위젯을 하나 리턴하는 걸로 할게요

import 'package:flutter/material.dart';

class Question extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text("hello");
  }
}

그리고 main.dart로 돌아가 Text를 방금 만든 Question으로 바꿔줄게요

여기는 지워주고...

Question을 치면 IDE가 자동으로 question.dart를 import까지 해줍니다.

핫 리로드를 해주면...!

좋습니다 우선 바꿔치기는 되었어요! 그런데 hello가 아니라 질문이 보이는 게 목표죠?
해당 값을 받을 수 있게 해야겠네요

다시 Question 클래스로 돌아가서

questionText이라는 String 변수를 하나 추가해주고
생성자를 하나 만들어주고
Text에게 questionText을 넘겨줄게요

class Question extends StatelessWidget {
  String questionText;
  Question(this.questionText);

  @override
  Widget build(BuildContext context) {
    return Text(questionText);
  }
}

그리고 main.dart에서 에러가 날 텐데

에러가 난 부분을 Question(_questions[_questionIndex])로 바꿔주면

짠!

이제 원하는 것처럼 잘 나오네요!

그리고 버튼을 누르면 다음 질문으로 잘 넘어가지네요

stateless 위젯

그런데 제가 Question을 stateless 위젯으로 했는데, 선택지를 눌렀을 때 string값이 바뀌는 이유는 뭘까요?

앞에서 얘기했던 것처럼 input 데이터(question 스트링)가 바뀌기 때문에 widget이 다시 렌더링 되는 것입니다.

즉 Question의 questionText는 state에 해당하는 것이 아니였죠.

final

앗 그런데 Question 클래스로 가보면

이렇게 파란색 밑줄이 쳐져있네요.

대충 얘기를 들어보니 immutable한(바뀌지 않는) 객체인데, var로 questionText를 만들면 mutable인 객체로 표시하고 있다고 말을 합니다.

앞에 final을 붙여줄게요

final String questionText;

그러면 파란색 밑줄이 사라집니다

final은 앞으로 이 친구는 변하지 않을 거다!라고 말해줍니다.

스타일링!

Question의 build함수가 리턴하고있는 Text에 여러 가지 named parameter가 있는데, 한번 볼게요

Text의 괄호 안에서 ctrl + 스페이스바 를 해보면 Text가 받는 모든 paramter를 보여줍니다.

 

흠.. 이중에 style이 맘에 드네요

이 style이 어떤 객체를 받는지 보기 위해서 style위에 커서를 올려보면

TextStyle이라는 객체를 원하는 것 같네요. TextStyle을 치고 다시 ctrl + 스페이스바 를 해줄게요

TextStyle 역시 여러 가지 parameter가 있네요.

정확한 거는 모르지만
아마 color는 글씨 색, 그리고 fontSize는 글씨 크기를 정해주는 parameter겠죠?

   return Text(
      questionText,
      style: TextStyle(
        color: Colors.red,
        fontSize: 28,
      ),
    );

이렇게 넣어주고 핫 리로드를 해주면...!

첫 스타일링!

이제 글씨를 정렬해주고 싶은데 화면의 가운데에 정렬을 하는 게 좋겠죠?

이번에 Text의 textAlign parameter를 적용해보면

이렇게 TextAlign이라는 친구를 필요로 하는 것 같아요

Widget build(BuildContext context) {
    return Text(
      questionText,
      style: TextStyle(
        color: Colors.red,
        fontSize: 28,
      ),
      textAlign: TextAlign.center,
    );
  }

그런데 핫 릴로드 해도 가운데 정렬이 안되었는데요?

현재 text가 글씨에 해당하는 영역만 갖고 있기 때문입니다

flutter inspector를 이용해서 확인해볼 수도 있습니다. Text가 해당 공간을 딱 가지고 있으니까 정렬의 의미가 없는 겁니다.

해결을 하기 위해서 Container를 이용할 겁니다.

Text위에 커서를 두고 cmd + . 을 눌러주고 Wrap with Container를 눌러주세요

 

Container

Container위젯은 스타일링을 위해 자주 쓸 위젯입니다.

기본적으로 child를 가지고 있습니다. 지금 같은 경우에는 Text위젯이 child가 되겠죠?

만약에 border를 가지고 있으면, Border와 child 사이의 간격을 padding, Border와 다른 위젯 사이의 간격을 margin이라고합니다.

또한 크기를 정해주기 위해서 widthheight를 정해줄수도 있습니다.

저희는 width를 정해줄 건데 양 옆으로 최대한 길게 뻗게 하기 위해서 무한으로 설정할게요

return Container(
      width: double.infinity,
      child: Text(
        questionText,
        style: TextStyle(
          color: Colors.red,
          fontSize: 28,
        ),
        textAlign: TextAlign.center,
      ),
    );

Text가 가운데 정렬이 잘 되었네요!

위아래로 너무 붙어있는 것 같아서 margin 또한 넣어줄게요

EdgeInsets.symmetric(vertical: 20)위아래로 20 만큼 공간을 주겠다 라는 뜻입니다.

완성된 Question widget 코드

import 'package:flutter/material.dart';

class Question extends StatelessWidget {
  final String questionText;
  Question(this.questionText);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      margin: EdgeInsets.symmetric(vertical: 20),
      child: Text(
        questionText,
        style: TextStyle(
          color: Colors.red,
          fontSize: 28,
        ),
        textAlign: TextAlign.center,
      ),
    );
  }
}

Widget Catalog

플러터에서 UI를 만들 때는 정말 다양한 위젯을 쓰게 될 겁니다. IDE가 제공하는 자동완성 기능과 snippet기능등을 이용하면 정말 편하게 쓸 수 있습니다. 하지만 가끔은 IDE상으로는 한계가 있을때가 있는데요, 그때는 공식 문서를 참고하면 큰 도움이 될겁니다.

카테고리 별로 보기 위해서는 https://flutter.dev/docs/development/ui/widgets 을 참고하시면 되고.

widget 하나를 참고하기 위해서는 https://api.flutter.dev/flutter/widgets/Container-class.html 로 들어가셔서 오른쪽 상당의 검색을 활 요하시면 됩니다.

 

 

 

 

다음 글에는 선택지를 위젯으로 분리시켜볼게요!

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함