0Pricing
Swift Academy · บทเรียน

พื้นฐานโพรโทคอล Layout

ใช้งาน sizeThatFits และ placeSubviews

พื้นฐานโพรโทคอล Layout เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงต้องใช้การจัดวางแบบกำหนดเอง

SwiftUI มี HStack, VStack และ ZStack มาให้ แต่บางครั้งคุณต้องใช้ตรรกะการจัดวางที่สิ่งเหล่านี้แสดงออกไม่ได้ เช่น เมนูวงกลม การจัดวางแบบไหล และตารางแบบก่ออิฐ

โปรโตคอลการจัดวางช่วยให้คุณเขียนตรรกะนั้นได้ พร้อมยังประกอบใช้งานร่วมกับมุมมอง SwiftUI ปกติ

โปรโตคอลการจัดวาง

Layout ต้องมีสองเมธอด ได้แก่ sizeThatFits (ฉันควรมีขนาดเท่าใด) และ placeSubviews (ลูกแต่ละตัวควรอยู่ที่ใด)

คุณทำให้ชนิดค่าเป็นไปตามโปรโตคอล แล้วใช้งานเหมือนสแตกในตัวทั่วไป

struct MyLayout: Layout {
    func sizeThatFits(proposal: ProposedViewSize,
                      subviews: Subviews,
                      cache: inout ()) -> CGSize { .zero }
    func placeSubviews(in bounds: CGRect,
                       proposal: ProposedViewSize,
                       subviews: Subviews,
                       cache: inout ()) { }
}

การใช้การจัดวางแบบกำหนดเอง

ค่าของ Layout ทำหน้าที่เป็นคอนเทนเนอร์ คุณส่งมุมมองลูกเข้าไปในคลอสเชอร์ต่อท้ายของมันได้เหมือนกับสแตก

var body: some View {
    MyLayout {
        Text("One")
        Text("Two")
        Text("Three")
    }
}

ProposedViewSize

มุมมองแม่เสนอขนาดให้การจัดวางของคุณผ่าน ProposedViewSize ค่า width และ height เป็นค่าทางเลือก โดย nil หมายถึง "ไม่ได้ระบุ ให้เลือกขนาด ideal ของคุณเอง"

ค่าพิเศษ .zero, .infinity และ .unspecified ใช้ตรวจสอบขนาดต่ำสุด สูงสุด และ ideal ตามลำดับ

func sizeThatFits(proposal: ProposedViewSize,
                  subviews: Subviews,
                  cache: inout ()) -> CGSize {
    let width = proposal.width ?? 0
    return CGSize(width: width, height: 44)
}

sizeThatFits โดยละเอียด

sizeThatFits คืนค่าขนาดที่การจัดวางของคุณต้องการเมื่อได้รับข้อเสนอขนาดหนึ่ง SwiftUI อาจเรียกเมธอดนี้หลายครั้งด้วยข้อเสนอที่แตกต่างกัน เพื่อทำความเข้าใจความยืดหยุ่นของคุณ

func sizeThatFits(proposal: ProposedViewSize,
                  subviews: Subviews,
                  cache: inout ()) -> CGSize {
    // Sum child ideal sizes for a simple horizontal stack
    let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
    let w = sizes.reduce(0) { $0 + $1.width }
    let h = sizes.map(\.height).max() ?? 0
    return CGSize(width: w, height: h)
}

คอลเลกชันของมุมมองย่อย

Subviews คือคอลเลกชันของพร็อกซีสำหรับลูกแต่ละตัว พร็อกซีแต่ละตัวตอบ sizeThatFits และเปิดเผยลำดับความสำคัญของการจัดวางกับค่ากำหนดเอง

คุณจะไม่เห็นมุมมองจริง แต่จะเห็นเพียงพร็อกซีสำหรับการวัดขนาดเหล่านี้

for subview in subviews {
    let size = subview.sizeThatFits(.unspecified)
    print(size)
}

placeSubviews

placeSubviews กำหนดตำแหน่งให้ลูกแต่ละตัวภายในสี่เหลี่ยม bounds ที่ส่งให้คุณ

เรียก place(at:anchor:proposal:) บนพร็อกซีของมุมมองย่อยแต่ละตัว

