Перевод подготовлен в рамках курса "iOS Developer. Basic". Если вам интересно узнать о курсе больше, приходите на день открытых дверей онлайн.
Время от времени мне нужно визуализировать данные в виде красивых графиков. В этой статье будет показано, как рисовать графики в SwiftUI-приложении.
Создание пакета для построения графиков с нуля было невозможным из-за ограничений по времени и бюджету, поэтому мне пришлось искать уже существующие решения.
Выбор пал на SwifUI-Charts, который предлагает действительно красиво выглядящие графики и простую интеграцию.
Установка и конфигурация проекта
Сначала мы начнем с создания проекта в XCode.
Отправной точкой является стандартное SwiftUI-приложение, которое будет модифицировано для отображения графика.
На следующем этапе пакет будет добавлен, за счет открытия настройки проекта.
Нажав на кнопку "плюс", можно добавить новый пакет. Здесь необходимо указать полный путь к репозиторию: https://github.com/spacenation/swiftui-charts.git.
На следующем экране я оставил все значения по умолчанию.
На последнем экране я также оставил значения по умолчанию такими, какими они были.
Отображение постоянных данных
Пришло время добавить код. Для первого теста я просто взял
несколько фрагментов кода из Github-Readme и добавил их в
ContentView
:
import Chartsimport SwiftUIstruct ContentView: View { var body: some View { Chart(data: [0.1, 0.3, 0.2, 0.5, 0.4, 0.9, 0.1]) .chartStyle( LineChartStyle(.quadCurve, lineColor: .blue, lineWidth: 5) ) }}
При запуске этого в симуляторе будет нарисован красивый график, показывающий постоянные значения.
Это считается первым успешным тестом.
Отображение динамических данных
В той области, в которой я работаю, данные, которые мне нужно визуализировать, меняются со временем, например, в результате сенсорного ввода. Давайте расширим пример, чтобы динамически обновлять графики в соответствии с изменением данных.
В качестве "сенсора" будет использоваться класс
ObservableObject
, который просто публикует случайное
значение Double
каждые 500 миллисекунд.
import Foundationclass ValuePublisher: ObservableObject { @Published var value: Double = 0.0 init() { Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in self.value = Double.random(in: 0...1.0) } }}
Его нужно инстанцировать в ContentView
как
переменную @State
.
@StateObject var valuePublisher = ValuePublisher()
ValuePublisher
выдает только отдельные значения, но
нам необходимо, чтобы эти значения были доступны в виде списка. С
этой задачей справляется простая очередь структуры данных.
struct Queue<T> { var list = [T]() mutating func enqueue(_ element: T) { list.append(element) } mutating func dequeue() -> T? { if !list.isEmpty { return list.removeFirst() } else { return nil } } func peek() -> T? { if !list.isEmpty { return list[0] } else { return nil } }}
Эта очередь будет инстанцирована как переменная
@State
в ContentView
@State var doubleQueue = Queue<Double>()
Основной список должен быть инициализирован при появлении представления.
.onAppear { doubleQueue.list = [Double](repeating: 0.0, count: 50)}
График также должен содержать информацию о списке, в котором хранятся значения.
Chart(data: doubleQueue.list)
На последнем этапе опубликованные значения
ValuePublisher
должны быть добавлены в очередь, а
самое старое значение из очереди должно быть удалено.
.onChange(of: valuePublisher.value) { value in self.doubleQueue.enqueue(value) _ = self.doubleQueue.dequeue()}
На этом все, вот полный ContentView
, где я также
немного изменил внешний вид графика.
import Chartsimport SwiftUIstruct ContentView: View { @State var doubleQueue = Queue<Double>() @StateObject var valuePublisher = ValuePublisher() var body: some View { Chart(data: doubleQueue.list) .chartStyle( AreaChartStyle(.quadCurve, fill: LinearGradient(gradient: .init(colors: [Color.blue.opacity(1.0), Color.blue.opacity(0.5)]), startPoint: .top, endPoint: .bottom) ) ) .onAppear { doubleQueue.list = [Double](repeating: 0.0, count: 50) } .onChange(of: valuePublisher.value) { value in self.doubleQueue.enqueue(value) _ = self.doubleQueue.dequeue() } .padding() }}
Вот скриншот окончательного варианта приложения
Я также загрузил видео, чтобы вы могли посмотреть, как это выглядит, когда значения обновляются динамически.
Видео: Графики в SwiftUI
Ресурсы