Skip to content
Tüm yazılar

SwiftUI Satır Yüksekliği: iOS 26 lineHeight Modifier'ı Açıklandı

iOS 26'da SwiftUI satır yüksekliği nasıl çalışır: .lineHeight preset'leri, multiple(factor:), exact ve leading değerleri, lineSpacing farkı; iPhone ve iPhone Duo'da.

AppleDuo EditörlüğüYayınlanma 6 dk okuma

Diğer dillerde:EnglishDeutschEspañolFrançais日本語

Bu sayfada
  1. SwiftUI'da satır yüksekliği nasıl ayarlanır?
  2. .tight, .normal ve .loose ne anlama geliyor?
  3. .multiple(factor:) CSS line-height ile nasıl karşılaştırılır?
  4. lineHeight ile tek satırlık bir etiket neden fazla yukarıda görünüyor?
  5. lineHeight, lineSpacing ve leading arasındaki fark nedir?
  6. contentTransition(.numericText()) ile sayılar nasıl yuvarlanarak değişir?
  7. Satır yüksekliği iPhone Duo'da daha mı önemli?
  8. Önemli çıkarımlar

Tasarımcılar "17 pt, satır yüksekliği 1.5" gibi spesifikasyonlar verir ve uzun süre SwiftUI'da bunu doğrudan ifade etmenin bir yolu yoktu. Bunu satırlar arasına point ekleyen .lineSpacing ile ya da üç ince adım sunan bir fontun .leading ayarıyla yaklaşık olarak yapıyordunuz. iOS 26, gerçek bir SwiftUI satır yüksekliği modifier'ı ile bunu çözüyor.

Bu rehber lineHeight(_:) modifier'ını, kabul ettiği her değeri, eski API'lerle nasıl karşılaştırıldığını ve insanları şaşırtan tek davranışı, yani ekstra boşluğun nereye gittiğini anlatıyor. Apple'ın dokümantasyonuna, Natalia Panferova'nın Nil Coalescing'deki yazısına ve iOS geliştiricisi @sarunw'nin paylaşımlarına dayanıyor. Modifier iOS 26.0 ile yeni geldi; ayrıntılar sürümler arasında değişebilir.

SwiftUI'da satır yüksekliği nasıl ayarlanır?

.lineHeight(_:)'ı bir Text'e veya onun üzerindeki herhangi bir view'a uygulayın. Apple onu "view hiyerarşisindeki varsayılan satır yüksekliği için bir modifier" olarak tanımlıyor; yani .font gibi environment üzerinden çalışıyor:

Text(article.body)
    .font(.body)
    .lineHeight(.loose)

Parametre opsiyonel bir AttributedString.LineHeight; Apple'ın art arda gelen iki satırın taban çizgileri arasındaki mesafe olarak tanımladığı bir Foundation türü. Varsayılan değer nil ve Apple'a göre bu durumda SwiftUI "her bağlam için uygun bir satır yüksekliği ayarını otomatik olarak seçiyor." Bir alt ağacı bu otomatik davranışa döndürmek için nil verin.

Modifier ve eşleşen lineHeight environment değeri iOS 26.0, iPadOS 26.0, macOS 26.0, Mac Catalyst 26.0, tvOS 26.0, visionOS 26.0 ve watchOS 26.0'dan itibaren kullanılabilir. Eski sürümlere geri taşıma (back-deployment) yok; bu yüzden eski sürümleri destekliyorsanız onu #available(iOS 26.0, *) ile koruyun.

.tight, .normal ve .loose ne anlama geliyor?

AttributedString.LineHeight'ın dört statik özelliği ve üç factory metodu var. Apple'ın dokümantasyonu her birini şöyle tanımlıyor:

DeğerApple'ın tanımıDynamic Type ile ölçeklenir mi
.tightSıkı algılanan bir point size katıEvet
.normalNormal algılanan bir point size katıEvet
.looseGevşek algılanan bir point size katıEvet
.variableHer satırdaki fontların ascent ve descent değerlerine dayanırEvet
.multiple(factor:)En büyük point size çarpı factorEvet
.leading(increase:)En büyük point size artı increase pointKısmen: font büyür, ek değer büyümez
.exact(points:)Point cinsinden sabit bir toplamHayır

Apple üç preset'in arkasındaki sayıları yayımlamıyor. @sarunw'ye göre bunlar .multiple(factor:) için kısayollar: .tight 1.0, .normal 1.2 ve .loose 1.5. Belirli bir değere ihtiyacınız varsa, kodunuz bu eşlemeye bağlı kalmasın diye katsayıyı kendiniz yazın.

