Swift Charts στο SwiftUI: Πλήρης Οδηγός για Διαγράμματα σε iOS με Παραδείγματα (2026)

Πλήρης οδηγός για το Swift Charts στο SwiftUI: πώς να φτιάξεις γραμμικά, ραβδωτά και 3D διαγράμματα στο iOS 26, να προσθέσεις διαδραστικότητα, custom άξονες και προσβασιμότητα με VoiceOver, όλα με παραδείγματα κώδικα Swift 6.2.

Swift Charts στο SwiftUI (2026)

Ενημερώθηκε: 29 Αυγούστου 2026

Το Swift Charts είναι το declarative framework διαγραμμάτων της Apple που ενσωματώνεται απευθείας στο SwiftUI και σου επιτρέπει να φτιάξεις γραμμικά, ραβδωτά, σημειακά ή και 3D διαγράμματα με λίγες μόνο γραμμές κώδικα. Είναι διαθέσιμο σε iOS 16+, ενώ από το iOS 26 προσθέτει native 3D marks, βελτιωμένη διαδραστικότητα και audio graphs για προσβασιμότητα. Σε αυτόν τον οδηγό θα δείξω πώς στήνεις ένα διάγραμμα από το μηδέν, πώς κάνεις custom στους άξονες, πώς ενεργοποιείς scroll/zoom, και ποια είναι τα νέα APIs που έφερε το iOS 26. Στο τελευταίο μου project δούλεψα ένα analytics dashboard με πάνω από 5.000 σημεία και τα περισσότερα από όσα γράφω παρακάτω βγήκαν από πολύ πραγματικές αστοχίες performance.

  • Το Swift Charts χρησιμοποιεί το struct Chart και δηλωτικά marks όπως BarMark, LineMark, PointMark και AreaMark.
  • Απαιτεί iOS 16 / macOS 13 και άνω, ενώ τα scrollable charts θέλουν iOS 17 και τα 3D charts iOS 26.
  • Η διαδραστικότητα κτίζεται με chartXSelection / chartYSelection και RuleMark για custom tooltips.
  • Οι άξονες παραμετροποιούνται με chartXAxis, chartYAxis και AxisMarks, χωρίς καθόλου UIKit.
  • Το VoiceOver και το Audio Graph API διαβάζουν αυτόματα το διάγραμμα όταν προσθέσεις accessibilityLabel και accessibilityValue στα marks.
  • Στο iOS 26 το Chart3D δέχεται PointMark3D, SurfacePlot και chart projection για περιστροφή με gesture.

Τι είναι το Swift Charts και ποιες εκδόσεις iOS υποστηρίζει;

Το Swift Charts ανακοινώθηκε στο WWDC22 ως το πρώτο επίσημο framework διαγραμμάτων της Apple, χτισμένο πάνω στο SwiftUI. Δεν είναι wrapper πάνω από UIKit· τα διαγράμματα δηλώνονται με τον ίδιο declarative τρόπο που γράφεις οποιοδήποτε άλλο View. Ένα Chart δέχεται μία σειρά από marks (BarMark, LineMark, PointMark, RectangleMark, RuleMark, AreaMark) και το framework αναλαμβάνει τους άξονες, το scaling, το layout, τα legends και το accessibility tree.

Το minimum SDK είναι iOS 16, iPadOS 16, macOS 13, watchOS 9 και tvOS 16. Τα καινούργια APIs, ωστόσο, κλιμακώνονται σταδιακά: το chartXVisibleDomain για scrollable charts μπήκε στο iOS 17, το chartXSelection για touch selection επίσης στο iOS 17, ενώ το Chart3D, το SurfacePlot και οι επίσημες Charts docs της Apple τεκμηριώνουν τα 3D APIs που εισήχθησαν με το iOS 26. Αν θες το framework να τρέξει και σε iOS 15, δεν υπάρχει back-port. Θα χρειαστείς κάτι σαν το DGCharts.

Πώς φτιάχνεις το πρώτο σου διάγραμμα σε SwiftUI;

Το πιο απλό διάγραμμα χρειάζεται τρία πράγματα: (α) ένα Identifiable model με τα δεδομένα σου, (β) ένα Chart view και (γ) ένα mark που περιγράφει τη μορφή του διαγράμματος. Το παρακάτω παράδειγμα εμφανίζει μηνιαίες πωλήσεις ως γραμμικό διάγραμμα:

