티스토리 뷰

UI는 데이터를 화면에 맞게 구성해서 보여주는 것도 중요하지만 사용자의 입력, 데이터의 변동에 따라 유동적으로 움직이는 효과가 굉장히 중요하다. 잘 만든 transition과 animation은 속도감도 주고 앱 자체의 완성도도 올려준다. PPT를 잘 만들려면 애니메이션이나 모핑 같은 기술을 사용해야 하는 것과 같다.

리스트를 만들어 볼 건데, 이 리스트는 간략하게 요약된 노드가 보이지만, 각 노드에 있는 버튼을 누르면 커지면서 세부 내용이 보이도록 할 거다.

 

우측에 있는 버튼을 누르면 노드가 커지면서 상세 내용이 보인다.

 

먼저 리스트를 채울 노드를 만들어 보자. Stack으로 레이아웃을 구성하고 우측에 버튼을 추가한다.

 

중요한 부분이 아니니 간단하게 구성한다.

 

showDetail이라는 변수를 추가해서 이 변수에 따라 노드에 제목만 표시할지, 세부 내용도 같이 표기할지 분기하도록 한다. 이 값을 실시간으로 바뀜에 따라 view의 상태도 따라서 바뀌도록 만든다. 원래는 view에 선언된 변수를 하위 view에서 접근할 수 없다. 하지만 @State라는 annotation을 사용하면 하위 view에서 값을 읽을 수 있도록 할 수 있다.

 

struct MyView: View {
	private var showDetail = false
	@State private var showLink = false

	var body: some View {
		Button (action: {
			self.showDetail.toggle()    // can't access
			self.showLink.toggle()      // can access to @State variable
		}) {
			// label
		}
	}
}
annotation에 대해서는 아직 완벽한 이해가 안돼서 다른 포스팅에 따로 공부해서 올려야겠다. 쉽게 말해서 변수나 함수에 어떤 태그를 붙여놓고, 컴파일 시점에 그 태그에 따라서 자동으로 코드를 만들어주는 것이라고 이해할 수 있을것 같다. 

@State
의 경우 외부에서 접근할 수 있도록 접근자들을 만들어준다고 한다.

요즘 UE4로 개인 프로젝트를 만들고 있는데 UE4에 있는 UPROPERTY()가 이런 것과 비슷하지 않을까 하는 생각이 든다.

showDetail이라는 변수를 제어 하면서, showDetail의 상태에 따라 변경되는 이미지를 가진 버튼을 만들자.

 

Button(action: {
	self.showDetail.toggle()    // @State varible
}) {
	Image(systemName: "chevron.right.circle")
		.imageScale(.large)
		.rotateEffect(.degree(showDetail ? 90 : 0))    // depends on showDetail's state
    .animation(.easeInOut)    // apply easeInOut animation 
		.padding()
}

 

label로 사용한 Image에 추가한 옵션들을 중에 showDetail에 따라 값이 달라지는 옵션을 추가했다. 만약 showDetail이 true면 90도 회전하고 반대라면 회전하지 않은 상태로 화면에 그린다. Animation은 이처럼 이미 화면에 있는 view의 상태가 변화할 때 적용할 수 있는 기능으로 animation이 적용될 수 있는 값이 A에서 B로 변한다면 정해진 delay동안 그 변화를 선형보간 한다.

 

두 값을 선형보간하면서 서서히 변화시킨다.

 

상태에 따라 변화하는 view가 한 개 거나, 여러 view가 각자 다른 animation으로 움직여야 할 때는 각자 설정하는 방법이 좋을 수도 있지만 상태에 따라 여러 view가 바뀌어야 한다면 매 번 animation을 추가하는 일은 코드도 길어질 뿐 아니라 여간 번거로운 일이 아니다.

 

Button(action: {
	withAnimation(.easeInOut) {    // apply to all views which depends on showDetail
		self.showDetail.toggle()
	}
}) {
	// label
}

 

showDetail을 변화시키는 연산 자체에 animation을 걸어버리면 showDetail의 변화 자체가 선형보간되기 때문에 이 값과 연결된 다른 값들이 같은 animation을 적용시킨것과 같은 효과를 낸다.

Transition은 화면에 없던 view가 새롭게 생성되거나 소멸할 때 상태를 정의한다. 좌표나 투명도를 정의할 수 있는데 이것 또한 view 상태가 바뀌는 것이기 때문에 animation의 재료가 되며, 필연적으로 묶여 있다.

 

animation이 없으면 의미가 없다.

 

상세 내용의 경우 화면에 없지만 버튼을 누르면 제목 밑에 생성되고, 다시 버튼을 누르면 화면에서 사라진다.

 

// ...Button...

if showDetail {
	Text("detail content")
		.transition(.slide)
}

 

이 Text view는 showDetail에 따라 화면에 추가될 수도, 소멸할 수도 있다. 이런 view에 적용할 수 있는 효과가 바로 transition이다. animation과 마찬가지로 transition도 기본으로 제공되는 몇가지를 사용할 수 있다. slide는 화면 양옆에서 등장하고 퇴장하는 효과를 만들어준다.

기본 제공 효과가 마음에 들지 않을 때는 AnyTransition 변수를 새롭게 만들 수 있다.

 

extension AnyTransition {
	// make global transition
	static moveAndFade: AnyTransition {
		let insertion = AnyTransition.move(edge: .trailing).combine(.opacity)
		let removal = AnyTransition.move(edge: .bottom).combine(.opacity)
		return .asymmetric(insertion: insertion, removal: removal)
	}
}

// ...

Text("detail content")
	.transition(.moveAndFade)

 

AnyTransition을 확장한 후 제공하는 기능들을 조합해서 새로운 효과를 만들 수 있다. 생성할 때 소멸할 때 다른 효과를 주기 위해서 asymmetric(비대칭) transition을 만들고, insertion(생성)과 removal(소멸)을 정의했다.

 

struct MyView: View {
	// make local transition
	var moveAndFade: AnyTransition {
			let insertion = AnyTransition.move(edge: .trailing).combine(.opacity)
			let removal = AnyTransition.move(edge: .bottom).combine(.opacity)
			return .asymmetric(insertion: insertion, removal: removal)
	}
}

 

굳이 전역에서 사용하는게 아니라면 View 내부에 로컬 변수로 정의하고 사용할 수도 있다.

이제 이 기능들을 활용할 수 있는 list를 만들어 보자.

 

// in ForEach loop...

let contentString = data[index]
let endIndex = contentString.index(contentString.startIndex, offsetBy: min(contentString.count - 1, 8))
let titleString = String(contentString[...endIndex]) + "..."

AlarmView(titleText: titleString, contentText: contentString)

낚시를 위해서 앞부분 내용만 조금 잘라서 타이틀로 사용한다.

 

결과

'Programming > SwiftUI' 카테고리의 다른 글

SwiftUI Beginner | Drawing Path  (0) 2020.10.29
SwiftUI Beginner | Sticky Header  (0) 2020.10.07
SwiftUI Beginner | 기초문법과 Navigation List  (0) 2020.09.15
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함