การเปลี่ยนผ่านใน SwiftUI · objc.io

 

ในระหว่างการประชุมเชิงปฏิบัติการ SwiftUI เรามักจะสังเกตเห็นว่ามีคนเพียงไม่กี่คนที่รู้เกี่ยวกับการเปลี่ยนภาพ แม้ว่าพวกเขาจะไม่ซับซ้อนและมีประโยชน์อย่างเหลือเชื่อ

การเปลี่ยนภาพเกิดขึ้นเมื่อมุมมองถูกลบออกจากแผนผังมุมมอง หรือเพิ่มลงในแผนผังมุมมอง อย่างไรก็ตาม หากคุณทำ SwiftUI เสร็จแล้ว คุณจะสังเกตเห็นว่าไม่มีทางจริงในการเพิ่มมุมมองให้กับแผนผังมุมมอง — ไม่มี addSubview(_:). คุณสามารถเพิ่มและลบมุมมองได้ผ่านการรวมกันของการเปลี่ยนแปลงสถานะและการใช้ an . เท่านั้น if คำสั่ง (หรือ switch หรือ ForEach). กล่าวอีกนัยหนึ่ง มุมมองจะถูกเพิ่มและลบให้เราโดยอัตโนมัติ แต่การเปลี่ยนจะทำงานเพียงครั้งเดียว ก่อนที่เราจะลงรายละเอียดในเรื่องนี้ เรามาพิจารณาการเปลี่ยนแปลงง่ายๆ ก่อน:

struct ContentView: View {
    @State var visible = false
    var body: some View {
        VStack {
            Toggle("Visible", isOn: $visible)
            if visible {
                Text("Hello, world!")
            }
        }
        .animation(.default, value: visible)
    }
}

เมื่อเราเรียกใช้โค้ดข้างต้น เราจะเห็นข้อความค่อยๆ เข้าและออก นี่คือการเปลี่ยนแปลงเริ่มต้น (.opacity). เมื่อมุมมองถูกแทรกลงในแผนผังมุมมอง มุมมองจะค่อยๆ จางลง และเมื่อนำออกแล้วจะค่อยๆ จางหายไป โปรดทราบว่าหาก body ดำเนินการอีกครั้ง มุมมองจะไม่จางหายไปอีกเว้นแต่เงื่อนไขใน if การเปลี่ยนแปลงคำสั่ง

เพื่อสร้างแบบจำลองทางจิตของสิ่งที่เกิดขึ้น เราสามารถพิจารณาแผนผังมุมมอง SwiftUI สำหรับมุมมองด้านบน:

มุมมอง SwiftUI นั้นชั่วคราว: เนื้อหาของ ContentView ถูกประหารชีวิตและจากมัน a เรนเดอร์ต้นไม้ ถูกสร้างขึ้น แผนผังการแสดงผลนี้จะคงอยู่ตลอดการอัปเดตมุมมอง และแสดงถึงมุมมองจริงบนหน้าจอ เมื่อต้นไม้แสดงผลได้รับการปรับปรุง ค่าสำหรับ body แล้วจากไป นี่คือแผนผังการแสดงผลหลังจากการเรนเดอร์ครั้งแรก:

เมื่อเราแตะสวิตช์ จะเกิดการเปลี่ยนแปลงสถานะและเนื้อความของ ContentView ดำเนินการอีกครั้ง ต้นไม้แสดงผลที่มีอยู่แล้วคือ อัพเดท. ในกรณีนี้ SwiftUI สังเกตว่า if สภาพเปลี่ยนจาก false ถึง trueและมันจะแทรกของเรา Text ดูต้นไม้แสดงผล:

การเปลี่ยนแปลงในแผนผังการแสดงผลคือสิ่งที่ทำให้เกิดการเปลี่ยนแปลง การเปลี่ยนภาพจะเคลื่อนไหวก็ต่อเมื่อธุรกรรมปัจจุบันมีภาพเคลื่อนไหว ในตัวอย่างข้างต้น .animation การโทรทำให้เกิดการเปลี่ยนแปลงเพื่อเคลื่อนไหว