import SwiftUI
import Charts

struct SalePoint: Identifiable {
    let id = UUID()
    let month: Date
    let revenue: Double
}

struct RevenueChartView: View {
    let data: [SalePoint]

    var body: some View {
        Chart(data) { point in
            LineMark(
                x: .value("Μήνας", point.month, unit: .month),
                y: .value("Έσοδα (€)", point.revenue)
            )
            .interpolationMethod(.catmullRom)
            .symbol(.circle)
        }
        .frame(height: 260)
        .padding()
    }
}

Οι κλήσεις .value("Μήνας", ...) δίνουν plottable σημασιολογία στα δεδομένα σου: το Swift Charts καταλαβαίνει ότι ο X άξονας είναι ημερομηνία και επιλέγει αυτόματα διαμόρφωση με σύντομα ονόματα μηνών. Η .interpolationMethod(.catmullRom) εξομαλύνει τη γραμμή, ενώ το .symbol(.circle) προσθέτει σημεία πάνω σε κάθε τιμή. Δεν χρειάζεται καμία διαμόρφωση άξονα, γίνεται δωρεάν από το framework.

Τα βασικά είδη marks: BarMark, LineMark, PointMark, AreaMark

Ένα διάγραμμα δεν περιορίζεται σε έναν τύπο mark. Μπορείς να συνδυάσεις πολλά μέσα στο ίδιο Chart. Δες πώς φτιάχνεις ένα σύνθετο διάγραμμα με ράβδους για ημερήσιες μονάδες και μία μέση γραμμή:

Chart {
    ForEach(dailySales) { sale in
        BarMark(
            x: .value("Ημέρα", sale.day, unit: .day),
            y: .value("Μονάδες", sale.units)
        )
        .foregroundStyle(by: .value("Κατηγορία", sale.category))
        .cornerRadius(4)
    }

    RuleMark(y: .value("Μέσος όρος", average))
        .lineStyle(StrokeStyle(lineWidth: 1, dash: [4]))
        .annotation(position: .top, alignment: .leading) {
            Text("Μέσος όρος: \(Int(average))")
                .font(.caption)
                .foregroundStyle(.secondary)
        }
}
.chartLegend(position: .bottom, alignment: .leading)

Πότε επιλέγεις κάθε mark

  • BarMark: για συγκρίσεις κατηγοριών ή διακριτών χρονικών περιόδων (ημερήσιες, εβδομαδιαίες πωλήσεις).
  • LineMark: για συνεχείς τάσεις στον χρόνο, π.χ. τιμή μετοχής ή τηλεμετρία.
  • PointMark: για scatter plots ή για να τονίσεις μεμονωμένα σημεία μιας σειράς.
  • AreaMark: για σωρευτικά μεγέθη ή για να δείξεις εύρος (π.χ. min-max εύρος με yStart/yEnd).
  • RectangleMark: για heatmaps και για συνεχή χρωματική κωδικοποίηση 2D χώρου.
  • RuleMark: για baselines, όρια ή μέσους όρους. Δεν αναπαριστά δεδομένα από μόνη της, αλλά υπογραμμίζει.

Το .foregroundStyle(by:) κάνει αυτόματο group και color mapping. Αν έχεις δύο ή περισσότερες κατηγορίες, το Swift Charts δημιουργεί μόνο του το legend. Για custom παλέτα χρησιμοποίησε .chartForegroundStyleScale(range: [.blue, .orange]).

Πώς κάνεις custom στους άξονες και τα labels;

Οι default άξονες του Swift Charts είναι καλοί, όχι όμως πάντα ό,τι θέλεις. Οι modifiers chartXAxis, chartYAxis και chartXScale σου δίνουν πλήρη έλεγχο πάνω στο πόσα gridlines θα δείξεις, τι μορφή έχουν οι ετικέτες και σε ποιο εύρος τιμών θα κινηθείς. Δες πώς φτιάχνεις έναν άξονα Y που δείχνει έσοδα σε ευρώ με χίλιαδες:

