플러터 UI 챌린지 #2(메가박스 클론-1)

개요

"오 이거 내가 만들 수 있을 것 같은데?"
-고문의 시작을 알리는 마음의 소리

이번 UI 챌린지는 메가박스 앱 클론으로 골랐다. 메가박스 앱의 UI는 복잡한듯 아닌듯 미묘한 경계선에 있다. 앱 프론트 개발자로서 한 번 도전 할 만 하다고 생각 됐다. 물론 아직 다 완성한 것은 아니다. 계속 개발 중이고 디테일 한 부분에서 다른 점도 많다. 하지만 그럼에도, 개발 과정에서 얻은 지식을 정리 해두려 한다.

삽질 ①: 버튼 테두리에만 그라데이션 효과 주기✨


플러터의 Container 위젯에는 그라데이션 파라미터가 있다. 전체 색상에 그라데이션이 적용 된다. 문제는 테두리에만 그라데이션을 주는 파라미터가 없다는 것이다. 혹시 제가 모르는 것이라면 부디 알려주세요...

class MFeedButton extends StatelessWidget {
  VoidCallback func;
  MFeedButton({required this.func});
  
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: func,
      child: Container(
      //테두리용 Container
       ...
          gradient: LinearGradient(
           ...
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(1.0),
          child: Container(
          //실제 내용물 Container
           ...
            child: const Center(
              child: ...
              ),
            ),
          ),
        ),
      ),
    );
  }
}

내가 선택 한 방법은 간단하다. Container 2개를 겹치는 것이다. 전체 그라데이션이 적용 된 Container와, 그보다 아주 살짝 작은 Container를 겹친다. 그럼 전체 그라데이션이 적용 된 Container살짝 삐져 나오는데, 시각적으론 버튼 테두리에 그라데이션이 적용 된 것처럼 보인다.

삽질 ②: 가운데 정렬 안 되는 텍스트들🥲

Stack 위젯을 이용해서 이미지 위에 텍스트를 올렸는데, 아무리 가운데 정렬을 해도 환장하게도 자꾸 왼쪽으로 치우쳤다. 고민 끝에 Align 위젯이 아니라 Text위젯의 textAlign 파라미터를 사용하기로 했다.

textAlign 파라미터에 .center 값을 지정 할 경우, Text위젯이 차지한 영역 내에서 텍스트를 가운데로 정렬 해준다. 그렇다면 할 일은 하나. Text위젯이 이미지와 같은 가로 영역을 차지하게 하면 된다.

SizedBox(
    width: 70,
    child: Text(
        topCellLabels[index],
        textAlign: TextAlign.center,
        style: const TextStyle(color: Colors.white),
    ),
),

이미지와 똑같은 가로 길이의 SizedBox로 감싼 다음, .center를 적용 했더니 잘 됐다.

삽질 ③: ListView가 가로로 스크롤 될 때, 그림자가 잘리는 현상✂️

가로 스크롤 되는 리스트 뷰 아이템의 높이는, 리스트 뷰 전체 높이와 같다. 당연한 소리지만, 그림자는 원본보다 살짝 아래에 있다. 그래서 잘려버리는 것이다. 그렇다. 그냥 "영역 밖으로 조금 벗어나도 자르지 마세요"라고 지시하면 된다. ListView의 clipBehavior 파라미터에 .none 값을 지정 하면 된다.

삽질 ④: 위젯의 사이즈 구하기📐

선택 된 해시태그 아래에 보라색 밑줄이 있다. 문제는, 이 밑줄은 텍스트의 길이와 같다는 것이다. 해시태그는 계속 바뀔텐데, 어떤 텍스트가 올 줄 어떻게 알고 밑줄의 길이를 지정하는걸까?

내가 첫번째로 떠올린 방법은 투명 컨테이너로 감싸는 것이다. 선택 됐을 때 아래쪽 Border에만 색을 줘서, 마치 밑줄처럼 보이게 한다는 작전! 하지만 이 방법을 선택하진 않았다. 이 방법은 오직 이 위젯에서만 사용 할 수 있기 때문이다. 다른 곳에서 비슷한 문제를 만나면, 똑같은 구성으로 코드를 또 짜야 한다. 재사용성 측면에서 별로 좋지 않아 보였다.

그냥 렌더링 된 위젯의 사이즈를 런타임에 알아낼 수 있는 방법이 없을까🤔...? 고민을 하다, GlobalKey가 바로 그런데 쓰라고 있다는걸 알게됐다. GlobalKey는 RenderObj와 일대일 대응하고, 따라서 GlobalKey를 통해 그 키가 '꽂혀 있는' 위젯의 정보를 받아 올 수 있다고.

class SizeUtil {
  static Size? size;//BuildContext 상실 대비, 이전 값 백업용 변수
  static Size getWidgetSizeByGlobalKey(GlobalKey key) {
    if (key.currentContext == null) return size ?? const Size(0, 0);
    size = (key.currentContext!.findRenderObject() as RenderBox).size;
    return size ?? const Size(0, 0);
  }
}

이 유틸리티 클래스를 통해서, 특정 위젯이 런타임에 사이즈가 얼마나 되는 지 알 수 있다.

이번 주 작업(?) 후기

"역시 난 아직 멀었구나"

이 클론 작업은 매주 주말마다 진행 될 것 같다. 평일에는 회사 일을 해야하니까. 이제 막 시작 했는데 후기를 쓰는 것도 웃긴다. 하지만 일단은 첫 주 소감을 적는다.

플러터 프레임워크와 더 친해진다는 느낌을 많이 받았다. 그동안 주먹구구 식으로 '직접' 구현 했던 많은 것들이, 사실 플러터 프레임워크에서 상당 수 지원 된다는 것을 알았다.

나는 그동안 플러터 프레임워크에서 기본적으로 제공 되는 기능들도 다 파악하지 못한 체, 플러터 개발자로 일 하고 있었다. 프레임워크를 사용하면서 프레임워크에대한 이해도가 많이 부족했다.

누군가 말했다. 프레임워크만으로 모든걸 할 순 없지만, 적어도 프레임워크로 할 수 있는건 다 할 수 있어야 한다고. 그래야 나 OOO프레임워크로 개발 해요, 말 할 수 있다고. 이 클론 개발이 끝났을 때, 나도 플러터 프레임워크 '좀 쓸 줄 알아요'라고 할 수 있는 개발자가 되길 바란다.

좋은 웹페이지 즐겨찾기