본문 바로가기
공허의 유산/사상의 도구

[Flutter]. 08. Flutter tutorial on codelab(4)

by 바른생활머시마 2023. 1. 24.
728x90
반응형

앞에서 UI를 재정의 하는 코드를 삽입하는 방법과 Refactoring 명령으로 Wrapping 하는 방법 등을 살펴보았습니다.

https://learn-and-give.tistory.com/46

 

[Flutter]. 06. Flutter tutorial on codelab(3)

앞에서 앱의 가장 기본적인 구조, 즉, 화면과 로직을 구현하는 클래스를 정의하고 상호간 연동하는 부분을 구현하였습니다. https://learn-and-give.tistory.com/44 [Flutter]. 05. Flutter tutorial on codelab(2) 지난

learn-and-give.tistory.com

이제 남은 꾸미기를 마저 진행 해 보겠습니다.

 

TextTheme

Text에도 테마를 적용 할 수가 있군요.

 

먼저 context로부터 현재 설정 된 style을 가져와서, 카드의 텍스트 표시를 나타내는 위젯에 스타일 관련 속성을 반영합니다.

  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);

    // ↓ Add this.
    var style = theme.textTheme.displayMedium!.copyWith(
      color: theme.colorScheme.onPrimary,
    );

    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        //child: Text(pair.asLowerCase),
        child: Text(pair.asLowerCase, style: style),
      ),
    );
  }

새로 추가한 코드에 낯선 표현이 있네요.

theme.textTheme.displayMedium!.copyWith

 

displayMedium 뒤의 느낌표가 무슨 역할을 하는 것일까요? 뒤의 점과 함께 묶어서 어떤 연산자 역할을 하는 것 같기도 하고... 아래 설명을 보니, 절대 null이 아니라는 표현을 하는 것으로 bang operator라고 한다고 되어 있네요. null-safe인 Dart에게 코드 문맥상 null이 될 수도 있는 것은 실행되지 않을 수 있으니, "내가 null 아니라고 보장 할테니 실행해줘" 뭐 요런 느낌???

 

  • The theme's displayMedium property could theoretically be null. Dart, the programming language in which you're writing this app, is null-safe, so it won't let you call methods of objects that are potentially null. In this case, though, you can use the ! operator ("bang operator") to assure Dart you know what you're doing. (displayMedium is definitely not null in this case. The reason we know this is beyond the scope of this codelab, though.)

.을 통해서 하위 속성들을 여러가지 접근 할 수 있는데, 어떤 속성들이 있는지는 많은 샘플을 보면서 공부 해 나가야 할 것 같습니다. 여기서 사용하는 displayMedium 속성은 짧고 중요한 문구용 속성인 것 같은데, 아직은 정확히 잘 모르겠네요.

 

copyWith를 통해서 그 속성의 사본을 만들 때 필요한 속성을 변경할 수 있는데, 여기서는 색상을 변경하여 style의 사본을 만들어 내고, 그것을 사용하는 것입니다.

 

이렇게 카드의 Text 위젯 속성을 변경하고 실행하면 아래와 같은 결과를 볼 수 있습니다.

copyWith에 사용 할 수 있는 다양한 인자들은 Control+Shift+Space를 누르면 나온다고 되어 있는데, VS Code에서 마우스만 갖다 두어도 보이네요. 물음표 문법도 처음 보는 문법인데 값을 넣어주면 쓰고 아니면 말고? 뭐 그런 느낌??ㅋ  지정하지 않으면 기본값 그대로 쓰고, 지정 된 속성만 변경하는 것으로 이해하면 될 것 같습니다.

 

Semantics Label