Chart(data) { point in
    LineMark(
        x: .value("Μήνας", point.month, unit: .month),
        y: .value("Έσοδα", point.revenue)
    )
}
.chartXAxis {
    AxisMarks(values: .stride(by: .month)) { value in
        AxisGridLine()
        AxisValueLabel(format: .dateTime.month(.abbreviated), centered: true)
    }
}
.chartYAxis {
    AxisMarks(position: .leading, values: .automatic(desiredCount: 4)) { value in
        AxisGridLine()
        AxisValueLabel {
            if let euros = value.as(Double.self) {
                Text(euros, format: .currency(code: "EUR").precision(.fractionLength(0)))
            }
        }
    }
}
.chartYScale(domain: 0...maxRevenue * 1.1)

Το AxisMarks είναι builder: μέσα του συνθέτεις AxisGridLine, AxisTick, AxisValueLabel. Το values: δέχεται .automatic, .stride(by:) ή explicit [Value]. Το .chartYScale(domain:) κλειδώνει το εύρος ώστε το διάγραμμα να μην τρεμοπαίζει καθώς εισέρχονται νέα δεδομένα. Αν χρησιμοποιείς @Observable models, ίσως σου φανεί χρήσιμος και ο οδηγός για το @Observable Macro που εξηγεί πώς αποφεύγεις περιττά redraws.

Πώς φτιάχνεις διαδραστικά διαγράμματα με selection;

Από το iOS 17 το chartXSelection(value:) επιτρέπει στον χρήστη να σέρνει το δάχτυλό του πάνω από το διάγραμμα κι εσύ να παίρνεις πίσω την τιμή του άξονα X. Ο τυπικός τρόπος να δείξεις tooltip είναι με ένα RuleMark στη θέση της επιλογής, συνοδευμένο από annotation που εμφανίζει τα ακριβή δεδομένα:

struct InteractiveChart: View {
    let data: [SalePoint]
    @State private var selectedDate: Date?

    private var selectedPoint: SalePoint? {
        guard let date = selectedDate else { return nil }
        return data.min {
            abs($0.month.timeIntervalSince(date))
          < abs($1.month.timeIntervalSince(date))
        }
    }

    var body: some View {
        Chart {
            ForEach(data) { point in
                LineMark(
                    x: .value("Μήνας", point.month),
                    y: .value("Έσοδα", point.revenue)
                )
            }

            if let sel = selectedPoint {
                RuleMark(x: .value("Επιλογή", sel.month))
                    .foregroundStyle(.gray.opacity(0.4))
                    .annotation(position: .top, spacing: 4) {
                        VStack(alignment: .leading) {
                            Text(sel.month, format: .dateTime.month(.wide))
                            Text(sel.revenue, format: .currency(code: "EUR"))
                        }
                        .padding(8)
                        .background(.regularMaterial, in: .rect(cornerRadius: 8))
                    }
            }
        }
        .chartXSelection(value: $selectedDate)
        .frame(height: 260)
    }
}

Scrolling και zooming σε μεγάλα datasets

Όταν το dataset έχει εκατοντάδες σημεία, δεν χωράνε όλα στην οθόνη. Το chartScrollableAxes(.horizontal) ενεργοποιεί οριζόντιο scroll, ενώ το chartXVisibleDomain(length:) ορίζει πόσος χρόνος φαίνεται μονομιάς. Συνδυάζοντας αυτά με το chartScrollPosition, κρατάς την τρέχουσα ημερομηνία διαθέσιμη ως state:

@State private var scrollPosition: Date = .now
private let sixMonths: TimeInterval = 60 * 60 * 24 * 30 * 6

Chart(data) { point in
    BarMark(
        x: .value("Ημέρα", point.day, unit: .day),
        y: .value("Πωλήσεις", point.units)
    )
}
.chartScrollableAxes(.horizontal)
.chartXVisibleDomain(length: sixMonths)
.chartScrollPosition(x: $scrollPosition)
.chartScrollTargetBehavior(
    .valueAligned(matching: .init(day: 1), majorAlignment: .matching(.init(month: 1)))
)

