อัตราส่วนภาพใน SwiftUI · objc.io

 

หนึ่งในตัวดัดแปลงที่ทำให้ฉันงงเล็กน้อยคือ .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 สำหรับทีมของคุณ

See also  การเรียนรู้ SwiftUI สำหรับ iOS 16 และ Xcode 14 ได้รับการเผยแพร่แล้ว

By C-MTI