func placeSubviews(in bounds: CGRect,
                   proposal: ProposedViewSize,
                   subviews: Subviews,
                   cache: inout ()) {
    var x = bounds.minX
    for subview in subviews {
        let size = subview.sizeThatFits(.unspecified)
        subview.place(at: CGPoint(x: x, y: bounds.midY),
                      anchor: .leading,
                      proposal: .unspecified)
        x += size.width
    }
}

จุดยึดขณะวาง

พารามิเตอร์ anchor ระบุว่าจุดใดของลูกจะตรงกับตำแหน่งที่คุณกำหนด .topLeading จะวางโดยใช้มุมซ้ายบน ส่วน .center จะจัดลูกให้อยู่กึ่งกลางตรงตำแหน่งนั้น

subview.place(at: CGPoint(x: 0, y: 0),
              anchor: .topLeading,
              proposal: .unspecified)

ขอบเขตไม่ได้อยู่ที่จุดกำเนิดเสมอไป

สี่เหลี่ยม bounds อาจไม่ได้เริ่มต้นที่ (0,0) ให้จัดตำแหน่งโดยอ้างอิงจาก bounds.minX และ bounds.minY เสมอ อย่าใช้ศูนย์สัมบูรณ์

let startX = bounds.minX // not 0
let startY = bounds.minY

การจัดวางแบบเว้นระยะเท่ากันอย่างง่าย

เมื่อนำทุกอย่างมารวมกัน นี่คือการจัดวางที่วางลูกจากซ้ายไปขวาโดยไม่มีระยะห่าง เมธอดทั้งสองยังคงสอดคล้องกัน ขนาดที่รายงานตรงกับตำแหน่งที่วาง

struct SimpleHStack: Layout {
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
        return CGSize(width: sizes.reduce(0){ $0 + $1.width },
                      height: sizes.map(\.height).max() ?? 0)
    }
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        var x = bounds.minX
        for s in subviews {
            let size = s.sizeThatFits(.unspecified)
            s.place(at: CGPoint(x: x, y: bounds.minY), anchor: .topLeading, proposal: .unspecified)
            x += size.width
        }
    }
}

คุณต้องรักษาความสอดคล้อง

SwiftUI เชื่อว่าเมธอดทั้งสองของคุณให้ผลสอดคล้องกัน หาก placeSubviews ใช้พื้นที่มากกว่าที่ sizeThatFits รายงาน ลูกอาจถูกตัดหรือซ้อนทับกัน

ใช้การคำนวณเรขาคณิตชุดเดียวกันร่วมกันในเมธอดทั้งสอง

ตรวจสอบความเข้าใจ: พื้นฐานการจัดวาง

ทดสอบความเข้าใจของคุณเกี่ยวกับโปรโตคอลการจัดวาง

สรุป: พื้นฐานโปรโตคอลการจัดวาง

โปรโตคอล Layout เปลี่ยนตรรกะการจัดวางแบบกำหนดเองให้เป็นคอนเทนเนอร์ที่นำกลับมาใช้ใหม่ได้ sizeThatFits รายงานขนาดของคุณสำหรับ ProposedViewSize และ placeSubviews จัดตำแหน่งพร็อกซีของลูกแต่ละตัวภายใน bounds โดยใช้ place(at:anchor:proposal:)

ข้อเสนอจะมีมิติที่เป็นค่าทางเลือก ขอบเขตอาจมีจุดเริ่มต้นเยื้องจากจุดกำเนิด และเมธอดทั้งสองต้องรักษาความสอดคล้องทางเรขาคณิต ต่อไปเราจะวัดขนาดมุมมองย่อยในรายละเอียด

คำถามที่พบบ่อย

บทเรียน “พื้นฐานโพรโทคอล Layout” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “พื้นฐานโพรโทคอล Layout” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “พื้นฐานโพรโทคอล Layout”

ใช้งาน sizeThatFits และ placeSubviews คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “พื้นฐานโพรโทคอล Layout” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐานโพรโทคอล Layout
  2. การวัดมุมมองย่อย
  3. การสร้างการจัดวางแบบไหล
  4. แคชการจัดวางและประสิทธิภาพ
← กลับไปที่ Swift Academy