본문 바로가기
Projects/Swift

Swift :: 버스시간표 앱을 만들기 - 5 [ 스플래시 화면 ]

by 앱병찬 2024. 12. 12.

이제 앱 들어가면 실행되는 스플래시 화면을 만들어볼 것이다

@State private var isActive = false
@State private var circleOpacity: Double = 0.3
@State private var circleScale: CGFloat = 0.5
@State private var textOpacity: Double = 0.0

@State

- 뷰의 상태를 저장하고, 상태가 변경될 때 UI를 업데이트하는 데 사용

- 뷰 내에서만 상태를 저장하며, 상태값이 변경되면 뷰가 다시 그려진다.

isActive

- 스플래시 화면에서 메인 화면으로 전환되는 지를 제어

- false : 스플래시 화면을 표시

- true : 메인화면(ContentView())로 전환

circleOpacity

- 원의 투명도를 제어

- 값: 투명 0.0 ~ 1.0 불투명

circleScale

- 원의 크기 제어

- 크기: 기본 1.0 ~ 0.5 절반

textOpacity

- 텍스트의 투명도 제어

- 투명 0.0~1.0 불투명

 

* CGFloatCore Graphics Framework에서 사용하는 부동소수점 데이터 타입 ( 화면상 크기, 위치, 비율 등을 표현하기 위해 쓰임)


if isActive {
            ContentView()
        } else {
  • isActive 가 true면 ContentView()로 전환

ZStack {
                Color.black // 배경색
                    .ignoresSafeArea()
                
                // 애니메이션 배경 원
                Circle()
                    .fill(Color.blue)
                    .scaleEffect(circleScale)
                    .opacity(circleOpacity)
                    .frame(width: 300, height: 300)
                    .onAppear {
                        withAnimation(
                            .easeInOut(duration: 1.0).repeatForever(autoreverses: true)
                        ) {
                            self.circleScale = 1.5
                            self.circleOpacity = 0.7
                        }
                    }
  • ZStack - 겹치기
  • Color.black - 배경색: 검은색
  • Circle() - 원
    .fill(Color.blue) - 파란색으로 칠해라
    .scaleEffect(circleScale) - 원의 크기를 circleScale값으로 조정( 애니메이션효과-크기 )
    .opacity(circleOpacity) - 원의 투명도를 circleOpacity 상태 값으로 조정( 애니메이션효과-투명도 )
    .frame(width : 300, height : 300) - 원의 초기값 크기
  • onAppear - 뷰가 화면에 나타날 때 실행되는 동작
    withAnimation - 애니메이션 효과 추가
    .easeInOut(duration: 1.0) - 1초동안 애니메이션이 천천히 시작하고 천천히 끝나는 효과
    .repeatForever(autoreverses: true) - 애니메이션 반복 / autoreverses: true - 애니메이션이 끝난 후 reverse된다. = 무한반복

    self.circleScale = 1.5 ( 초기값 0.5 -> 1.5로 크기 고정)
    self.circleOpacity = 0.7 ( 초기값: 0.3 -> 0.7 불투명)

 VStack {
                    Image(systemName: "bus.fill")
                        .font(.system(size: 80))
                        .foregroundColor(.white)
                    
                    Text("INOUTY")
                        .font(.system(size: 36))
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .opacity(textOpacity)
                        .onAppear {
                            withAnimation(.easeIn(duration: 1.5)) {
                                self.textOpacity = 1.0
                            }
                        }
                }
  • VStack - 수직으로 뷰 쌓기
  • Image(systemName : "bus.fill") - 버스 아이콘 불러오기
  • opacity(textOpacity) - textOpacity:  0.0 이므로 완전투명
  • .easeIn(duration:1.5) - easeIn(천천히 들어오다) 1.5초동안 천천히 불투명해짐
    textOpacity = 1.0 - 텍스트 색이 1.0(완전불투명)으로 변경됨 1.5초뒤에

.onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { // 시간 조정
                    withAnimation {
                        self.isActive = true
                    }
                }
            }
  • onAppear - 초기 설정, 애니메이션 시작
  • DispatchQueue.main.asyncAfter - 일정 시간 후 특정 작업을 실행하기 위해 사용
    (deadline: ~) - 비동기로 지연 실행을 처리
    .now() + 2.0:  현재 시간에서 2초 후
  • self.isActive = true - isActive 상태값을 true로 변경하여 ContentView()를 실행시킴

 


전체코드 : SplashScreenView.swift

import SwiftUI

struct SplashScreenView: View {
    @State private var isActive = false
    @State private var circleOpacity: Double = 0.3
    @State private var circleScale: CGFloat = 0.5
    @State private var textOpacity: Double = 0.0
    
    var body: some View {
        if isActive {
            ContentView()
        } else {
            ZStack {
                Color.black // 배경색
                    .ignoresSafeArea()
                
                // 애니메이션 배경 원
                Circle()
                    .fill(Color.blue)
                    .scaleEffect(circleScale)
                    .opacity(circleOpacity)
                    .frame(width: 300, height: 300)
                    .onAppear {
                        withAnimation(
                            .easeInOut(duration: 1.0).repeatForever(autoreverses: true)
                        ) {
                            self.circleScale = 1.5
                            self.circleOpacity = 0.7
                        }
                    }
                
                // 로고 및 텍스트
                VStack {
                    Image(systemName: "bus.fill")
                        .font(.system(size: 80))
                        .foregroundColor(.white)
                    
                    Text("INOUTY")
                        .font(.system(size: 36))
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .opacity(textOpacity)
                        .onAppear {
                            withAnimation(.easeIn(duration: 1.5)) {
                                self.textOpacity = 1.0
                            }
                        }
                }
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { // 시간 조정
                    withAnimation {
                        self.isActive = true
                    }
                }
            }
        }
    }
}