หนึ่งในตัวดัดแปลงที่ทำให้ฉันงงเล็กน้อยคือ .aspectRatio
. มันทำงานอย่างไร? เมื่อฉันคิดออก มันกลับกลายเป็นง่ายกว่าที่ฉันคิด
ที่เดียวที่เราสามารถค้นพบวิธีการทำงานของ SwiftUI ได้มากมายคือ SwiftUI’s .swiftinterface
ไฟล์. ซึ่งอยู่ภายใน Xcode ภายในเทอร์มินัลของคุณ ไปที่ /Applications/Xcode.app
และดำเนินการคำสั่งต่อไปนี้:
find . -path "*/SwiftUI.framework*swiftinterface"
มีบางรุ่นของ .aspectRatio
API แต่ทั้งหมดนั้น ล้วนแต่เป็นการใช้งานครั้งเดียว:
func aspectRatio(_ aspectRatio: CGFloat?, contentMode: ContentMode) -> some View {
}
ตัวแปรกับ CGSize
เพียงแค่เรียกวิธีนี้ด้วย size.width/size.height
และ .scaledToFit
และ .scaledToFill
เรียกวิธีนี้ด้วยโหมดเนื้อหาที่เกี่ยวข้องและan aspectRatio
ของ nil
.
เมื่อเราเรียก aspectRatio
ด้วยอัตราส่วนภาพคงที่ เช่น .aspectRatio(16/9, contentMode: .fit)
การใช้อัตราส่วนกว้างยาวจะใช้ขนาดที่เสนอ และเสนอขนาดใหม่ให้กับองค์กรย่อย เมื่อโหมดเนื้อหาเป็น .fit
โดยจะพอดีกับสี่เหลี่ยมผืนผ้าที่มีอัตราส่วนกว้างยาวที่ต้องการภายในขนาดที่เสนอ ตัวอย่างเช่น เมื่อคุณเสนอ 100×100 มันจะเสนอ 100×56.2 ให้กับลูกของมัน เมื่อคุณเลือก .fill
แต่จะเสนอ 177.8×100 ให้กับลูกแทน
ฉันพบพฤติกรรมนี้โดยการพิมพ์ขนาดที่เสนอ เพิ่มเติมเกี่ยวกับที่ด้านล่าง
บางทีการใช้งานทั่วไปของ aspectRatio
รวมกับภาพที่ปรับขนาดได้ดังนี้:
Image("test")
.resizable()
.aspectRatio(contentMode: .fit)
นี้จะวาดภาพให้พอดีกับขนาดที่เสนอ โปรดทราบว่าเราไม่ได้ระบุอัตราส่วนภาพตามจริง: ได้มาจากภาพต้นแบบ
เมื่อเราไม่ระบุอัตราส่วนภาพคงที่แต่ใช้ nil
สำหรับพารามิเตอร์ ตัวแก้ไขอัตราส่วนกว้างยาวจะดูที่ ขนาดเหมาะ ของมุมมองพื้นฐาน นี่หมายความว่ามันเพียงแค่เสนอ nil×nil
ไปยังมุมมองพื้นฐาน และใช้ผลลัพธ์นั้นเพื่อกำหนดอัตราส่วนกว้างยาว ตัวอย่างเช่น เมื่อรูปภาพรายงานขนาดที่เหมาะสมที่สุดเป็น 100×50 อัตราส่วนภาพที่คำนวณได้คือ 100/50
.
กระบวนการยังดำเนินต่อไปเหมือนเมื่อก่อน: เมื่อเสนอมุมมอง 320×480 ภาพจะมีขนาดเป็น 320×160 เมื่อตั้งค่าโหมดเนื้อหาเป็น .fit
และ 960×480 เมื่อตั้งค่าโหมดเนื้อหาเป็น .fill
.
การหาขนาดที่เสนอ
ขนาดที่เสนอไม่ได้เป็นส่วนหนึ่งของ API สาธารณะของ SwiftUI แม้ว่าคุณจะต้องเข้าใจวิธีการทำงานนี้เพื่อเขียนเลย์เอาต์ที่มีประสิทธิภาพ แต่ก็ไม่ได้มีการบันทึกไว้จริงๆ สถานที่อย่างเป็นทางการเพียงแห่งเดียวที่มีการอธิบายพฤติกรรมนี้ในการพูดคุย WWDC ที่ยอดเยี่ยมในปี 2019 การสร้างมุมมองที่กำหนดเองด้วย SwiftUI
อย่างไรก็ตาม มีแฮ็คที่จะทำสิ่งนี้ ภายในไฟล์อินเทอร์เฟซที่กล่าวถึงข้างต้น ฉันค้นหา “ProposedSize” และพบโปรโตคอลที่ชื่อ _ArchivableView
ซึ่งทำให้เราสามารถแทนที่ sizeThatFits
:
struct MySample: _ArchivableView {
var body: some View {
Rectangle()
}
func sizeThatFits(in proposedSize: _ProposedSize) -> CGSize {
print(proposedSize.pretty)
return proposedSize.orDefault
}
}
ตอนนี้เราสามารถสร้าง a . ได้ง่ายๆ MySample
ด้วยอัตราส่วนกว้างยาวและพิมพ์ผลลัพธ์ แทนที่จะเป็น .frame
คุณยังสามารถใช้ .fixedSize()
เพื่อเสนอเป็นศูนย์สำหรับความกว้างและ/หรือความสูง ในทำนองเดียวกัน ลองละพารามิเตอร์แรกออกแล้วดูวิธีการ .aspectRatio
เสนอให้ไม่มีเพื่อหาขนาดในอุดมคติของมุมมองย่อย
MySample()
.aspectRatio(100/50, contentMode: .fill)
.frame(width: 320, height: 480)
น่าเสียดายที่ width
และ height
คุณสมบัติบน _ProposedSize
ไม่ปรากฏในอินเทอร์เฟซที่รวดเร็ว ดังนั้นฉันจึงต้องใช้วิปัสสนาเพื่อพิมพ์สิ่งเหล่านั้น (และเพิ่มวิธีการช่วยเหลือสองสามอย่างเช่น .pretty
และ .orDefault
). รหัสเต็มอยู่ในส่วนสำคัญ
หากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการทำงานของ SwiftUI โปรดอ่านหนังสือ Thinking in SwiftUI ของเรา เมื่อบริษัทของคุณกำลังสร้างสิ่งต่างๆ ใน SwiftUI — หรือกำลังจะเริ่มต้น — ให้พิจารณาจอง SwiftUI Workshop สำหรับทีมของคุณ