【초보자】Swift UI를 공부한다 그 ⑩ ーー disabled와 DispatchQueue 애니메이션을 더욱 자유롭게

소개



지난번은 선택한 Card를 탭하면 리스트 리스트를 낼 수 있도록 했습니다.
그러나 선택한 courses는 고정된 채로 이번에는 각각의 Card를 각각의 리스트를 낼 수 있도록 합니다.

완성품↓
 

목차



  • disabled 및 DispatchQueue
  • 요약
  • 참고문헌


  • disabled 및 DispatchQueue · 우선 Course.swift Course를 새로 만든 Model Group으로 이동합니다. ( MVVM )
    ・현상에서는, show 가 true인지flase인지를 조건으로 하여 Card의 상태를 관리하고 있습니다.
    모든 카드는 자신이 가진 목록을 인식하도록 먼저 seletedItem를 만듭니다.
    디폴트로 nil( Optional )을 붙여, Card가 아직 선택되어 있지 않은 상태를 의미합니다.

    CoursesView.swift
    
    @State var show = false
    @Namespace var namespace
    @State var selectedItem: Course? = nil
    
    

    · 탭 제스처는 여전히 루프 밖에 있기 때문에 카드 안으로 이동합니다.
    또한 어떤 카드를 탭했는지 알기 위해 클로저의 itemselectedItem에 붙입니다.

    CoursesView.swift
    
    ForEach(courses) { item in
        CourseItem(course: item)
            .matchedGeometryEffect(
                   id: item.id, in: namespace, isSource: !show
            )
               .frame(width: 335, height: 250)
               .onTapGesture {
                      withAnimation(.spring()) {
                             show.toggle()
                             selectedItem = item
                       }
                }
    }
    
    

    ・Card중의 List는↑위로부터 selectedItem를 받고, 자신전속의 리스트 겟트 할 수 있게 되었습니다.
    ・단지, 지금은 Card를 열 수 밖에 할 수 없고, 닫을 경우는 Card와 같이, List도 onTapGesture() 를 사용합니다. 또, Card를 닫음으로써, selectedItem 필요없게 되므로, nil를 붙여 갑니다.

    CoursesView.swift
    
    if selectedItem != nil {
         ScrollView {
              CourseItem(course: selectedItem!)
                   .matchedGeometryEffect(
                        id: selectedItem!.id, in: namespace
                    )
                   .frame(height: 300)
                   .onTapGesture {
                        withAnimation(.spring()) {
                              show.toggle()
                              selectedItem = nil
                         }
                    }
    .......
    



    ・이것으로 9할을 할 수 있었습니다만, 탭하는 스피드가 너무 빠르면, Card와 Card가 겹쳐 버립니다.
    해결하는 로직도 간단합니다만, Card①의 애니메이션이 끝날 때까지 다른 Card를 disable로 합니다.

    CoursesView.swift
    
    @State var isDisabled = false
    
    ForEach(courses) { item in
        CourseItem(course: item)
            .matchedGeometryEffect(
                   id: item.id, in: namespace, isSource: !show
            )
               .frame(width: 335, height: 250)
               .onTapGesture {
                      withAnimation(.spring()) {
                             show.toggle()
                             selectedItem = item
                             isDisabled = true
                       }
                }
                .disabled(isDisabled)
    }
    
    

    · 마찬가지로, 카드 안에서 disable로 했으므로 List에서 disable을 제거합니다.
    DispatchQueue 를 사용하여 애니메이션을 자유롭게 늦출 수 있으므로 0.5초를 늦추면 깨끗하게 할 수 있었습니다.

    CoursesView.swift
    
    if selectedItem != nil {
         ScrollView {
              CourseItem(course: selectedItem!)
                   .matchedGeometryEffect(
                        id: selectedItem!.id, in: namespace
                    )
                   .frame(height: 300)
                   .onTapGesture {
                        withAnimation(.spring()) {
                              show.toggle()
                              selectedItem = nil
                              DispatchQueue.main.asyncAfter(
                                   deadline: .now() + 0.5
                               ) {
                                   isDisabled = false
                                }
                         }
                    }
    .......
    

    요약 소스 코드 Github

    참고문헌
  • Design Code --- SwiftUI for iOS 14
  • 좋은 웹페이지 즐겨찾기