Trang chủ

Animation

Chuyện gì xảy ra giữa hai trạng thái

Trong SwiftUI bạn không bao giờ chạy animation cho một view. Bạn đổi một giá trị, và nói rằng những thay đổi của giá trị ấy nên được nội suy chứ đừng áp vào một phát.

Câu đó là toàn bộ chương này, và nó giải thích vì sao API trông lạ khi bạn đến từ UIKit. Không có lời gọi “chạy animation cho view này”, vì một view là một bản mô tả rồi bị vứt đi — chẳng có gì ở đó để mà animate. Thứ tồn tại lâu dài là giá trị, và animation thuộc về nó.

withAnimation(.spring) {
    isExpanded.toggle()
}

Không có gì trong khối đó nhắc đến một view. Nó đổi một Bool, và mọi view có bố cục hay diện mạo phụ thuộc vào cái Bool ấy đều nội suy từ chỗ nó đang ở tới chỗ nó giờ phải tới.

Vì sao điều này quan trọng hơn nghe có vẻ

Trong UIKit, một animation là một thứ bạn khởi động, và nó phải được hòa giải với bất cứ thứ gì khác đang chạy: hai animation trên cùng một thuộc tính thì đánh nhau, một animation bị ngắt thì giật phựt, và hủy một cái giữa chừng để lại cái layer ở trạng thái không ai định trước.

Trong SwiftUI, trạng thái hiện tại luôn là sự thật. Một animation là lộ trình đi từ sự thật cũ tới sự thật mới, nên ngắt nó không phải trường hợp đặc biệt — một thay đổi mới đơn giản là bắt đầu một lộ trình mới từ chỗ giá trị đang đứng. Các đường spring làm chuyện này trông đúng mà bạn chẳng phải cố gắng gì, và đó là lý do chúng là mặc định.

Hai chương

Ngầm định và tường minh nói về hai cách gắn một animation — .animation(_:value:) trên một view so với withAnimation bọc quanh một thay đổi — khi nào cái nào đúng, và vì sao cái modifier ấy mọc thêm tham số value:. Chương cũng nói về Animatable và cách một giá trị tự định nghĩa trở nên nội suy được, mảnh ghép biến animation từ một bộ đồ có sẵn thành thứ bạn mở rộng được.

Chuyển cảnh và matched geometry nói về việc view đi vào và đi ra chứ không phải thay đổi: .transition, vì sao nó cần một animation thì mới chạy, và matchedGeometryEffect cho trường hợp một view nên trông như di chuyển giữa hai chỗ trong cây thay vì mờ đi ở chỗ này rồi hiện lên ở chỗ kia.

Một quy tắc mang theo

Animation đi theo danh tính. Một view giữ nguyên danh tính thì chạy animation từ trạng thái cũ sang trạng thái mới của nó. Một view nhận danh tính mới là một view khác: cái cũ chuyển cảnh đi ra, cái mới chuyển cảnh đi vào, và không thuộc tính nào được nội suy giữa hai cái.

Mọi câu “sao nó nhảy phựt thay vì trượt?” đều là sự phân biệt đó. Trước khi với tới một đường cong gia tốc khác, hãy kiểm tra xem thứ bạn mong được chạy animation có còn là đúng cái view của một khung hình trước không — chương về danh tính là nơi chuyện đó được quyết.