[SwiftUI] CryptoApp: Expandable View

Junyoung Park·2022년 11월 4일
0

SwiftUI

목록 보기
91/136
post-thumbnail
post-custom-banner

https://www.youtube.com/watch?v=po4lRojJXdA&list=PLwvDm4Vfkdphbc3bgy_LpLRQ9DDfFGcFu&index=23

CryptoApp: Expandable View

구현 목표

  • 확장/축소 가능한 뷰 구현

구현 태스크

  • 코인 디테일 모델의 설명 프로퍼티 연결
  • 버튼을 통한 뷰 길이 토글링
  • 웹사이트 링크 연결

핵심 코드

coinDetailDataService
            .$coinDetails
            .sink { [weak self] coinDetails in
                self?.coinDescription = coinDetails?.readableDescription
                self?.websiteURL = coinDetails?.links?.homepage?.first
                self?.redditURL = coinDetails?.links?.subredditURL
            }
            .store(in: &cancellables)
  • 코인 디테일 모델을 구독하는 뷰 모델에서 뷰가 사용할 데이터를 퍼블리셔로 넘겨주는 addSubscription 함수의 일부분
private var descriptionSection: some View {
        ZStack {
            if
                let coinDescription = viewModel.coinDescription,
                !coinDescription.isEmpty {
                VStack(alignment: .leading) {
                    Text(coinDescription)
                        .lineLimit(showFullDescription ? nil : 3)
                        .font(.callout)
                        .foregroundColor(Color.theme.secondaryText)
                    Button {
                        withAnimation(.easeInOut) {
                            showFullDescription.toggle()
                        }
                    } label: {
                        Text(showFullDescription ? "Less" : "Read more...")
                            .font(.caption)
                            .fontWeight(.bold)
                    }
                    .tint(.blue)
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                
            }
        }
    }
  • @State로 선언한 showFullDescription 변수 값에 따라 현재 설명 텍스트 뷰를 보여줄 lineNumber를 결정 가능
  • 동적 연결을 위한 애니메이션 효과 적용

소스 코드

private var descriptionSection: some View {
        ZStack {
            if
                let coinDescription = viewModel.coinDescription,
                !coinDescription.isEmpty {
                VStack(alignment: .leading) {
                    Text(coinDescription)
                        .lineLimit(showFullDescription ? nil : 3)
                        .font(.callout)
                        .foregroundColor(Color.theme.secondaryText)
                    Button {
                        withAnimation(.easeInOut) {
                            showFullDescription.toggle()
                        }
                    } label: {
                        Text(showFullDescription ? "Less" : "Read more...")
                            .font(.caption)
                            .fontWeight(.bold)
                    }
                    .tint(.blue)
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                
            }
        }
    }
    
    private var websiteSection: some View {
        VStack(alignment: .leading, spacing: 20) {
            if
                let websiteURLString = viewModel.websiteURL,
                let url = URL(string: websiteURLString) {
                Link("Website", destination: url)
            }
            if let redditURLString = viewModel.redditURL,
               let url = URL(string: redditURLString) {
                Link("Reddit", destination: url)
            }
        }
        .tint(.blue)
        .frame(maxWidth: .infinity, alignment: .leading)
        .font(.headline)
    }
  • 설명 뷰뿐만 아니라 링크 정보 또한 핸들링
  • 링크를 통해 해당 URL로 연결

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글