แผนผังการแสดงผลไม่มีอยู่จริงกับชื่อหรือแบบฟอร์มนั้น แต่เป็นเพียงแบบจำลองสำหรับการทำความเข้าใจวิธีการทำงานของ SwiftUI เราไม่แน่ใจอย่างสมบูรณ์ว่าสิ่งเหล่านี้แสดงอย่างไรภายใต้ประทุน

เมื่อเราเปลี่ยนทัศนะเป็น if/else เงื่อนไข สิ่งต่าง ๆ น่าสนใจขึ้นเล็กน้อย นี่คือรหัส:

struct ContentView: View {
    @State var visible = false
    var body: some View {
        VStack {
            Toggle("Visible", isOn: $visible)
            if visible {
                Text("Hello, world!")
            } else {
                Image(systemName: "hand.wave")
            }
        }
        .animation(.default, value: visible)
    }
}

เมื่อเราสร้างโครงสร้างมุมมองเริ่มต้น มันจะประกอบด้วย a VStack กับ Toggle และ Text. เมื่อสถานะเปลี่ยนจาก false ถึง trueข้อความจะถูกแทนที่ด้วยรูปภาพ ในแผนผังมุมมองชั่วคราวจะมี Text หรือ Image, ไม่เคยทั้งสองอย่าง อย่างไรก็ตาม ในแผนผังการแสดงผล ในระหว่างแอนิเมชัน ต้นไม้จะมี ทั้งสองมุมมอง:

เนื่องจากเราใช้การเปลี่ยนค่าเริ่มต้น ดูเหมือนว่าข้อความจะค่อยๆ จางลงในรูปภาพและย้อนกลับ อย่างไรก็ตาม คุณอาจมองว่าเป็นช่วงการเปลี่ยนภาพแยกกัน: ข้อความมีช่วงการเปลี่ยนภาพลบออก (เฟดออก) และภาพมีการเปลี่ยนแทรก (เฟดอิน)


เราไม่ จำกัด เฉพาะการเปลี่ยนการจางหายเริ่มต้น ตัวอย่างเช่น นี่คือการเปลี่ยนที่เลื่อนเข้ามาจากขอบชั้นนำเมื่อแทรกมุมมอง และเอามุมมองออกโดยการลดขนาดลง:

let transition = AnyTransition.asymmetric(insertion: .slide, removal: .scale)

จากนั้นเราสามารถรวมเข้ากับ an .opacity (จาง) การเปลี่ยนแปลง ดิ .combined โอเปอเรเตอร์รวมทรานซิชันทั้งสองแบบขนานกันเพื่อให้ได้เอฟเฟกต์ต่อไปนี้:

let transition = AnyTransition.asymmetric(insertion: .slide, removal: .scale).combined(with: .opacity)
VStack {
    Toggle("Visible", isOn: $visible)
    if visible {
        Text("Hello, world!")
            .transition(transition)
    } else {
        Text("Hello world!")
            .transition(transition)
    }
}
.animation(.default.speed(0.5), value: visible)

โปรดทราบว่าในตัวอย่างข้างต้น เราใช้ a visible ค่าที่จะสลับไปมาระหว่างสอง Textถึงแม้ว่าพวกเขาจะเหมือนกันก็ตาม เราสามารถลดความซับซ้อนของโค้ดได้เล็กน้อยโดยใช้ id(_:). เมื่อไหร่ก็ตามที่คุณค่าที่เราส่งต่อไปยัง id การเปลี่ยนแปลง SwiftUI ถือว่านี่เป็นมุมมองใหม่ในแผนผังการแสดงผล เมื่อเรารวมสิ่งนี้เข้ากับความรู้เกี่ยวกับการเปลี่ยนภาพ เราสามารถทำให้เกิดการเปลี่ยนแปลงได้โดยการเปลี่ยน id ของมุมมอง ตัวอย่างเช่น เราสามารถเขียนตัวอย่างด้านบนใหม่ได้:

