Sentetik bir kartın yerel macOS sürüklemesi sırasında bütün görünmesini sağlamak için dış kapsayıcısına tek bir sürükleme kaynağı ekleyin ve önizleme olarak kartın tamamını oluşturun. Önizlemenin başlangıç çerçevesini ve işaretçi ofsetini açıkça denetlemeniz gerektiğinde AppKit kullanın.
Bu kılavuz, kendi Mac uygulamanızdaki iki panel arasında bellekteki tek bir kartı sürüklemeyi ele alır. Pratik amaç, hareket işleme ve model güncellemelerinin sorumluluğunu açıkça belirlerken kartın şekillerini, metnini, aralıklarını ve kimliğini korumaktır.
Sürüklemenin hangi kısmı değişmeli?
Apple, aktarılan veriyi sürükleme sırasında gösterilen görsel temsilden ayırır. SwiftUI’nin draggable(_:preview:) öğesi, sürükleme başladığında önizleme görünümünüzün bir görüntüsünü oluşturur. Belgelenen önizleme kaynak görünümün üzerinde ortalanır. Kaynak görünümün kendisi aktarılmaz. Apple’ın draggable(_:preview:) belgelerine bakın.
İhtiyacınız olan denetimi belirlemek için bu karar yardımını kullanın:
| İstenen davranış | Desteklenen başlangıç noktası |
|---|---|
| Kartın etiketini, şekillerini ve arka planını birlikte tutmak | Tam bir özel önizlemeye sahip tek bir dış sürükleme kaynağı |
| Kaldırma geçişi sırasında dış çizgiyi ayarlamak | contentShape(.dragPreview, shape) |
| Kartın hangi bölümünün sürüklemeyi başlatabileceğini değiştirmek | contentShape(.interaction, shape) |
| Kartı başka bir panele eklemek | Yükü doğrulayın ve hedefte modeli güncelleyin |
| Başlangıç sürükleme görüntüsü dikdörtgenini ve işaretçi ilişkisini açıkça ayarlamak | NSDraggingItem kullanan, AppKit’in yönettiği bir oturum |
| Yerel bırakma hedefleri olmadan bir tuvaldeki öğeyi sürekli hareket ettirmek | Yerel bir DragGesture etkileşimi |
İki içerik şekli arasındaki ayrım önemlidir: Apple, .dragPreview öğesinin önizleme şeklini, .interaction öğesinin ise isabet testini denetlediğini belgeliyor. Yalnızca önizleme dış çizgisini değiştirmek, sürüklemeyi başlatan bölgeyi genişletmez. ContentShapeKinds.dragPreview belgesine bakın.
Yerel bir DragGesture, bir hareket dizisi boyunca sürükleme hareketini bildirir. Görev bir tuval konumunu güncellemekse bu yaklaşımı seçin. Bu makaledeki paneller arası yerel bırakma görevi için sürükleme hareketlerini draggable kurmalıdır. Apple’ın DragGesture başvurusuna ve sürükleme kaynağı kılavuzuna bakın.
Sentetik kartın tamamı için tek bir önizleme oluşturun
Sürükleme değiştiricisini, birlikte taşınması gereken her şeyi içeren en küçük kapsayıcıya ekleyin. Daire, iki metin satırı ve yuvarlatılmış bir arka plandan oluşan kart için bu kapsayıcı kartın tamamıdır. Alt öğelere ayrı sürükleme kaynakları eklemek, ayrı etkileşimler tanımlar.
Kaynak ve önizleme için aynı sunum görünümünü yeniden kullanın. Bu görünüme açık boyutlar ve kendi arka planını verin; çevresindeki panelden devralınan biçimlendirmeye bağlı kalmayın. Bu, işlenmiş önizlemenin davranışından çıkarılan bir tasarım önerisidir: kendi başına yeterli bir sunum, iki görünümü eşleştirmeyi kolaylaştırır.
Tam SwiftUI örneği
Dağıtım hedefi macOS 13 veya üzeri olan bir macOS SwiftUI uygulaması oluşturun. Oluşturulan uygulama girişini ve içerik görünümünü bu tek dosyayla değiştirin; hedefte tam olarak bir @main bildirimi bırakın. Burada kullanılan hem özel önizleme değiştiricisinin hem de hedef aşırı yüklemesinin macOS 13’ten itibaren kullanılabildiği belgelenmiştir. draggable(_:preview:) ve dropDestination(for:action:isTargeted:) belgelerine bakın.
import Foundation
import SwiftUI
@main
struct IntactDragDemoApp: App {
var body: some Scene {
WindowGroup {
BoardView()
}
}
}
private struct CardFace: View {
var body: some View {
HStack(spacing: 14) {
Circle()
.fill(Color.orange)
.frame(width: 36, height: 36)
VStack(alignment: .leading, spacing: 6) {
Text("Tile A")
.font(.headline)
Text("Circle and label")
.font(.caption)
}
.foregroundStyle(Color.white)
}
.padding(16)
.frame(width: 220, height: 100, alignment: .leading)
.background(Color.indigo)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}
private struct BoardView: View {
@State private var token = UUID().uuidString
@State private var isOnRight = false
var body: some View {
VStack(spacing: 20) {
Text("Drag the card between panels")
.font(.headline)
HStack(spacing: 24) {
panel(right: false)
panel(right: true)
}
}
.padding(24)
}
private func panel(right: Bool) -> some View {
VStack(spacing: 16) {
Text(right ? "Right" : "Left")
.font(.headline)
ZStack {
if isOnRight == right {
CardFace()
.contentShape(
.interaction,
RoundedRectangle(cornerRadius: 16)
)
.contentShape(
.dragPreview,
RoundedRectangle(cornerRadius: 16)
)
.draggable(token) {
CardFace()
}
} else {
Text("Drop here")
.foregroundStyle(.secondary)
}
}
.frame(width: 240, height: 120)
}
.frame(width: 260, height: 180)
.background(
RoundedRectangle(cornerRadius: 20)
.fill(Color.gray.opacity(0.12))
)
.contentShape(Rectangle())
.dropDestination(for: String.self) { items, _ in
guard items == [token] else {
return false
}
isOnRight = right
return true
}
}
}
Bu örnekte yalnızca sentetik grafikler ve bellekte oluşturulan bir tanımlayıcı kullanılır. String zaten Transferable protokolüne uyar; bu nedenle özel bir aktarım gösterimine ihtiyaç duymaz. Apple, bu yerleşik uyumu Bir görünümü sürükleme kaynağına dönüştürme belgesinde açıklıyor.
Beklenen etkileşim basittir: Tile A öğesini diğer panele sürükleyin, bırakın, sonra geri sürükleyin. Hareket eden önizlemeyi CardFace öğesinin tamamı sağlar. Hedef, tam olarak bir eşleşen belirteci kabul eder ve tek konum değerini değiştirir. true döndürmek başarılı bir bırakma bildirir; false döndürmek ise hedef eyleminin belgelenmiş sözleşmesini izleyerek bırakmayı reddeder.
Bu, bir macOS uygulama hedefi için hazırlanmış eksiksiz bir örnektir. Araştırma ortamında Swift araç zinciri veya macOS çalışma zamanı bulunmadığından burada derlenmemiş ya da çalıştırılmamıştır.
Görsel sürekliliği model sahipliğinden ayrı tutun
Örnekte, kabul edilen bir bırakma isOnRight değerini değiştirene kadar özgün kart görünür kalır. Panellerin dışına bırakmak modelde değişiklik yapmaz. Dolu panele geri bırakmak, mevcut konumu yeniden atar. Durum değişmeden önce eşleşmeyen bir belirteç veya birden fazla öğe reddedilir.
Bu davranış, kartı sürükleme başında kaldırıp iptalden sonra yeniden oluşturma ihtiyacını önler. Önizleme görsel sürekliliği sağlar; konum değişikliğinin sorumluluğu hedeftedir. Daha büyük bir pano için aynı düzeni kararlı bir öğe tanımlayıcısına ve tek bir yetkili koleksiyona uygulayın.
Swift değer semantiği, bir yükü aktarmanın özgün modeli neden otomatik olarak taşımadığını açıklar. Yapılar ve dizeler değer semantiğine sahiptir; bunları atamak veya aktarmak, uygulamanızın koleksiyonundaki bir öğeyi örtük olarak başka yere taşımaz. Bu taşımayı model güncellemeniz ifade etmelidir. Yapılar ve Sınıflar belgesine bakın.
Ayrıca uygulama düzeyindeki bir yer değiştirmeyi yerel sürükleme işleminden ayırın. Örnek, kabul edilen bir bırakmadan sonra paylaşılan tek pano durumunu değiştirir; yerel taşıma anlaşmasını yapılandırmaz veya taşıma imlecini garanti etmez.
macOS 26 ve üzeri için Apple, desteklenen işlemleri bildirmek üzere DragConfiguration öğesini ve gerçekleştirilen işlemi gözlemlemek üzere onDragSessionUpdated(_:) öğesini belgeliyor. Hedef, gerçekleştirdiği işlemi seçer. Yerel bir taşıma işleminden sonra kaynaktan kaldırma uyguluyorsanız, aynı paylaşılan öğenin iki kez kaldırılmaması için bunu hedef işleme ile eşgüdümleyin. DragConfiguration ve onDragSessionUpdated(_:) belgelerine bakın.
Sürükleme oturumunu AppKit ne zaman yönetmeli?
Kabul ölçütü, örneğin kart alınırken işaretçinin kart içindeki aynı noktanın üzerinde kalması gibi, konumu açıkça belirlenmiş bir sürükleme görüntüsü içeriyorsa AppKit kullanın. SwiftUI’nin belgelenmiş özel önizleme değiştiricisi bir yük ve önizleme görünümü alır ve ortalanmış bir önizleme tanımlar. AppKit, sürükleme öğesinin çerçevesine doğrudan erişim sağlar.
AppKit uygulaması için şu sırayı izleyin:
- Kaynak
NSViewöğesinin gerçek fare aşağı olayını almasına izin verin ve etkileşimin sürüklemeye dönüşüp dönüşmediğini izleyin. - Sentetik kartın tamamını tek bir
NSImageiçine işleyin ve pano yazıcısıyla tek birNSDraggingItemoluşturun. setDraggingFrame(_:contents:)ile görüntüyü ve başlangıç dikdörtgenini ayarlayın.- Bu dikdörtgeni başlatan görünümün koordinat sisteminde ifade edin, ardından başlatan fare aşağı olayı ve
NSDraggingSourceöğenizlebeginDraggingSession(with:event:source:)çağrısını yapın. - Hedefin bırakmayı doğrulayıp uygulamasına izin verin. Oturum temizliği için kaynağın tamamlama geri çağrısını kullanın.
Apple, başlatan olayın fare konumunun sürüklenen simgenin ofsetini belirlediğini ve her öğenin başlangıç çerçevesinin kaynak görünümün koordinatlarını kullanması gerektiğini belirtir. Kart dikdörtgeni ile olay konumunu tutarlı bir koordinat sisteminde tutun. beginDraggingSession(with:event:source:) belgesine bakın.
setDraggingFrame(_:contents:), tek bir görüntüyle temsil edilen sürükleme öğesi için belgelenmiş kolaylık yöntemidir. Sentetik bir kart birkaç çizilmiş öğe içerebilir, ancak yine de bu tek görüntüyle temsil edilebilir. setDraggingFrame(_:contents:) belgesine bakın.
Olay ve oturum sınırlarını koruyun
Kartın etkileşimli bölgesi için tek bir sürükleme başlatıcısı seçin. Uygulama kuralı olarak, aynı bölge için etkin bir SwiftUI draggable kaynağının üzerine AppKit oturum başlatıcısı eklemekten kaçının. Her ikisi de etkileşimin sorumluluğunu üstlenmeye çalışır. Hareket sahipliği belirsizliğini gidermek için fare olayları üretmeyin.
AppKit kaynağını NSViewRepresentable kullanarak yerleştirebilirsiniz. Yerel olay işlemeyi kendi NSView öğesinde tutun ve kabul edilen model değişikliklerini bağlamalar veya bir koordinatör aracılığıyla iletin. SwiftUI, temsil edilen görünümün düzenini denetler; Apple, yönetilen bu görünümün frame veya bounds değerlerinin doğrudan ayarlanmaması gerektiğini özellikle belirtir. Sürükleme öğesinin görüntü dikdörtgeni ayrı bir konudur. NSViewRepresentable belgesine bakın.
NSDraggingItem öğesini saklayıp daha sonra değiştirmeyin. Apple, sınırlı ömrünü belgeliyor: oturum oluşturulduktan sonra sürükleme öğelerini oturum numaralandırması aracılığıyla değiştirin ve numaralandırılan her öğeyi yalnızca geri çağrısı içinde kullanın. Bırakma hedefi üzerindeki değişiklikler, sürükleme o hedefteyken kaynak tarafındaki görüntü değişikliklerini de geçersiz kılabilir. NSDraggingItem ve enumerateDraggingItems(options:for:classes:searchOptions:using:) belgelerine bakın.
Hâlâ yanlış görünen bir önizlemeyi nasıl teşhis edersiniz?
Sorunu göründüğü aşamada denetleyin:
| Belirti | İlk kontrol |
|---|---|
| Yalnızca daire veya metin hareket ediyor | Kartın tamamını kapsayan kapsayıcıya tek bir sürükleme kaynağı koyun. |
| Önizleme boyutları karttan farklı | Aynı sunum görünümünü ve açık boyutları yeniden kullanın. |
| Alınma anındaki dış çizgi hareket eden görüntüden farklı | .dragPreview öğesini özel önizleme kapanışından ayrı olarak denetleyin. |
| Boş alan beklenmedik biçimde sürüklemeyi başlatıyor | .interaction öğesini ve kaynak kapsayıcının sınırlarını gözden geçirin. |
| AppKit görüntüsü alınma anında sıçrıyor | Başlatan fare aşağı olayını ve kaynak görünüm koordinatlarını denetleyin. |
| AppKit görüntüsünde sonraki değişiklikler etkisiz kalıyor | Bunları oturum numaralandırması içinde yapın. |
| İptalden sonra kart kayboluyor | Model değişikliğini kabul edilen bırakma işlemine taşıyın ve temizliği gözden geçirin. |
İptal, kabul edilen bir bırakma, özgün panele geri bırakma ve reddedilen bir yük durumlarını ayrı ayrı doğrulayın. Yararlı değişmez, tek bir model konumunun baştan sona yetkili kalmasıdır. Tam SwiftUI önizlemesiyle başlayın; ardından yalnızca gerekli görüntü konumu açık çerçeve ve olay denetimleri gerektirdiğinde AppKit’in yönettiği bir kaynağa geçin.
Kaynaklar
draggable(_:preview:) — Apple Geliştirici Belgeleri.
Bir görünümü sürükleme kaynağına dönüştürme — Apple Geliştirici Belgeleri.
dragPreview — Apple Geliştirici Belgeleri.
DragGesture — Apple Geliştirici Belgeleri.
dropDestination(for:action:isTargeted:) — Apple Geliştirici Belgeleri.
Yapılar ve Sınıflar — Swift.org.
DragConfiguration — Apple Geliştirici Belgeleri.
onDragSessionUpdated(_:) — Apple Geliştirici Belgeleri.
beginDraggingSession(with:event:source:) — Apple Geliştirici Belgeleri.
setDraggingFrame(_:contents:) — Apple Geliştirici Belgeleri.
NSViewRepresentable — Apple Geliştirici Belgeleri.
NSDraggingItem — Apple Geliştirici Belgeleri.
enumerateDraggingItems(options:for:classes:searchOptions:using:) — Apple Geliştirici Belgeleri.