Nil Coalescing'in karşılaştırması .normal ve .variable'ı varsayılandan neredeyse ayırt edilemez buldu. Fark tanımda: .variable her satırın font metriklerini izlerken, diğer değerler Apple'ın ifadesiyle "kullanılan fontların etkin ascent ve descent değerlerinden" bağımsız olarak sabittir.

.multiple(factor:) CSS line-height ile nasıl karşılaştırılır?

Web dünyasından geliyorsanız istediğiniz .multiple(factor:). @sarunw'nin ifadesiyle .lineHeight(.multiple(factor: 1.5)), CSS'teki line-height: 1.5 gibi çalışır: satır yüksekliği, font boyutu çarpı katsayıdır.

Apple'ın tanımı da aynı şeyi söylüyor, tek bir ayrıntıyla: katsayı satırdaki en büyük point size'ı çarpar; yani 17 pt'lik gövde metnini 22 pt'lik bir satır içi ifadeyle karıştıran bir satır 22 pt'yi kullanır.

Text(article.body)
    .font(.body)
    .lineHeight(.multiple(factor: 1.5))

.body bir text style olduğu için point size kişinin Dynamic Type ayarıyla değişir ve satır yüksekliği de onunla birlikte değişir. Nil Coalescing, multiple(factor:)'ın Dynamic Type boyutları arasında boşluğu orantılı tuttuğunu doğruluyor.

Diğer iki metot bu esnekliği kontrolle takas eder:

Text(caption)
    .lineHeight(.leading(increase: 6))

Text(ticketNumber)
    .lineHeight(.exact(points: 24))

.leading(increase:) en büyük point size artı sabit sayıda point'tir; bu yüzden font büyüdükçe aralık aynı kalır. .exact(points:) ise fontu tamamen yok sayar. Nil Coalescing, sabit bir değerle satırların büyük metin boyutlarında üst üste binebileceği veya kesilebileceği konusunda uyarıyor; bu yüzden onu, kullanacaksanız, yalnızca kısa ve sabit boyutlu metinlere ayırın.

lineHeight ile tek satırlık bir etiket neden fazla yukarıda görünüyor?

İşin püf noktası bu. Bir tarayıcı, CSS satır yüksekliğinin ekstra boşluğunu ikiye bölüp metnin üstüne ve altına dağıtır; CSS spesifikasyonu buna half-leading diyor. @sarunw'ye göre SwiftUI'ın .lineHeight'ı tüm ekstra boşluğu her satırın altına koyuyor, "tek satır olsa bile." Bu yüzden .multiple(factor: 2) ile tek satırlık bir etiket "fazla yukarıda duruyormuş gibi görünüyor."

Bir paragrafta bu zararsızdır: boşluk satırların arasına düşer, ki istediğiniz de buydu. Bir düğme, bir chip veya ortalanmış bir satır içindeki tek satırlık bir etikette ise metin daha uzun bir frame'in üst kısmında durur ve frame'i ortalamak metni ortalamaz.

Bununla başa çıkmanın birkaç yolu var:

  • Modifier'ın kapsamını sınırlayın. .lineHeight environment üzerinden aktarıldığı için onu tüm ekrana değil, paragraf Text'ine uygulayın. Bir üst view onu ayarlıyorsa, bir etiketi .lineHeight(nil) ile sıfırlayın.
  • Taban çizgilerine göre hizalayın. Bir satırda HStack(alignment: .firstTextBaseline) veya .lastTextBaseline kullanın; böylece etiketler frame'lerine göre değil metinlerine göre hizalanır ve bir satırın altındaki ekstra boşluk onları kaydırmaz.
  • Kısa metinlerde katsayıları ölçülü tutun. Büyük bir katsayı esas olarak uzun metin okumaya yardımcı olur. Başlıklar ve etiketler nadiren varsayılandan fazlasına ihtiyaç duyar.
HStack(alignment: .firstTextBaseline) {
    Text(item.title)
        .font(.headline)
    Spacer()
    Text(item.price, format: .currency(code: "USD"))
        .font(.subheadline)
}
.lineHeight(nil)

Burada satır, yukarıda ayarlanmış herhangi bir satır yüksekliğini yok sayar ve iki etiket ilk taban çizgilerine göre hizalanır. İkisini de büyük Dynamic Type boyutlarıyla test edin, çünkü boşluk sorunları ilk orada ortaya çıkar.

lineHeight, lineSpacing ve leading arasındaki fark nedir?

