Skip to content

Latest commit

 

History

History
286 lines (228 loc) · 11.9 KB

[1주차] KakaoPay.md

File metadata and controls

286 lines (228 loc) · 11.9 KB

1주차 카카오페이💰

전체 코드

구현하려던 UI 구현한 UI(BoxLayout) 추가 구현한 UI(BoxRowLayout) 추가 구현한 UI(BoxGridLayout)
스크린샷 2023-01-25 오후 11 45 07 스크린샷 2023-01-25 오후 11 45 56 스크린샷 2023-01-25 오후 11 46 26

1️⃣ BoxView

BoxView를 BoxType으로 나누어 UI 적용

스크린샷 2023-01-26 오후 9 34 08

enum BoxType {
    case large // 노랑색, 금액 나오는 가장 큰 박스
    case normal // 검정색, 작은 박스
    case recentPayment // 검정색, 하단 가장 최근 결제
}

struct BoxView: View {
    var title: String
    var subTitle: String
    var boxType: BoxType
    var largeImageSize: CGFloat = 40
    var smallImageSize: CGFloat = 30
    
    var body: some View {
        GeometryReader { geometryProxy in
            VStack(alignment: .leading, content: {
                Text(title)
                    .font(boxType == .normal ? .headline:  .system(size: 26).bold())
                    .foregroundColor(boxType == .large ? .black : .white)
                    .offset(x: 10)
                    .padding(EdgeInsets(top: 16, leading: 0, bottom: 1, trailing: 0))
                
                Text(subTitle)
                    .font(.subheadline)
                    .foregroundColor(boxType == .large ? Color.gray : Color.white.opacity(0.5))
                    .offset(x: 10)
                
                VStack(alignment: .trailing, content: {
                    Image(systemName: "camera")
                        .resizable()
                        .scaledToFit()
                        .frame(width: boxType == .large ? largeImageSize : smallImageSize, height: boxType == .large ? largeImageSize : smallImageSize)
                        .foregroundColor(Color.white.opacity(0.5))
                })
                .frame(
                    minWidth: 0,
                    maxWidth: .infinity,
                    minHeight: 0,
                    maxHeight: .infinity,
                    alignment: .bottomTrailing
                )
                .padding(EdgeInsets(top: 0, leading: 0, bottom: 16, trailing: 16))
            })
            .frame(
                minWidth: 0,
                maxWidth: .infinity,
                minHeight: 0,
                maxHeight: .infinity,
                alignment: .topLeading
            )
            .background(boxType == .large ? Color.yellow : Color.black)
        }
    }
}

// BoxView 자체에 radius와 shadow를 주기 위한 modifier
struct BoxModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .cornerRadius(12)
            .shadow(color: Color(.systemGray4), radius: 8)
    }
}

2️⃣ contentView 안에서 레이아웃 적용

stack뷰의 조합으로 만들어보려 했는데, 각각의 frame 사이즈를 이런 직접적으로 적용하는건 비효율적인 것 같아서 Layout으로 수정
스크린샷 2023-01-24 오후 3 53 58

VStack {
    HStack {
        BoxView(title: "4,200원", subTitle: "카카오페이머니", boxType: .large).modifier(BoxModifier())
            .frame(width: (UIScreen.main.bounds.width - 40)*2/3)
        VStack {
            BoxView(title: "선택하기", subTitle: "송금", boxType: .normal).modifier(BoxModifier())
            BoxView(title: "선택하기", subTitle: "결제", boxType: .normal).modifier(BoxModifier())
        }
    }
    BoxView(title: "iTunes&App Store", subTitle: "3,000원", boxType: .recentPayment)
        .modifier(BoxModifier())
        .frame(height: 140)
}
.frame(height: 420, alignment: .top)
.padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20))

3️⃣ Layout 커스텀

WWDC 영상 참고

*iOS 16.0부터 사용 가능
스크린샷 2023-01-24 오후 8 52 07

스크린샷 2023-01-26 오후 9 42 40