Το chartScrollTargetBehavior κάνει snap στη 1η κάθε μήνα, οπότε το scrolling νιώθει φυσικό και δεν αφήνει τον χρήστη ενδιάμεσα σε μία ημερομηνία. Για zoom μπορείς να συνδέσεις ένα MagnificationGesture στην sixMonths τιμή. Στο iOS 18+ υπάρχει και το chartXAxis auto-format που αλλάζει την γρανουλαρότητα (μήνες → εβδομάδες → ημέρες) όσο κάνεις pinch.

Τι νέο έφερε το iOS 26: Chart3D και SurfacePlot

Το iOS 26 προσθέτει τρεις σημαντικές καινοτομίες: το νέο container Chart3D, το SurfacePlot για συνεχείς επιφάνειες, και το PointMark3D για scatter σε τρεις διαστάσεις. Αυτό ξεκλείδωσε use cases όπως ML embeddings, geospatial data και engineering plots χωρίς εξωτερικές βιβλιοθήκες όπως το SceneKit. Δες πώς φτιάχνεις ένα 3D scatter με περιστροφή μέσω gesture:

#if swift(>=6.2)
@available(iOS 26.0, *)
struct EmbeddingsChart: View {
    let vectors: [Embedding]

    var body: some View {
        Chart3D(vectors) { v in
            PointMark3D(
                x: .value("x", v.x),
                y: .value("y", v.y),
                z: .value("z", v.z)
            )
            .foregroundStyle(by: .value("cluster", v.cluster))
        }
        .chart3DCameraProjection(.perspective(fieldOfView: .degrees(45)))
        .chart3DPose(.rotatable(initial: .front))
        .frame(height: 320)
    }
}
#endif

Ο modifier chart3DPose(.rotatable) ενεργοποιεί δωρεάν gesture για περιστροφή με ένα δάχτυλο, ενώ το chart3DCameraProjection επιλέγει perspective ή orthographic προβολή. Το SurfacePlot δέχεται συνάρτηση (x, y) -> z και είναι ιδανικό για μαθηματικά διαγράμματα.

Animations και μεταβάσεις μεταξύ δεδομένων

Οι transitions στο Swift Charts δουλεύουν όπως σε οποιοδήποτε άλλο SwiftUI view: αν το data source σου είναι @State ή @Observable, τυλίγεις τις αλλαγές σε withAnimation και το framework interpolates τα marks αυτόματα. Ένα κλασσικό pattern για dashboards είναι να χρησιμοποιείς .animation(.smooth, value: data), ώστε κάθε ανανέωση δεδομένων να έρχεται με fluid animation:

Chart(viewModel.metrics) { m in
    BarMark(
        x: .value("Ημέρα", m.day, unit: .day),
        y: .value("Χρήστες", m.activeUsers)
    )
    .foregroundStyle(.tint)
}
.animation(.smooth(duration: 0.35), value: viewModel.metrics)
.transaction { $0.disablesAnimations = false }

Για να μπει και το initial appear animation, όρισε .transition(.blurReplace) στο εξωτερικό view. Για πιο controlled transitions ανά mark, από iOS 18 μπορείς να δηλώσεις .transition(.identity) σε συγκεκριμένα marks όταν δεν θες να interpolated. Πληροφορίες για τη βελτίωση performance στα animations και τη σχέση με το structured concurrency θα βρεις στον οδηγό Swift Concurrency.

Προσβασιμότητα, VoiceOver και audio graphs

Ένα από τα πιο δυνατά χαρακτηριστικά του Swift Charts είναι το built-in accessibility. Το framework παράγει αυτόματα ένα accessibility tree όπου κάθε mark γίνεται στοιχείο, ενώ το iOS εκφωνεί τους άξονες με VoiceOver. Παρόλα αυτά, για τη μέγιστη εμπειρία πρέπει να προσθέσεις accessibilityLabel και accessibilityValue:

BarMark(
    x: .value("Μήνας", point.month, unit: .month),
    y: .value("Έσοδα", point.revenue)
)
.accessibilityLabel(point.month.formatted(.dateTime.month(.wide)))
.accessibilityValue("\(Int(point.revenue)) ευρώ")