SwiftUI'da artık satırlar arasındaki boşluğu değiştirmenin üç yolu var ve her biri farklı bir şeyi ölçüyor:

APIİtibarenNeyi ayarlarBirim
.lineHeight(_:)iOS 26Taban çizgisinden taban çizgisineKatsayı veya point
.lineSpacing(_:)iOS 13Bir satırın altından sonrakinin üstünePoint
Font.leading(_:)iOS 14Fontun kendi satır aralığı.standard, .loose, .tight

lineSpacing(_:) satırlar arasına sabit bir aralık ekler. Bu kullanışlıdır, ancak satır yüksekliğini bir kat olarak veren bir tasarım spesifikasyonuyla örtüşmez ve aralık Dynamic Type ile büyümez. Apple'ın örneği .lineSpacing(10) kullanıyor.

Font.leading(_:), .font(.title.leading(.loose)) örneğindeki gibi bir fonta uygulanır. Apple, "leading ayarlarının kullanılabilirliğinin fonta bağlı olduğunu" ve bazı fontlarda modifier'ın hiçbir etkisi olmadığını belirtiyor. Nil Coalescing onun etkisini çok ince olarak tanımlıyor.

iOS 26 ve sonrası için yazılan yeni kodda, tasarımcıların metni tanımlama biçimine uyan .lineHeight'tır. Eski deployment target'lar için .lineSpacing'i koruyun.

contentTransition(.numericText()) ile sayılar nasıl yuvarlanarak değişir?

İlgili bir metin efekti ve skorlar, sayaçlar ve fiyatlar için sık istenen bir şey: @sarunw, .contentTransition(.numericText())'in "sayıların yeni değerlerine yuvarlanarak geçmesini sağladığını" belirtiyor. Her değişen rakam solmak yerine yeni değerine kayar.

struct ScoreView: View {
    @State private var score = 0

    var body: some View {
        VStack {
            Text(score, format: .number)
                .font(.largeTitle.monospacedDigit())
                .contentTransition(.numericText(value: Double(score)))
            Button("Add 10") {
                withAnimation { score += 10 }
            }
        }
    }
}

Bunun çalışması için iki ayrıntı gerekiyor. Birincisi, Apple'ın contentTransition(_:) hakkındaki ipucu, onun yalnızca bir animasyon içinde etkili olduğunu söylüyor; bu yüzden değeri withAnimation içinde değiştirin. İkincisi, iOS 17 ile gelen numericText(value:), yönü seçmek için eski ve yeni değer arasındaki farkı kullanır. iOS 16 ile gelen eski numericText(countsDown:) ise yönü bunun yerine bir Boolean olarak alır.

.monospacedDigit() fontu, rakamlar değişirken sayının genişliğini sabit tutar. Sayılarınızın yanındaki animasyonlu semboller için SF Symbols animasyonları ve rendering modları rehberimize bakın.

Satır yüksekliği iPhone Duo'da daha mı önemli?

