본문 바로가기

iOS 개발/Apple App Store 클론 코딩

AppleAppStore - 17. DetailViewController의 section, cell 구현 6

반응형

안녕하세요. Skillist입니다.

앱스토어 클론코딩도 얼마 안남았습니다!

아직 구현할 기능은 있지만, 목표했던 구현에는 충분히 도달했어요.

앱스토어 클롭코딩을 하며, 배운것도 많았고, 실력이 향상한것을 느끼고 있습니다. 여러분도 같이 느껴지죠??

 

어쨌든 section과 cell을 구현해보죠!!

 

이번에 구현할 section과 cell입니다.

움짤인데, 어떻게 구현해야 하는지 감이 오나요???

한번 생각해보고 스크롤을 내려보세요.

.

.

.

.

.

.

.

.

.

.

.

.

.

 

 

header - 리뷰 정보를 보여주는 영역

 

cell - 리뷰 text를 보여주는 영역

생각한것과 같나요? 저는 header와 cell을 나눠서 구현했습니다.

더 좋은 방법이 있으면 알랴주세요! 

 

참고로 header는 지난 글에서 구현한 header를 상속할거에요.

상단의 lineview와 large title, button이 동일하죠?

상속하여 사용하고 있습니다!! 큰 그림은 아니지만, 개발전에 app store 앱을 뜯어보면서 계획했죠 흐흐흫

 

------------------------------------------------------------------------------------------------------------------

 

그럼 역시 section 구현부터 갈게요.

 

315라인 : item 입니다.

 

320라인 : group 입니다.

 

326라인 : section 입니다. 페이징 스크롤 구현했습니다.

 

331라인 : header입니다!

 

------------------------------------------------------------------------------------------------------------------

 

귤을 먹으며 작성중인데, 귤이 달달하네요 뀰?

 

리뷰 헤더 입니다.

500라인 : 헤더 text를 세팅했습니다.

 

504라인 : 헤더 리뷰 정보를 세팅했습니다.

 

------------------------------------------------------------------------------------------------------------------

 

header부터 살펴볼까요



12라인 : "3.3"으로 표시되는 평점 Label입니다.

 

19라인 : 우측에 보이는 별 모양과 progressView입니다. stackView에요.

어떻게 짜야 잘짰다고 소문날지 고민했었는데요, 음.......

horizontal stackView에 별 label과 progressView를 추가하고,

이를 vertical stackView에 추가했어요.

이렇게 horizontal stackView를 다섯번 추가하여 레이아웃을 구성했어요!

다른 방법으로도 구현해봤지만, 해당 방법이 젤 깔끔했어요.

 

57라인 : "3.3" 아래에 위치하는 Label입니다.

 

63라인 : 우측 하단에 위치하는 label입니다.

 

69라인 : 이니셜라이저입니다.

 

81라인 : 스냅킷으로 레이아웃 제약사항을 구성했습니다.

스냅킷으로 샤샤샥 배치해주세요

 

123라인 : 버튼 동작인데, 선언만 하고 구현하진 않았습니다.

 

127라인 : 헤더 정보를 설정합니다.

 

이렇게 하여, Header를 구현했습니다!

 

------------------------------------------------------------------------------------------------------------------

 

이번엔 cell을 구현해볼까요

 

저는 아주 간단하게 단순 label로 구현했습니다.

 

12라인 : textLabel입니다.

 

21라인 : 이니셜라이저입니다.

 

31라인 : 레이아웃을 구성합니다.

 

42라인 : 셀 정보를 설정합니다.

 

------------------------------------------------------------------------------------------------------------------

 

오늘도 이렇게 section과 cell을 구현해봤습니다.

 

어떠신가요 얼마 안남았습니다 같이 화이팅 해요!!

 

 

잘못되거나 부족한 내용 등, 피드백 감사합니다!

 

Skillist의 AppleAppStore 프로젝트

https://github.com/DeveloperSkillist/AppleAppStoreCloneCode

 

GitHub - DeveloperSkillist/AppleAppStoreCloneCode: AppleAppStoreCloneCode

AppleAppStoreCloneCode. Contribute to DeveloperSkillist/AppleAppStoreCloneCode development by creating an account on GitHub.

github.com

 

 

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓  전체 코드  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    private func createReviewSection() -> NSCollectionLayoutSection {
        let itemMargin: CGFloat = 5
        let sectionMargin: CGFloat = 15
        
        //item
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = .init(top: itemMargin, leading: itemMargin, bottom: itemMargin, trailing: itemMargin)
        
        //group
        let width = (self.view.frame.width - (sectionMargin * 2))
        let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(width), heightDimension: .absolute(width * 0.7))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