Πέρα από VoiceOver, το iOS 17+ φέρνει και audio graphs: ο χρήστης ακούει το διάγραμμα σαν μία ακολουθία τόνων που ανεβοκατεβαίνουν με τις τιμές. Το framework το ενεργοποιεί μόνο του, φτάνει να έχουν τα marks σαφή accessibilityLabel. Για dashboard views, συνιστάται να προσθέτεις κι ένα κρυφό Text summary για screen readers, ώστε ο χρήστης να πάρει τη γενική εικόνα πριν εξερευνήσει σημείο-σημείο. Οι HIG οδηγίες accessibility της Apple εξηγούν με λεπτομέρεια πότε προτιμάς summary vs. per-mark labels.

Βέλτιστες πρακτικές performance

Το Swift Charts κάνει διακριτικό caching και δεν redraws χωρίς λόγο, αλλά ένα κακά δομημένο view μπορεί εύκολα να πέσει κάτω από 60fps. Ειλικρινά, το πρώτο μου dashboard κόλλαγε σε 22fps ώσπου ακολούθησα τα εξής:

  1. Κράτα το data model απλό. Χρησιμοποίησε struct με προ-υπολογισμένα values. Μην κάνεις string parsing μέσα σε .value(...).
  2. Απόφυγε heavy annotations. Ένα Text(...) ναι, ένα custom shape με blur όχι, τουλάχιστον σε χιλιάδες marks.
  3. Downsample πριν το plot. Για >1000 σημεία, εφάρμοσε moving average ή min/max downsampling. Το ανθρώπινο μάτι δεν διακρίνει διαφορά.
  4. Καθόρισε σταθερό frame. Δώσε ρητή .frame(height: ...), γιατί το dynamic sizing πυροδοτεί ξανά layout σε κάθε αλλαγή.
  5. Χρησιμοποίησε @Observable αντί για ObservableObject. Το observation tree περιορίζει τα redraws στα marks που άλλαξαν πραγματικά.
  6. Απενεργοποίησε animations σε rapid streams. Σε live tickers όρισε .animation(nil, value: data) και ενημέρωσε το view με throttling.

Αν χτίζεις navigation-heavy dashboards, δες και τον οδηγό NavigationStack για να διατηρήσεις σωστά το scroll position ανάμεσα σε screens που περιέχουν διαγράμματα.

Συχνές ερωτήσεις

Είναι το Swift Charts δωρεάν;

Ναι. Το Swift Charts είναι μέρος του iOS SDK, τεκμηριώνεται στις επίσημες Apple docs και δεν χρειάζεται licensing, subscription ή εξωτερικό SPM package.

Ποια είναι η ελάχιστη έκδοση iOS για το Swift Charts;

Χρειάζεται iOS 16, iPadOS 16, macOS Ventura, watchOS 9 ή tvOS 16 και άνω. Τα scrollable charts θέλουν iOS 17, ενώ τα Chart3D και SurfacePlot iOS 26.

Μπορεί το Swift Charts να δείξει 3D δεδομένα;

Ναι, από το iOS 26. Χρησιμοποιείς το container Chart3D με PointMark3D για scatter ή SurfacePlot για συνεχείς επιφάνειες, ενώ το chart3DPose(.rotatable) επιτρέπει gesture-based περιστροφή.

Πώς προσθέτω tooltip σε ένα SwiftUI chart;

Δέσε ένα @State optional στο chartXSelection(value:) και ζωγράφισε ένα RuleMark στη θέση της επιλογής με .annotation(position:). Το annotation δέχεται οποιοδήποτε SwiftUI view για styled tooltip.

Το Swift Charts υποστηρίζει export ως εικόνα;

Ναι, αλλά όχι με API. Τυλίγεις το Chart σε ImageRenderer του SwiftUI για να το κάνεις render σε PNG ή PDF και μετά αποθηκεύεις το UIImage/NSImage όπου θέλεις, π.χ. στη φωτογραφική βιβλιοθήκη ή σε μία αναφορά PDF.

Ποια είναι η διαφορά ανάμεσα σε BarMark και RectangleMark;

Το BarMark έχει μία μεταβλητή διάσταση (ύψος ή πλάτος) και σταθερή θέση κατά μήκος του άλλου άξονα, ενώ στο RectangleMark ορίζεις και τις δύο διαστάσεις, ιδανικό δηλαδή για heatmaps ή για να τονίσεις μια περιοχή γραφήματος.

Editorial Team
Σχετικά με τον Συγγραφέα Editorial Team

Our team of expert writers and editors.