iPhone Duo'da iç ekran bir iPad gibi regular genişlik bildirirken dış ekran diğer iPhone'lar gibi davranır (iPhone Duo size class'ları rehberimize bakın). İç ekranı boydan boya kaplayan bir okuma view'u, dış ekrana göre çok daha uzun satırlarla sonuçlanabilir.

Uzun satırlar genellikle biraz daha fazla satır yüksekliğiyle daha iyi okunur; dış ekranda doğru görünen bir değer iç ekranda sıkışık hissettirebilir. .lineHeight bir environment değeri olduğu için onu size class'a bağlayabilirsiniz:

@Environment(\.horizontalSizeClass) private var horizontalSizeClass

var body: some View {
    Text(article.body)
        .font(.body)
        .lineHeight(.multiple(factor: horizontalSizeClass == .regular ? 1.5 : 1.3))
        .frame(maxWidth: 680)
}

Buradaki katsayılar örnektir, Apple'ın önerisi değildir. Genişliği frame(maxWidth:) ile sınırlamak çoğu zaman herhangi bir satır yüksekliğinden daha fazla yardımcı olur, çünkü daha geniş ekranda satır uzunluğunu rahat bir düzeyde tutar.

Önemli çıkarımlar

  • iOS 26, bir AttributedString.LineHeight alan ve environment üzerinden aktarılan .lineHeight(_:)'ı ekliyor. nil otomatik anlamına gelir.
  • .multiple(factor: 1.5), CSS'teki line-height: 1.5 gibi çalışır ve Dynamic Type ile ölçeklenir. @sarunw'ye göre .tight, .normal ve .loose sırasıyla 1.0, 1.2 ve 1.5 katsayılarıdır.
  • .leading(increase:) sabit point ekler; .exact(points:) ölçeklenmez ve büyük boyutlarda kırpabilir.
  • Tüm ekstra boşluk her satırın altına gider, bu yüzden tek satırlık etiketler yukarıda görünür. Modifier'ın kapsamını sınırlayın ve satırları metin taban çizgilerine göre hizalayın.
  • .lineHeight taban çizgisinden taban çizgisine ölçer; .lineSpacing satırlar arasına bir aralık ekler; Font.leading üç ince adım sunar.
  • Yuvarlanarak değişen sayılar için withAnimation içinde .contentTransition(.numericText(value:)) kullanın.

Sırada, iOS 27'nin SwiftUI'da sürükleyerek sıralama ve swipe action'ları nasıl ele aldığını görün ya da iPhone Duo'nun iki ekranına zaten uyum sağlayan uygulamalar için menteşe için tasarlanmış oyunlara göz atın.

Sık sorulan sorular

SwiftUI'da satır yüksekliği nasıl ayarlanır?

iOS 26 ve sonrasında bir Text'e veya herhangi bir üst view'a .lineHeight(_:) uygulayın, örneğin .lineHeight(.multiple(factor: 1.5)). Değer environment üzerinden aşağı doğru aktarılır. nil vermek SwiftUI'ın otomatik satır yüksekliğini geri getirir.

.tight, .normal ve .loose hangi değerleri kullanır?

Apple bunları, sıkı, normal ve gevşek algılanan bir point size katına dayanan sabit satır yükseklikleri olarak belgeliyor. Geliştirici @sarunw, bunların 1.0, 1.2 ve 1.5 değerleriyle .multiple(factor:)'a eşit olduğunu bildiriyor.

SwiftUI'da lineHeight ile lineSpacing arasındaki fark nedir?

lineSpacing(_:), bir satırın altı ile sonraki satırın üstü arasına point cinsinden boşluk ekler. lineHeight(_:) ise bir taban çizgisinden diğerine olan mesafeyi, font boyutunun bir katı veya bir point değeri olarak ayarlar.

SwiftUI lineHeight Dynamic Type ile ölçeklenir mi?

multiple(factor:) ölçeklenir, çünkü point size'ı çarpar. leading(increase:) fontla birlikte büyür ama sabit sayıda point ekler. exact(points:) sabit bir toplamdır; bu yüzden ölçeklenmez ve büyük boyutlarda metni kırpabilir veya üst üste bindirebilir.

lineHeight ile tek satırlık etiketim neden fazla yukarıda görünüyor?

@sarunw'nin belirttiği gibi .lineHeight, tek satır olsa bile tüm ekstra boşluğu her satırın altına koyar. Büyük katsayıları yalnızca çok satırlı metne uygulayın ve tek satırları frame'lerini ortalamak yerine metin taban çizgilerine göre hizalayın.

Kaynaklar

  1. lineHeight(_:) · Apple Developer Documentation
  2. AttributedString.LineHeight · Apple Developer Documentation
  3. multiple(factor:) · Apple Developer Documentation
  4. exact(points:) · Apple Developer Documentation
  5. leading(increase:) · Apple Developer Documentation
  6. lineSpacing(_:) · Apple Developer Documentation
  7. Font.Leading · Apple Developer Documentation
  8. numericText(value:) · Apple Developer Documentation
  9. contentTransition(_:) · Apple Developer Documentation
  10. iOS 26 adds a .lineHeight modifier to SwiftUI · @sarunw on X
  11. .lineHeight presets .tight, .normal, .loose = .multiple(factor:) 1.0, 1.2, 1.5 · @sarunw on X
  12. .lineHeight(.multiple(factor: 1.5)) works like CSS line-height: 1.5 · @sarunw on X
  13. .lineHeight puts all extra space below each line · @sarunw on X
  14. .contentTransition(.numericText()) makes numbers roll to their new value · @sarunw on X
  15. Adjusting line height in SwiftUI on iOS 26 · Nil Coalescing
  16. CSS 2.2: Visual formatting model details (line-height) · W3C

Katlanmayı uygulamanızın bir parçası yapın.

iPhone Duo ile gerçekten bir şey yapan uygulama ve oyunları tanıtıyoruz. App Store bağlantısıyla sizinkini gönderin ya da diğer geliştiricilerin neler yaptığına bakın.

[email protected]