Katmanları en-boy oranına göre sığdırılmış bir SwiftUI diyagramıyla hizalı tutmak için sığdırılmış diyagramın kendisini ölçün ve işaretçileri bu yerel koordinat alanına yerleştirin. Ölçüm katmanını, boş alan ekleyen dış çerçevelerden önce ekleyin.
Bu eğitimde, sentetik bir diyagram ve numaralandırılmış iki işaretçi içeren küçük bir macOS uygulaması oluşturuluyor. Amaç, pencerenin şekli değişirken her işaretçiyi diyagramdaki ilgili öğenin merkezinde tutmaktır. Uygulama, açıklama konumlarının pencere boyutlarından bağımsız kalması için normalize edilmiş koordinatlar kullanır.
Katmanlar, en-boy oranına göre sığdırılmış diyagramdan neden kayar?
En-boy oranına göre sığdırma, diyagramın oranlarını korurken kullanılabilir alana sığmasını sağlar. Kapsayıcının oranlarına bağlı olarak diyagramın üstünde ve altında ya da yanlarında boş alan kalabilir. Apple bu davranışı Görselleri kullanılabilir alana sığdırma başlıklı belgede açıklar.
Çizim ve işaretçileri farklı dikdörtgenleri kullandığında kayma oluşur. Örneğin çizim, 600'e 700 punto boyutlarında bir kapsayıcının içinde, ortalanmış ve 600'e 375 punto boyutlarında bir dikdörtgende yer alabilir. Kapsayıcının yüksekliğinin bir kesriyle konumlandırılan bir işaretçinin hesabına çevresindeki boş alan da dahil olur.
Hangi dikdörtgeni ölçtüğünüzü değiştirici sırası belirler. Apple, görünüm değiştiricilerinin uygulandıkları görünümü sardığını ve bir çerçevenin alt görünümünü başka bir dikdörtgen içinde konumlandırdığını belgeliyor. Bu nedenle, genişleyen bir çerçeveden sonra eklenen katman, doğrudan sığdırılmış çizime eklenen katmandan farklı bir yerleşim sınırını ölçer. Apple’ın View belgelerine ve esnek çerçeve belgelerine bakın.
Bu görev için şu sırayı kullanın:
- Esnek çizimi oluşturun.
.fitile açık en-boy oranını uygulayın.GeometryReaderiçeren bir katman ekleyin.- İşaretçileri okuyucunun boyutunu kullanarak konumlandırın.
- Dış çerçeveyi ve çevresindeki dolguyu ekleyin.
Apple, değiştirilen görünümün yerleşime hâkim olması gerektiğinde katman kullanılmasını önerir. Böylece diyagram, açıklamaların üzerine yerleştirildiği yerleşim sahibi olur. ZStack içindeki kardeş görünümlerden oluşan bir düzen farklı yerleşim davranışına sahiptir ve boyutu hangi görünümün belirlediğine daha fazla dikkat etmeyi gerektirir. Bkz. overlay(alignment:content:).
Eksiksiz bir macOS örneği oluşturun
Xcode'da arayüz olarak SwiftUI kullanan bir macOS uygulama projesi oluşturun. Burada kullanılan kapanış tabanlı katman API'si macOS 12 ve sonraki sürümlerde bulunduğundan, dağıtım hedefini macOS 12 veya üstü olarak ayarlayın. Oluşturulan uygulama giriş noktası dosyasını aşağıdaki eksiksiz programla değiştirin ve hedefte yalnızca tek bir @main uygulama bildirimi bırakın. API'nin kullanılabilir olduğu sürümler overlay(alignment:content:) belgesinde açıklanmıştır.
Sentetik çizim, en-boy oranı 1,6 olan 800'e 500'lük bir tasarım alanını temsil eder. İşaretçi koordinatları bu alanın kesirleri olarak ifade edilir: yatay sıfır sol kenarı, dikey sıfır üst kenarı gösterir; bir ise karşı kenarı belirtir. Görsel dosyalarına veya harici paketlere gerek yoktur.
import SwiftUI
@main
struct DiagramAlignmentApp: App {
var body: some Scene {
WindowGroup {
DiagramExample()
.frame(minWidth: 360, minHeight: 260)
}
}
}
struct DiagramMarker: Identifiable {
let id: Int
let label: String
let x: CGFloat
let y: CGFloat
}
struct DiagramExample: View {
let markers = [
DiagramMarker(id: 1, label: "1", x: 0.25, y: 0.40),
DiagramMarker(id: 2, label: "2", x: 0.75, y: 0.60)
]
var body: some View {
Rectangle()
.fill(Color.white)
.overlay {
DiagramArtwork()
.stroke(Color.gray, lineWidth: 2)
}
.aspectRatio(800.0 / 500.0, contentMode: .fit)
.overlay {
GeometryReader { geometry in
ForEach(markers) { marker in
Circle()
.fill(Color.blue)
.frame(width: 28, height: 28)
.overlay {
Text(marker.label)
.font(.caption.bold())
.foregroundColor(.white)
}
.position(
x: marker.x * geometry.size.width,
y: marker.y * geometry.size.height
)
}
}
}
.border(Color.gray)
.frame(
maxWidth: .infinity,
maxHeight: .infinity,
alignment: .center
)
.padding(24)
.background(Color.gray.opacity(0.12))
}
}
struct DiagramArtwork: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.addRect(CGRect(
x: rect.minX + 0.10 * rect.width,
y: rect.minY + 0.20 * rect.height,
width: 0.30 * rect.width,
height: 0.40 * rect.height
))
path.addRect(CGRect(
x: rect.minX + 0.60 * rect.width,
y: rect.minY + 0.40 * rect.height,
width: 0.30 * rect.width,
height: 0.40 * rect.height
))
path.move(to: CGPoint(
x: rect.minX + 0.25 * rect.width,
y: rect.minY + 0.40 * rect.height
))
path.addLine(to: CGPoint(
x: rect.minX + 0.75 * rect.width,
y: rect.minY + 0.60 * rect.height
))
return path
}
}
Uygulamayı çalıştırıp pencereyi yatay ve dikey yönde yeniden boyutlandırın. 1 işaretçisi ilk dikdörtgenin merkezinde, 2 işaretçisi ise ikinci dikdörtgenin merkezinde kalmalıdır. İnce kenarlık, sığdırılmış diyagramın sınırını belirtir; gri çevre alanı dış yerleşime aittir.
Bu değiştirici sırası neden işe yarar?
Temel dikdörtgen esnek çizimi sağlar ve .aspectRatio(800.0 / 500.0, contentMode: .fit) onun oranlarını sınırlar. Apple, en-boy oranı bağımsız değişkenini genişliğin yüksekliğe bölümü olarak tanımlar ve sığdırma sonucunun yeniden boyutlandırılabilir içeriğe uygulandığını belirtir. Bkz. aspectRatio(_:contentMode:).
Ölçüm katmanı bu kısıtlamanın hemen ardından gelir. GeometryReader, içeriğini kendi boyutu ve koordinat alanına göre tanımlar; geometry.size ise kapsayıcının boyutunu bildirir. Burada bu kapsayıcı sığdırılmış dikdörtgeni kapsar. Bu nedenle normalize edilmiş koordinatları genişliği ve yüksekliğiyle çarpmak, işaretçilerin yerel konumlarını verir. Bkz. GeometryReader ve GeometryProxy.size.
Sondaki genişleyen çerçeve, diyagram ve işaretçilerden oluşan tamamlanmış bileşimi kullanılabilir alanın ortasına yerleştirir. İşaretçiler zaten iç dikdörtgene eklendiğinden, dış kenar boşluklarını hesaplamaları gerekmez.
Çizim ve konumlandırma kurallarını koruyun
DiagramArtwork, Shape protokolüne uyar ve path(in:) yöntemi, sağlanan dikdörtgen içinde ifade edilmiş bir Path döndürür. Görünüm döndürmez ve yerleşim değişiklikleri yapmaz. Bu, Apple’ın belgelenmiş path(in:) sözleşmesine uygundur.
Her işaretçinin .position(x:y:) yöntemi, merkezini hesaplanan noktaya yerleştirir. Sol üst köşesini oraya yerleştirmez. Örnekte, Apple’ın position(x:y:) tanımına uygun olarak numaralı dairenin merkezi, ilgili öğeye sabitlenir.
Pencere yeniden boyutlandırılırken dairelerin genişliği 28 punto kalır, ancak merkezleri çizimi izler. Bu, açıklamaların okunaklı kalması için bilinçli bir sunum tercihidir. İşaretçi boyutları çizim içindeki mesafeleri temsil ediyorsa, bu boyutları da sığdırılmış boyuta göre hesaplayın.
Hesaplanmış bir koordinat örneğiyle hizalamayı kontrol edin
Sayısal bir kontrol, koordinat hatasını biçimlendirme sorunundan ayırmaya yardımcı olur. Ortalanmış en-boy oranına göre sığdırmada pozitif kaynak boyutlarını sourceWidth ve sourceHeight, sonlu kullanılabilir boyutları ise containerWidth ve containerHeight olarak tanımlayın. Aşağıdakiler ayrı bir Swift programı değil, matematiksel sözde koddur:
scale = min(containerWidth / sourceWidth,
containerHeight / sourceHeight)
fittedWidth = sourceWidth * scale
fittedHeight = sourceHeight * scale
originX = (containerWidth - fittedWidth) / 2
originY = (containerHeight - fittedHeight) / 2
containerX = originX + normalizedX * fittedWidth
containerY = originY + normalizedY * fittedHeight
Bu denklemler, belgelenmiş sığdırma davranışına göre tekdüze ölçeklemeyi ve ortalanmış yerleşimi türetir. Örnek olarak verilen 800'e 500'lük kaynak ve (0.25, 0.40) konumundaki 1 işaretçisi şu sonuçları verir. Buradaki kapsayıcı boyutları, çevresindeki dolgu çıkarıldıktan sonra kullanılabilir olan alanı ifade eder.
| Kullanılabilir kapsayıcı | Sığdırılmış diyagram | Diyagramın kapsayıcı içindeki başlangıç noktası | İşaretçi merkezinin kapsayıcı içindeki konumu |
|---|---|---|---|
| 1000 × 700 | 1000 × 625 | (0, 37.5) | (250, 287.5) |
| 600 × 700 | 600 × 375 | (0, 162.5) | (150, 312.5) |
| 1000 × 400 | 640 × 400 | (180, 0) | (340, 160) |
Orta satırda, kapsayıcının tam yüksekliğini 0.40 ile çarpmak 280 sonucunu verir; bu da 312.5 olan doğru dikey konumu kaçırır. Örnekteki yerel katmanda dikey koordinat basitçe 0.40 × 375 = 150 olur; çevreleyen yerleşim 162,5 puntoluk kenar boşluğunu ekler.
Tablodaki hesaplamalar, küçük ve deterministik bir Python hesabıyla kontrol edildi. SwiftUI programı incelendi ancak bu ortamda derlenmedi; görünümünü hedef Mac'te Xcode ile doğrulayın.
Bu düzeni mevcut bir diyagrama uyarlayın
Görsel tabanlı bir diyagram için, en-boy oranına göre sığdırma ve katman değiştiricilerini uygulamadan önce Image görünümünü yeniden boyutlandırılabilir yapın. Apple’ın görsel sığdırma kılavuzu, aksi durumda görselin özgün boyutunda işlendiğini ve yalnızca .resizable() kullanmanın eksenlerini birbirinden bağımsız ölçekleyebileceğini açıklar. Görselin gerçek en-boy oranını koruyup işaretçi katmanını dış çerçeveden önce ekleyin. Bkz. Görselleri kullanılabilir alana sığdırma.
Açıklamalar kaynak koordinatları olarak verilmişse, bunları aynı tam çizim sınırlarına göre normalize edin: kaynak yatay koordinatını kaynak genişliğine, dikey koordinatını ise kaynak yüksekliğine bölün. Görselin içindeki saydam kenar boşlukları da bu sınırlara dahildir. Koordinatlar kırpılmış bir bölgeye göre ölçüldüyse, bu düzeni kullanmadan önce tam görselin koordinat sistemine dönüştürün.
Görsele özgü değiştiricileri, genel görünüm değiştiricileri sarmadan önce Image üzerinde tutun. Benzer şekilde, bileşik görünüm için var body: some View bildirimini, şeklin çizim yöntemi için de Path dönüş türünü koruyun. Apple, özel görünüm bileşimini ve değiştiricilerin sarmalama davranışını View belgesinde açıklar.
Bu hesaplama, ek kırpma, döndürme veya bağımsız kaydırma ve yakınlaştırma dönüşümü olmayan tekdüze bir sığdırma varsayar. Bu işlemleri eklerseniz, çizim ve açıklamalara ortak bir dönüşüm uygulayın ya da koordinat eşlemesini açıkça genişletin. .fill seçeneğine geçmek sığdırma koşullarını değiştirir ve içeriğin çerçevenin dışına taşmasına yol açabilir; Apple, kırpmayı Görselleri kullanılabilir alana sığdırma belgesinde ayrı bir işlem olarak açıklar.
Kalan hizalama sorunlarını teşhis edin
Şu koşulları sırayla kontrol edin:
- Ölçüm sınırı: İşaretçi katmanını dıştaki genişleyen çerçeveden önce tutun. Kenarlığı, çevredeki boş alanı değil çizimi izlemelidir.
- Koordinat sınırları: Normalize edilmiş koordinatların tam kaynak dikdörtgenini ve amaçlanan sol üst başlangıç noktasını kullandığını doğrulayın. Bu örnekte, sınırlar içindeki değerler sıfır ile bir arasındadır; beklenmeyen değerleri sessizce kırpmak yerine reddedin.
- Sabitleme noktası seçimi:
.position(x:y:)yönteminin işaretçinin merkezini sabitlediğini unutmayın. Bir köşesinin öğeye değmesi gereken etiket için açık bir ek ofset ya da farklı bir sabitleme yöntemi gerekir. - Küçük düzenler: Bir işaretçi doğru merkezlenmiş olsa bile başka bir işaretçiyle çakışabilir. Küçük boyutlarda etiketleri gizlemek veya yeniden düzenlemek için ayrı bir kural belirleyin.
- Kenar davranışı: Çizimin kenarındaki bir işaretçi, merkezlendiğinde o kenarın dışına taşar. Kırpma eklemeden önce bu taşmanın kabul edilebilir olup olmadığına karar verin.
İlk ölçülen boyutu .onAppear içinde saklamak yerine, konumları geçerli geometriden türetin. Apple, bu geri çağırımı görünümün görünmesiyle ilişkilendirir ve zamanlamanın görünüm türüne bağlı olduğunu belirtir; bu, pencere yeniden boyutlandırma geri çağırımı değildir. Geometriyi doğrudan okumak, bu örnekteki konumlandırma hesabını geçerli yerleşime bağlı tutar. Bkz. onAppear(perform:).
Yeniden boyutlandırılabilir bir Mac penceresindeki sığdırılmış diyagram için güvenilir başlangıç noktası, paylaşılan tek bir dikdörtgendir: çizimin sığdırılmış sınırlarını belirlemesine izin verin, bu sınırları ölçün ve tüm açıklama merkezlerini bu sınırlardan türetin. Çevredeki yerleşimi ancak bu ilişki kurulduktan sonra ekleyin.
Kaynaklar
- aspectRatio(_:contentMode:) — Apple Geliştirici Belgeleri.
- overlay(alignment:content:) — Apple Geliştirici Belgeleri.
- GeometryReader — Apple Geliştirici Belgeleri.
- size — Apple Geliştirici Belgeleri.
- position(x:y:) — Apple Geliştirici Belgeleri.
- Görselleri kullanılabilir alana sığdırma — Apple Geliştirici Belgeleri.
- frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:) — Apple Geliştirici Belgeleri.
- path(in:) — Apple Geliştirici Belgeleri.
- View — Apple Geliştirici Belgeleri.
- onAppear(perform:) — Apple Geliştirici Belgeleri.