let transition = AnyTransition.asymmetric(insertion: .slide, removal: .scale).combined(with: .opacity)
VStack {
    Toggle("Visible", isOn: $visible)
    Text("Hello, world!")
        .id(visible)
        .transition(transition)
}
.animation(.default.speed(0.5), value: visible)

ก่อนที่แอนิเมชั่น จะมีข้อความ และระหว่างแอนิเมชั่น มุมมองที่แทรกใหม่ (ด้วย id(false)) ถูกเปลี่ยน และมุมมองเก่า (ด้วย id(true)) ถูกเปลี่ยนออก กล่าวอีกนัยหนึ่ง: มุมมองทั้งสองมีอยู่ในแอนิเมชัน:

See also  อัตราส่วนภาพใน SwiftUI


เมื่อทรานซิชันในตัวไม่ครอบคลุมความต้องการของคุณ คุณสามารถสร้างทรานซิชันแบบกำหนดเองได้ มี .modifier(active:identity) การเปลี่ยนแปลง เมื่อมุมมองไม่เปลี่ยน identity ตัวแก้ไขถูกนำไปใช้ เมื่อลบมุมมอง ภาพเคลื่อนไหวจะแทรกระหว่าง identity ตัวดัดแปลงและ active ตัวแก้ไขก่อนลบมุมมองทั้งหมด ในทำนองเดียวกัน เมื่อแทรกมุมมอง มุมมองจะเริ่มต้นด้วยตัวแก้ไขที่ทำงานอยู่เมื่อเริ่มต้นภาพเคลื่อนไหว และจบลงด้วยตัวแก้ไขข้อมูลประจำตัวที่ส่วนท้ายของภาพเคลื่อนไหว

ต่อไปนี้คือตัวอย่างปุ่มโปรดพร้อมการเปลี่ยนแบบกำหนดเอง นี่ไม่ใช่การใช้งานที่สมบูรณ์แบบ (เราจะไม่ฮาร์ดโค้ดออฟเซ็ตและความกว้างของปุ่ม) แต่มันแสดงให้เห็นว่าเป็นไปได้อย่างไร:

รหัสเต็มมีให้เป็นส่วนสำคัญ


บางครั้งเมื่อทำการเปลี่ยนแปลง คุณอาจเห็นผลข้างเคียงที่ไม่คาดคิด ในกรณีของเรา เรามักจะสามารถแก้ไขปัญหาเหล่านี้ได้โดยการตัดมุมมองที่เรากำลังเปลี่ยนภายในคอนเทนเนอร์ (ตัวอย่างเช่น VStack หรือ ZStack). ซึ่งจะเพิ่ม “ความเสถียร” บางอย่างให้กับแผนผังมุมมองที่สามารถช่วยป้องกันความบกพร่องได้

โดยพื้นฐานแล้ว การเปลี่ยนภาพไม่ซับซ้อนมากนัก อย่างไรก็ตาม การบรรลุผลที่คุณต้องการอาจเป็นเรื่องยากในบางครั้ง เพื่อให้ทำงานกับทรานซิชันได้อย่างมีประสิทธิภาพ คุณต้องเข้าใจความแตกต่างระหว่างแผนผังมุมมองและแผนผังการแสดงผล และเมื่อคุณต้องการมีทรานซิชันแบบกำหนดเอง คุณต้องเข้าใจวิธีการทำงานของแอนิเมชั่นด้วย เราครอบคลุมเรื่องนี้ทั้งในเวิร์กชอปและหนังสือ Thinking in SwiftUI ของเรา

หากบริษัทของคุณสนใจเวิร์กช็อปเกี่ยวกับ SwiftUI โปรดติดต่อ

By C-MTI