[240131] Today I Learned

YoungHyun Kim·2024년 1월 31일
1

TIL ✍️

목록 보기
44/68
post-thumbnail

코드로 UI 그리기

어떻게 해야 최대한 깔끔하게 코드를 작성할 수 있는지 고민하며 프로젝트를 진행하려 했습니다.
근데 실력이 좋지 않아서 깔끔하지 못한 코드가 나온... 초보인 점을 양지해주시길...!

1. UI 요소 만들기

  • 일단 레퍼런스로 받은 이미지대로 요소를 하나씩 만들어주기 시작했다.
  • UILabel, UIImageView, UIButton, UICollectionView, UIStackView 등의 요소를 사용했는데...

  • 위에 파란 블럭을 사용해서 어떤 식으로 UIStackView를 사용했는지 표현했다. 이런 식으로 StackView를 사용해두면, 나중에 어느 위치에 다른 요소를 더 추가할 상황에 쉽게 작업이 가능할 것 같았다!

UIStackView 자주 조작했던 프로퍼티

  1. axis : UIStackView 사용할 때 아주 기본이 되는 프로퍼티다. 스택 뷰 안에 포함시킬 요소들을 보여주는 방향을 결정하는 프로퍼티. .vertical (수직, 위 아래), .horizontal(수평, 양 옆) 두 가지 경우를 골라서 사용하면 된다.
  2. alignment : 스택 뷰 안에 위치시킨 요소들의 정렬을 담당하는 프로퍼티. .center, .leading, .trailing, .fill, .firstBaseline, .lastBaseline 등의 선택지가 있다. 기본값은 .fill
  3. distribution : 단어 그대로 분배라는 뜻. 스택 내의 요소들이 차지하는 공간을 어떤 식으로 분배할 것인지 결정해준다. .fill, .fillEqually, .fillProportionally, .equalSpacing, .equalCentering 다섯 가지의 선택지가 있음.
  4. spacing : 스택 내의 요소들이 얼마만큼의 간격을 가지고 배치될 지 결정해주는 프로퍼티. CGFloat 형식의 값을 받을 수 있다.

작성한 코드는 이런 모습입니다~~ㅠㅠ

private func setConstraint() {
        userInfoLabel.translatesAutoresizingMaskIntoConstraints = false
        menuButton.translatesAutoresizingMaskIntoConstraints = false
        userProfilePicture.translatesAutoresizingMaskIntoConstraints = false
        userPostNum.translatesAutoresizingMaskIntoConstraints = false
        postStack.translatesAutoresizingMaskIntoConstraints = false
        followerStack.translatesAutoresizingMaskIntoConstraints = false
        followingStack.translatesAutoresizingMaskIntoConstraints = false
        userFollowStack.translatesAutoresizingMaskIntoConstraints = false
        userInfoStack.translatesAutoresizingMaskIntoConstraints = false
        middleBarStack.translatesAutoresizingMaskIntoConstraints = false
        navStack.translatesAutoresizingMaskIntoConstraints = false
        moreButton.translatesAutoresizingMaskIntoConstraints = false
        profileButton.translatesAutoresizingMaskIntoConstraints = false
        customCollectionView.translatesAutoresizingMaskIntoConstraints = false
        bottomStack.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            userInfoLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            userInfoLabel.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 10),
            
            menuButton.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 10),
            menuButton.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: -14),
            
            userProfilePicture.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 14),
            userProfilePicture.topAnchor.constraint(equalTo: self.userInfoLabel.bottomAnchor, constant: 14),
            
            userFollowStack.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: -28),
            userFollowStack.leadingAnchor.constraint(equalTo: self.userProfilePicture.trailingAnchor),
            userFollowStack.centerYAnchor.constraint(equalTo: self.userProfilePicture.centerYAnchor),
            
            userInfoStack.topAnchor.constraint(equalTo: self.userProfilePicture.bottomAnchor, constant: 14),
            userInfoStack.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 14),
            
            moreButton.topAnchor.constraint(equalTo: self.userInfoStack.bottomAnchor, constant: 14),
            moreButton.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
            moreButton.centerYAnchor.constraint(equalTo: self.middleBarStack.centerYAnchor),
            
            middleBarStack.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 14),
            middleBarStack.topAnchor.constraint(equalTo: self.userInfoStack.bottomAnchor, constant: 14),
            middleBarStack.trailingAnchor.constraint(equalTo: self.moreButton.leadingAnchor, constant: 8),
            
            navStack.topAnchor.constraint(equalTo: self.middleBarStack.bottomAnchor, constant: 14),
            navStack.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
            navStack.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
            navStack.heightAnchor.constraint(equalToConstant: 40),
            
            customCollectionView.topAnchor.constraint(equalTo: self.navStack.bottomAnchor, constant: 10),
            customCollectionView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
            customCollectionView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
            customCollectionView.bottomAnchor.constraint(equalTo: self.bottomStack.topAnchor, constant: -14),
            
            bottomStack.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -10),
            bottomStack.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
            bottomStack.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor)
        ])
    }
    
    // MARK: add things into view
    private func addViews() {
        [userPostNum, postLabel].map ({
            self.postStack.addArrangedSubview($0)
        })
        [userFollowerNum, followerLabel].map ({
            self.followerStack.addArrangedSubview($0)
        })
        [userFollowingNum, followingLabel].map ({
            self.followingStack.addArrangedSubview($0)
        })
        [postStack, followerStack, followingStack].map {
            self.userFollowStack.addArrangedSubview($0)
        }
        [userNicknameLabel, userBioLabel, userLinkLabel].map {
            self.userInfoStack.addArrangedSubview($0)
        }
        [followButton, MessageButton].map {
            self.middleBarStack.addArrangedSubview($0)
        }
        [gridButton, unknownButton, unknown2Button].map {
            self.navStack.addArrangedSubview($0)
        }
        [profileButton].map {
            self.bottomStack.addArrangedSubview($0)
        }
        view.addSubview(userInfoLabel)
        view.addSubview(menuButton)
        view.addSubview(userProfilePicture)
        view.addSubview(userFollowStack)
        view.addSubview(userInfoStack)
        view.addSubview(middleBarStack)
        view.addSubview(navStack)
        view.addSubview(moreButton)
        view.addSubview(customCollectionView)
        view.addSubview(bottomStack)
    }
  • 최대한 가독성을 좋게하고 싶어서, NSLayoutConstraint.activate([......]) 를 사용해서 제약조건 설정할 때, .isActive = true부분을 없앴다. 그래도 워낙 들어간 요소들이 많아서 코드가 지저분하게 보이는 것 같다.
  • 별개로, 한 눈에 접근하기 쉽도록 MARK: 주석을 달아서 Xcode 상단 바에서도 접근할 수 있도록 노력했다.
    (swConstraint()부분을 눌러서 MARK 주석을 보고 코드에 접근할 수 있더라...)
profile
iOS 개발자가 되고 싶어요

0개의 댓글