//        group.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0)
        
        //section
        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = .groupPaging
        section.contentInsets = .init(top: sectionMargin, leading: sectionMargin, bottom: sectionMargin, trailing: sectionMargin)
        
        //header
        let sectionHeader = createHeader()
        section.boundarySupplementaryItems = [sectionHeader]
        
        return section
    }
            case .review:
                guard let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "DetailReviewHeaderView", for: indexPath) as? DetailReviewHeaderView else {
                    return UICollectionReusableView()
                }
                headerView.setupLargeTitleData(
                    largeTitleText: "app_review_title".localized,
                    largeButtonText: "show_all_title".localized
                )
                if let item = item {
                    headerView.setupItem(
                        rate: String(round(item.averageUserRating * 10)/10),
                        ratingCount: item.userRatingCount
                    )
                }
                return headerView
class DetailReviewHeaderView: DetailLargeTitleWithButtonHeaderView {
    
    private lazy var reviewRateText: UILabel = {
        var label = UILabel()
        label.font = .systemFont(ofSize: 80, weight: .bold)
        label.textColor = .label
        return label
    }()
    
    private lazy var reviewRateView: UIStackView = {
        var stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 5
        
        for starNum in 0...4 {
            var view = UIStackView()
            view.axis = .horizontal
            view.spacing = 10
            
            var starStr = ""
            for _ in 1...(5-starNum) {
                starStr.append("★")
            }
            let starView = UILabel()
            starView.text = starStr
            starView.textColor = .gray
            starView.textAlignment = .right
            starView.font = .systemFont(ofSize: 8)
            starView.snp.makeConstraints {
                $0.width.equalTo(55)
                $0.height.equalTo(10)
            }
            view.addArrangedSubview(starView)
            
            let progressView = UIProgressView()
            progressView.progressTintColor = .gray
            progressView.progress = .random(in: 0...1)
            progressView.snp.makeConstraints {
                $0.height.equalTo(5)
            }
            view.addArrangedSubview(progressView)
            
            stackView.addArrangedSubview(view)
        }
        return stackView
    }()
    
    private lazy var reviewSmallText: UILabel = {
        var label = UILabel()
        label.font = .systemFont(ofSize: 20, weight: .bold)
        return label
    }()
    
    private lazy var reviewNumbersText: UILabel = {
        var label = UILabel()
        label.font = .systemFont(ofSize: 20)
        return label
    }()
        
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupReviewLayout()
        
        setupAction()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupReviewLayout() {
        largeTitleLabel.snp.removeConstraints()
        largeTitleLabel.snp.makeConstraints {
            $0.top.equalTo(lineView.snp.bottom).offset(10)
            $0.leading.equalToSuperview().inset(2.5)
            $0.trailing.equalTo(largeButton.snp.leading).offset(-10)
            $0.height.equalTo(30)
        }
        
        [
            reviewRateText,
            reviewRateView,
            reviewSmallText,
            reviewNumbersText
        ].forEach {
            addSubview($0)
        }
                
        reviewRateText.snp.makeConstraints {
            $0.top.equalTo(largeTitleLabel.snp.bottom).offset(10)
            $0.leading.equalTo(largeTitleLabel)
            $0.trailing.equalTo(reviewRateView.snp.leading).offset(-10)
            $0.height.equalTo(80)
        }
        
        reviewRateView.snp.makeConstraints {
            $0.trailing.equalToSuperview().inset(2.5)
            $0.centerY.equalTo(reviewRateText)
        }
        
        reviewSmallText.snp.makeConstraints {
            $0.centerX.equalTo(reviewRateText)
            $0.top.equalTo(reviewRateText.snp.bottom)
            $0.bottom.equalToSuperview()
        }
        
        reviewNumbersText.snp.makeConstraints {
            $0.top.bottom.equalTo(reviewSmallText)
            $0.trailing.equalTo(reviewRateView)
        }
    }
    
    private func setupAction() {
        
    }
    
    func setupItem(rate: String, ratingCount: Int) {
        reviewRateText.text = rate
        reviewSmallText.text = "app_review_max_rate".localized
        reviewNumbersText.text = "\(ratingCount)" + "app_review_rate_count".localized
    }
}
class DetailReviewCollectionViewCell: UICollectionViewCell {
    
    private lazy var reviewText: UILabel = {
        var label = UILabel()
        label.font = .systemFont(ofSize: 15)
        label.textColor = .label
        label.numberOfLines = 0
        label.textAlignment = .natural
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupLayout()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupLayout() {
        addSubview(reviewText)
        
        reviewText.snp.makeConstraints {
            $0.edges.equalToSuperview().inset(10)
        }
        
        self.layer.cornerRadius = 10
        self.backgroundColor = UIColor(named: "lightgray,darkgray")
    }
    
    func setupItem(text: String) {
        reviewText.text = "리뷰 영역입니다.\n하지만, 리뷰 관련 데이터가 없어,\ndevice 목록을 보여줍니다.\n\n\(text)"
    }
}
반응형