Text 위젯에 대해서 조금 색다른 내용도 소개되어 있는데, Semantic Label이라는 속성입니다. 즉, 화면에 보여질 내용과 별도로 의미를 표현하기 위한 정보를 추가 할 수 있다고 합니다 .소개 된 예제가 이해하는데 적절한 예 같아요.

 요즘은 시각장애인들도 휴대폰을 쓸 수 있도록 접근성을 위한 정책이나 기술들이 많이 있습니다. 화면에 보여지는 글자 그대로 읽었을 때 그 의미가 온전히 전달되기 어려운 경우, 이를 고려하여 읽어서 의미를 전달하기 용이한 내용을 여기에 적으면 됩니다. 특히, 이 예제처럼 두 개의 단어가 합성되는 단어의 경우, 원래 없는 조합의 단어도 있으니 올바른 발음이 되지 않을 수 있으며, 각 단어의 발음을 따로 표현하는 것이 그 의미가 정확히 전달 될 수 있습니다. 이 경우, 화면에 표시되는 것처럼 asLowerCase라는 옵션을 쓰지 않고, asPascalCase 옵션을 쓰면, 단어별로 첫 글자를 대문자로 표시하기 때문에 화면을 읽어주는 기능이 단어별로 올바른 발음으로 읽어 줄 수 있게 됩니다.

 비슷한 예로, 이미지 테그에서 alt 속성의 역할과 조금 비슷한 부분이 있을 수 있겠네요.(억지로 갖다붙이자면.ㅋ)

 어떤 서비스의 접근성에 신경을 쓸 경우, 챙겨봐야 할 옵션인 것 같습니다.

 샘플 코드에는 아래와 같이 적용합니다.

  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);
    var style = theme.textTheme.displayMedium!.copyWith(
      color: theme.colorScheme.onPrimary,
    );

    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20),

        // ↓ Make the following change.
        child: Text(
          pair.asLowerCase,
          style: style,
          semanticsLabel: pair.asPascalCase, // <=========
        ),
      ),
    );
  }

 

 

 

 

Center 정렬

 

다음으로 Layout에서 위치를 잡아주는 부분입니다. 먼저 Column이라는 위젯에 이전에 만든 것을 다 넣어(Wrap) Column위젯을 만들고, 그 속성의 새로 정렬을 중앙(Center)으로 하여 세로 방향 정렬은 중앙에 되게 합니다. 그 후, 컬럼의 좌우 정렬을 Center라는 위젯에 넣어 가운데 정렬을 시켜주는 방식으로 합니다. 아마, 순서는 반대로 해도 되지 않을까 싶네요. 작업 대상은 카드와 버튼이 포함 된 UI부분 전체이니, MyHomePage 클래스 내부의 위젯 중 상위를 대상으로 하면 되겠고, Column 위젯은 이미 있으니, 속성 추가부터 하면 되겠습니다..

 먼저 Column 정렬 속성을 추가하여 아래와 같이 코드를 작성합니다.

    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,  // ← Add this.
        children: [
          Text('A random AWESOME idea:'),
          BigCard(pair: pair),
          ElevatedButton(
            onPressed: () {
              appState.getNext();  
            },
            child: Text('Next'),
          ),
        ],
      ),
    );
  }

 

결과는 아래와 같이 세로 정렬이 중앙으로 되었습니다.

이제 이 Column 위젯을 Center라는 위젯으로 감싸보겠습니다. 앞에서 했던 Refactoring 기능의 Wrap을 쓰면 됩니다.

이 과정은 tutorial의 gif 이미지를 보는 것이 더 좋겠네요.

그 결과, 화면 중앙에 정렬 된 위젯들을 볼 수 있습니다.

이제 마무리 단계인데요,

상단의 불필요한 텍스트를 제거하고,

카드와 버튼 사이에 공백이 없는데, 여기에 빈 박스(SizedBox) 위젯을 넣어 공간을 만들어 주는 것으로 마무리 합니다.

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center, 
          children: [
            BigCard(pair: pair),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                appState.getNext();  
              },
              child: Text('Next'),
            ),
          ],
        ),
      ),
    );
  }

결과는~

다음에는 기능 추가에 대한 내용으로, Like라는 토글형 버튼을 추가하는 내용입니다.

https://learn-and-give.tistory.com/48

 

[Flutter]. 09. Flutter tutorial on codelab(5)

앞에서 화면을 꾸미는 내용을 좀 다뤄봤습니다. https://learn-and-give.tistory.com/47 [Flutter]. 07. Flutter tutorial on codelab(4) 앞에서 UI를 재정의 하는 코드를 삽입하는 방법과 Refactoring 명령으로 Wrapping 하는

learn-and-give.tistory.com

 

728x90
반응형

댓글