// Layout, ProposedViewSize 16.0부터 가능
struct BoxLayout: Layout {
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        proposal.replacingUnspecifiedDimensions()
    }
    
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        guard !subviews.isEmpty else { return }
        
        let spacing: CGFloat = 10
        let minSize = CGSize(width: (bounds.width - spacing * 2) / 3, height: (bounds.height - spacing * 2) / 3)
        let midSize = CGSize(width: bounds.width, height: minSize.height)
        let maxSize = CGSize(width: minSize.width * 2 + spacing, height: minSize.height * 2 + spacing)
        
        let x = bounds.minX
        let y = bounds.minY
        
        var sizeProposal = ProposedViewSize(maxSize)
        
        for index in subviews.indices {
            switch index {
            case 0:
                subviews[index].place(at: CGPoint(x: x, y: y),
                                      anchor: .topLeading,
                                      proposal: sizeProposal)
            case 1:
                sizeProposal = ProposedViewSize(minSize)
                subviews[index].place(at: CGPoint(x: x + maxSize.width + spacing, y: y),
                                      anchor: .topLeading,
                                      proposal: sizeProposal)
            case 2:
                sizeProposal = ProposedViewSize(minSize)
                subviews[index].place(at: CGPoint(x: x + maxSize.width + spacing, y: y + minSize.height + spacing),
                                      anchor: .topLeading,
                                      proposal: sizeProposal)
            case 3:
                sizeProposal = ProposedViewSize(midSize)
                subviews[index].place(at: CGPoint(x: x, y: y + maxSize.height + spacing),
                                      anchor: .topLeading,
                                      proposal: sizeProposal)
            default:
                break
            }
        }
    }
}
BoxLayout {
    BoxView(title: "4,200원", subTitle: "카카오페이머니", boxType: .large).modifier(BoxModifier())
    BoxView(title: "선택하기", subTitle: "송금", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "선택하기", subTitle: "결제", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "iTunes&App Store", subTitle: "3,000원", boxType: .recentPayment).modifier(BoxModifier())
}
.padding()
.frame(height: 420)

4️⃣ 추가 Layout 커스텀

BoxRowLayout

스크린샷 2023-01-25 오후 11 45 56

struct BoxRowLayout: Layout {
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        proposal.replacingUnspecifiedDimensions()
    }
    
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        guard !subviews.isEmpty else { return }
        
        let subviewsCount: CGFloat = 3
        
        let spacing: CGFloat = 10
        let size = CGSize(width: (bounds.width - spacing * 2) / subviewsCount, height: bounds.height)
        
        var x = bounds.minX
        
        for index in subviews.indices {
            subviews[index].place(at: CGPoint(x: x, y: bounds.minY),
                                  anchor: .topLeading,
                                  proposal: ProposedViewSize(size))
            x += size.width + spacing
        }
    }
}
VStack(spacing: 10) {
    BoxView(title: "16P", subTitle: "카카오페이포인트", boxType: .recentPayment).modifier(BoxModifier())
        .frame(height: 140)
    BoxRowLayout {
        BoxView(title: "선택하기", subTitle: "송금", boxType: .normal).modifier(BoxModifier())
        BoxView(title: "선택하기", subTitle: "결제", boxType: .normal).modifier(BoxModifier())
        BoxView(title: "iTunes&App Store", subTitle: "3,000원", boxType: .normal).modifier(BoxModifier())
    }
    .frame(height: 140)
    BoxRowLayout {
        BoxView(title: "선택하기", subTitle: "송금", boxType: .normal).modifier(BoxModifier())
        BoxView(title: "선택하기", subTitle: "결제", boxType: .normal).modifier(BoxModifier())
        BoxView(title: "iTunes&App Store", subTitle: "3,000원", boxType: .normal).modifier(BoxModifier())
    }
    .frame(height: 140)
}
.padding()

BoxGridLayout

스크린샷 2023-01-26 오전 12 01 18 스크린샷 2023-01-26 오전 12 03 33

struct BoxGridLayout: Layout {

    let rowitemCount: Int
    
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        proposal.replacingUnspecifiedDimensions()
    }
    
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        guard !subviews.isEmpty else { return }
        
        let spacing: CGFloat = 10
        let length = (bounds.width - spacing * CGFloat((rowitemCount - 1))) / CGFloat(rowitemCount)
        
        var x = bounds.minX
        var y = bounds.minY
        
        for index in subviews.indices {
            subviews[index].place(at: CGPoint(x: x, y: y),
                                  anchor: .topLeading,
                                  proposal: ProposedViewSize(CGSize(width: length, height: length)))
            if index % rowitemCount == rowitemCount - 1 {
                x = bounds.minX
                y += length + spacing
            } else {
                x += length + spacing
            }
        }
    }
}
BoxGridLayout(rowitemCount: 3) {
    BoxView(title: "선택하기", subTitle: "송금", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "선택하기", subTitle: "결제", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "iTunes&App Store", subTitle: "3,000원", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "선택하기", subTitle: "송금", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "선택하기", subTitle: "결제", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "iTunes&App Store", subTitle: "3,000원", boxType: .normal).modifier(BoxModifier())
    BoxView(title: "선택하기", subTitle: "결제", boxType: .normal).modifier(BoxModifier())
}
.padding()