Exam View 설계

5073 단어 풀고풀고

Exam의 UI 구현

요구 사항

  • 응시 뷰
  • 출제 뷰
  • 오답노트 뷰

원래 생각했던 구현 방법

기존의 방식대로 모든 화면에 대한 스토리보드를 만들고, 코드를 집어넣어 완성하고자 하였다.

문제점

기존의 방식대로 하면서 항상 느껴왔던 문제점이 이번 구현으로 더욱 심해진 것을 느꼈다.
항상 느껴왔던 문제점이란 코드, UI 및 뷰 컨트롤러의 너무 심한 중복이다.
또한 스토리보드를 벗어나 구현을 해보고 싶은 마음이 생긴 것도 조금 있다.

3가지 종류의 요구사항이 모두 비슷한 틀, 비슷한 기능을 가지고 있고
심지어 아예 동일한 기능을 하는 것들이 꽤 있기 때문에 중복을 최대한 피하고 싶었다.

개선한 방법 - 1

가장 단순하게 찾을 수 있는 UI의 공통된 요소가 무엇이 있을까?

  • 상단의 UINavigationBar

    • 상단 왼쪽의 동그란 문제 번호 선택 버튼과 그것을 클릭할 때 나오는 말풍선
  • 하단의 이전 문제, 다음 문제 버튼

이 공통 요소들을 ExamRootViewController에서 구현하고,
3가지 종류의 요구 사항에 대한 뷰 컨트롤러가 ExamRootViewController을 상속하게 하였다.

이렇게 하여 기본적인 틀은 마련이 되었다.

1의 문제점

단순한 UI의 공통점은 그렇다 하지만, 그 공통점들을 제외하고 비슷한 점들은 무엇이 있을까?

  • 문제, 사진, 보기 작성 버튼

이 뷰는 비슷하긴 하지만, 똑같지 않다. 똑같지는 않지만, 너무 비슷하다.

이를 각각의 뷰에 레이아웃 제약을 걸어서 넣는다면, 이전 문제다음 문제 버튼을 누르면
애니메이션을 어떻게 줄 것인가? 애니메이션을 주지 않는다 해도 어떻게 전환할 것인가?

개선한 방법 - 2

이를 ContainerView로 지칭하고, 프로토콜로 정의하였다.

enum ExamType { case create, take, history }

protocol ContainerView: UIView { ... }

class CreateQuestionContainerView: UIView, ContainerView { ... }
class TakeExamContainerView: UIView, ContainerView { ... }
class ExamHistoryContainerView: UIView, ContainerView { ... }

또한 ExamTypeQuestion을 전달받아 적절한 ContainerView를 반환하는
ContainerViewFactory를 정의하였다.

class ContainerViewFactory {
    public static func getContainerView(of type: ExamType, question: Question?) -> ContainerView {
        ...
    }
}

이로써 ContainerView를 사용하는 입장에서는 ExamTypeQuestion만 던져 주면
그에 알맞은 ContainerView를 얻을 수 있게 되었다.

얻은 뷰로 애니메이션을 구현할 수도 있고, 전환이 매우 편해졌다.

좋은 웹페이지 즐겨찾기