Проект 16 (день 80)
Сегодня тоже не много тем, точнее они не очень объемные, но они не становятся менее интересными:
🟢 Result - тип похожий на Either из функциональных языков. Может содержать в себе либо success, либо failure. В Kotlin такой тоже есть.
🟢 Интерполяция изображений - у Image есть
🟢 Контекстные меню - при нажатии на элемент (удерживая палец) можно вызвать меню. Автор рекомендует им не увлекаться, т.к. такой функционал не очень очевиден пользователям.
Кстати, на маке в Swift Playground это не работает, видимо только для тачскринов.
#hackingwithswift
Сегодня тоже не много тем, точнее они не очень объемные, но они не становятся менее интересными:
interpolation
расширение, можно настроить степень интерполяции. Если простыми словами, это дорисовать новые пиксели на основе существующих при увеличении изображения.Кстати, на маке в Swift Playground это не работает, видимо только для тачскринов.
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Проект 16 (день 81)
Поскольку уроки небольшие, прохожу несколько за раз.
День 81 предлагает следующие темы:
🟢 Можно добавить кастомные свайп-кнопки на элементы списка
🟢 Нотификации. Фреймворк, насколько я понял, используется, скажем, не новый 😆
Запрашиваем права
Делаем отправку
🟢 Подключение проектов как зависимости. Выглядит, на самом деле, как
#hackingwithswift
Поскольку уроки небольшие, прохожу несколько за раз.
День 81 предлагает следующие темы:
List {
Text("Taylor Swift")
.swipeActions {
Button("Delete", systemImage: "minus.circle", role: .destructive) {
print("Deleting")
}
}
.swipeActions(edge: .leading) {
Button("Pin", systemImage: "pin") {
print("Pinning")
}
.tint(.orange)
}
}
Запрашиваем права
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
print(“Всё ок!”)
} else if let error {
print(error.localizedDescription)
}
}
Делаем отправку
let content = UNMutableNotificationContent()
content.title = “Накорми кота”
content.subtitle = “Он “голодный
content.sound = UNNotificationSound.default
// показать нотификацию через 5 секунд
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
// выбираем рандомный ид
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
git submodule
. Что тут ещё написать…?#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1😁1
Проект 16 (день 82)
И вновь день с небольшим количеством материала. Мы начали объединять пройденные ранее уроки в приложение для отслеживания людей, которых мы встретили на конференции:
🟢 Создали 4 основных таба, отражающих списки людей: все, с кем познакомились, с кем предстоит встретиться и информация о себе.
Для первых 3 табов используем одну и ту же View. Определяем тип с помощью перечисления:
🟢 Добавили SwiftData, для этого подготовили такую модель
🟢 Добавили динамическую фильтрацию в зависимости от FilterType при инициализации View:
#hackingwithswift
И вновь день с небольшим количеством материала. Мы начали объединять пройденные ранее уроки в приложение для отслеживания людей, которых мы встретили на конференции:
Для первых 3 табов используем одну и ту же View. Определяем тип с помощью перечисления:
enum FilterType {
case none, contacted, uncontacted
}
@Model
class Prospect {
var name: String
var emailAddress: String
var isContacted: Bool
init(name: String, emailAddress: String, isContacted: Bool) {
self.name = name
self.emailAddress = emailAddress
self.isContacted = isContacted
}
}
init(filter: FilterType) {
self.filter = filter
if filter != .none {
let showContactedOnly = filter == .contacted
_prospects = Query(filter: #Predicate {
$0.isContacted == showContactedOnly
}, sort: [SortDescriptor(\Prospect.name)])
}
}
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Проект 16 (день 83)
Сегодня мы разбирались:
🟢 Как генерировать QR код
Для генерации использовали
Тут пригодилась интерполяция, т.к. она включена по-умолчанию и изображение при масштабировании становится “мыльным”. Скину скрины для сравнения.
🟢 Как сканировать QR код
Для чтения использовали код автора (думаю, что это как раз тот код, упоминаемый тут https://t.me/kotlin2swift/86, по крайней мере называется он именно так).
🟢 Добавили возможность удаления записей с помощью свайпа.
Ниже приложу скриншоты📸
#hackingwithswift
Сегодня мы разбирались:
Для генерации использовали
CIFilter.qrCodeGenerator()
. Даже не подозревал, что настолько просто это можно сделать.Тут пригодилась интерполяция, т.к. она включена по-умолчанию и изображение при масштабировании становится “мыльным”. Скину скрины для сравнения.
Для чтения использовали код автора (думаю, что это как раз тот код, упоминаемый тут https://t.me/kotlin2swift/86, по крайней мере называется он именно так).
Ниже приложу скриншоты
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Проект 16 (день 84)
Две темы сегодня:
➡️ Контекстное меню на изображении - добавили кнопку “пошарить” QR код. Делается это довольно таки просто, что называется one-liner:
Но тут мы столкнулись с чем-то новым: изменение UI во время изменения UI❗️
➡️ Нотификации: проверка настроек нотификаций и добавление кнопки, чтобы мы получили нотификацию о конкретном человеке из нашего списка.
#hackingwithswift
Две темы сегодня:
Image(uiImage: qrCode)
.interpolation(.none)
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
.contextMenu {
ShareLink(item: Image(uiImage: qrCode), preview: SharePreview("My QR Code", image: Image(uiImage: qrCode)))
}
Но тут мы столкнулись с чем-то новым: изменение UI во время изменения UI
qrCode
переменная - это @State
, и код ниже вызывается при отрисовки UI. Присвоение qrCode нового значения меняет состояние, тогда это событие должно порождать новую итерацию перерисовки.
if let outputImage = filter.outputImage {
if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
qrCode = UIImage(cgImage: cgImage)
return qrCode
}
}
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Проект 17 (день 86)
Новый проект - новые горизонты ⛵
86 день открывает тайны жестов (gestures), чуть больше чем обычные нажатия (taps).
▶️ Двойной тап, нажание (long press), минимальное время нажания, щипок (magnify gesture), поворот (rotate gesture). Не очень большой, но уже внушительный список разнообразных жестов. А так же различные настройки жестов
Как утверждает автор, заигрываться с этим не стоит, т.к. пользователь должен интуитивно понимать интерфейс. Полностью согласен, и даже более чем: по опыту - мало кто вообще осваивает хоть какие-то жесты в приложениях для более комфортного использования. Поэтому впервую очереь базовый функционал!
▶️
SwiftUI👶 💪
#hackingwithswift
Новый проект - новые горизонты ⛵
86 день открывает тайны жестов (gestures), чуть больше чем обычные нажатия (taps).
highPriorityGesture
, simultaneousGesture
, pressGesture.sequenced(before: dragGesture)
. Напоминают мне игру Fruit NinjaКак утверждает автор, заигрываться с этим не стоит, т.к. пользователь должен интуитивно понимать интерфейс. Полностью согласен, и даже более чем: по опыту - мало кто вообще осваивает хоть какие-то жесты в приложениях для более комфортного использования. Поэтому впервую очереь базовый функционал!
allowsHitTesting
- позволяет отключить tappable функциональность. Дополнительно рассматривали как ведут себя view обернутые в ZStack, VStack. К примеру, по умолчанию, Spacer
в VStack
не является кликабельным, но это можно испрваить указав .contentShape(.rect)
у VStack
SwiftUI
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Проект 17 (день 87)
Eщё один подготовительный, технический день:
▶️ Timer - механизм позволяющий выполнять переодические и (или) отложенные задачи. Интересно, что есть настройка tolerance, помогающая системе оптимизировать аккумулятор, откладывая вычисления.
▶️ ScenePhase - текущая состояние приложения, доступно через
▶️ Accessibility настройки, такие как accessibilityDifferentiateWithoutColor, позволяют настроить View под определенные запросы пользователя. Это не правило, которому нужно 100% придерживаться, а скорее рекомендация.
#hackingwithswift
Eщё один подготовительный, технический день:
@Environment(\.scenePhase) var scenePhase
, и позволяет понять когда пользователь, к примеру, свернул наше приложение.#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Media is too big
VIEW IN TELEGRAM
Проект 17 (день 88)
Приступили к реализации приложения. Используем полученные навыки, поэтому обойдёмся сегодня только видео🎥
Наконец-то свои карточки делаем😆
#hackingwithswift
Приступили к реализации приложения. Используем полученные навыки, поэтому обойдёмся сегодня только видео
Наконец-то свои карточки делаем
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Проект 17 (день 89)
Сегодня в программе (всё можно увидеть на видео):
🟢 Цветные карточки при свайпе. Влево - 🔴 вправо - 🟢
При включенной опции accessibilityDifferentiateWithoutColor мы не красим карточки, а показываем индикаторы на экране куда смахивать правильные и куда неправильные карточки.
🟢 Таймер на экране и состояние активности приложения (когда можно смахивать карточки). Также когда приложение сворачивается - таймер останавливается. Если ничего не предпринимать, то несколько секунд будет потеряно, поскольку iOS не сразу останавливает таймер.
🟢 Финальный аккорд - кнопка перезапуска, если карточек больше не осталось.
Согласитесь классный курс?🤩
#hackingwithswift
Сегодня в программе (всё можно увидеть на видео):
При включенной опции accessibilityDifferentiateWithoutColor мы не красим карточки, а показываем индикаторы на экране куда смахивать правильные и куда неправильные карточки.
Согласитесь классный курс?
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Проект 17 (день 90)
90 день, время летит, знания прибавляются⏳
🟢 Пофиксили баги, оказывается они появляются не всегда просто так, а иногда намеренно, чтобы выучить новые уроки.
Самый забавный баг заключается в том, что не только верхнюю карточку можно смахнуть, но и любую другую из стека. В основном баги были связаны с accessibility. А так же с анимацией (не назвал бы это багом), добавили bounce анимацию, если карточка была недостаточно далеко отведена и отпущена.
🟢 Отдельная форма в конеце видео, позволяющая добавлять и удалять карточки. Делали это уже много раз.
Добавил карточки, которые, надеюсь, всем очевидны😆
#hackingwithswift
90 день, время летит, знания прибавляются
Самый забавный баг заключается в том, что не только верхнюю карточку можно смахнуть, но и любую другую из стека. В основном баги были связаны с accessibility. А так же с анимацией (не назвал бы это багом), добавили bounce анимацию, если карточка была недостаточно далеко отведена и отпущена.
Добавил карточки, которые, надеюсь, всем очевидны
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Проект 17 (день 91)
Сегодня был день челенжа (доделывали прижение с карточками) и, как обычно, теоритический тест.
Из самостоятельных доделок:
➡️ Очищаю текстовые поля после добавления новой карточки
➡️ Пофиксил: если карточка была немного сдвинута вправо - при возвращении она становилась немного красной
➡️ При смахивании карточки влево, она возвращается обратно в стек. Это было самое сложное, т.к. пришлось переделать
#hackingwithswift
Сегодня был день челенжа (доделывали прижение с карточками) и, как обычно, теоритический тест.
Из самостоятельных доделок:
ForEach
, который был основан на индексах. А так же реализовал разные обработчики свайпа вправо и влево.#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Начинаем проект 18 (день 92)
Это технический проект, где мы начинаем изучать особенности layout системы SwiftUI.
На мой взгляд, самая сложная тема, которая требует большого количества экспериментов. Поскольку порой поведение вьюшек, скажем, удивляет.
🔴 Основное правило определение размеров состоит из 3 шагов:
1️⃣ Parent предлагает доступное пространство (propose size)
2️⃣ Child выбирает свой собственный размер (chooses its size)
3️⃣ Parent позиционирует child внутри себя
🔴
🔴 offset & position
🔸 offset - относительное смещение, интересно, что не влияет на последующие модификаторы (например, background color);
🔸 position - абсолютное позиционирование на экране.
Читал в группах по разработке, что layouts это одна из самых важных тем. Посмотрим как пойдёт дальше. Возможно, понадобится посмотреть дополнительные ролики или почитать статьи👀
Как вам новый стиль эмоджи?🔥 правда?
#hackingwithswift
Это технический проект, где мы начинаем изучать особенности layout системы SwiftUI.
На мой взгляд, самая сложная тема, которая требует большого количества экспериментов. Поскольку порой поведение вьюшек, скажем, удивляет.
alignmentGuide
модификатор и кастомный VerticalAlignment
. Тут я совсем не понял как это работает и нужно с этим отдельно разобраться #todoЧитал в группах по разработке, что layouts это одна из самых важных тем. Посмотрим как пойдёт дальше. Возможно, понадобится посмотреть дополнительные ролики или почитать статьи
Как вам новый стиль эмоджи?
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Проект 18 (день 93)
Продолжаем знакомиться с layout системой📕
🔴
К слову,
Тут есть и обратная сторона, элемент с таким frame будет позиционирован не по центру, а в левом верхнем углу. Фиксится это так:
Выглядит как костылище! Нет, это он и есть… Сначала говорим картинке, что у неё ширина 80%, а потом говорим, что оно должно отображаться на всей доступной области.
🔴 У
Область применения мне пока не понятна, но безусловно хорошо, что такое есть.
🔴 В
Классный эффект с вращающимся текстом при скроллинге😺
Текущий этап изучения: ох уж этот SwiftUI👶
Мне определенно нужно будет пройти этот проект ещё раз. Но я надеюсь, что я не столкнусь с проблемами связанными с layout😆
#hackingwithswift
Продолжаем знакомиться с layout системой
GeometryReader
- предоставляет информацию о размере и положении вью внутри доступного пространства. С его помощью можно центрировать элемент вручную, иметь адаптивный размер вью, создавать кастомный layout.
GeometryReader { proxy in
Image(.example)
.resizable()
.scaledToFit()
.frame(width: proxy.size.width * 0.8, height: 300)
}
К слову,
containerRelativeFrame
работает не так, при использовании его внутри HStack, VStack. GeometryReader в этом случае справляется “лучше”.Тут есть и обратная сторона, элемент с таким frame будет позиционирован не по центру, а в левом верхнем углу. Фиксится это так:
GeometryReader { proxy in
Image(.example)
.resizable()
.scaledToFit()
.frame(width: proxy.size.width * 0.8)
.frame(width: proxy.size.width, height: proxy.size.height)
}
Выглядит как костылище! Нет, это он и есть… Сначала говорим картинке, что у неё ширина 80%, а потом говорим, что оно должно отображаться на всей доступной области.
GeometryReader
есть возможность получить координаты относительно CoordinateSpace: глобальный, локальный, кастомный. Например, proxy.frame(in: .global).midX
.Область применения мне пока не понятна, но безусловно хорошо, что такое есть.
ScrollView
есть возможность получить доступ к неявному GeometryReader через visualEffect
.
Text("Number \(num)")
.font(.largeTitle)
.padding()
.background(.red)
.frame(width: 200, height: 200)
.visualEffect { content, proxy in
content
.rotation3DEffect(.degrees(-proxy.frame(in: .global).minX) / 8, axis: (x: 0, y: 1, z: 0))
}
Классный эффект с вращающимся текстом при скроллинге
Текущий этап изучения: ох уж этот SwiftUI
Мне определенно нужно будет пройти этот проект ещё раз. Но я надеюсь, что я не столкнусь с проблемами связанными с layout
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2 1
Media is too big
VIEW IN TELEGRAM
Предлагаю полюбоваться на этот прекрасный и очень простой в реализации эффект, который был в уроке
https://www.hackingwithswift.com/books/ios-swiftui/scrollview-effects-using-geometryreader
#hackingwithswift
https://www.hackingwithswift.com/books/ios-swiftui/scrollview-effects-using-geometryreader
#hackingwithswift
🔥2
Проект 18 (день 94)
Заключительная часть Проекта 18 включает:
🔴 Тест - результаты которого можно найти в предыдущем посте https://t.me/c/2294310025/234
🔴 Челленж - видео будет в следующем посте. В основу взят список с различными (фиксированными цветами).
Челенж небольшой, всего 3 задания:
🟢 эффект прозрачности для элементов сверху списка
🟢 масштабирование - сверху элементы меньше размером, внизу больше
🟢 менять цвета в зависимости от положения на экране, но я также добавил изменение цвета ещё и в зависимости от индекса
#hackingwithswift
Заключительная часть Проекта 18 включает:
Челенж небольшой, всего 3 задания:
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
День 95 - Челенж
❗️ Предлагается создать приложения для броска кубика (1, 2 или 3).
Что ж, оказалось сделать это не просто😰 И признаться я с этим не справился. Хотя потратил на это больше одного дня, с перерывами, но всё же.
Изначально я хотел сделать зацикленный прокручивающийся список. ScrollView для этого не подходит, да и в целом, у SwiftUI нет подходящей реализации, и нужно делать её самостоятельно.
Попытка сделать VStack со сдвигами элементов не увенчалась успехом и мне пришла идея сделать вращающиеся барабаны как в автоматах казино. Для этого я использовал уже знакомый
Результат далёк от идеала, увидеть это можно на видео.
1️⃣ Полупрозрачность даёт не тот результат, который я ожидал. Особенно при анимировании, вращение прозрачных чисел выглядит как пробел в “барабане”
2️⃣ Для большого количества граней числа наезжают друг на друга. Как увеличить между ними размер я не придумал.
3️⃣ Добавление нового “кубика” может создать его в невалидном состоянии.
#hackingwithswift
Что ж, оказалось сделать это не просто
Изначально я хотел сделать зацикленный прокручивающийся список. ScrollView для этого не подходит, да и в целом, у SwiftUI нет подходящей реализации, и нужно делать её самостоятельно.
Попытка сделать VStack со сдвигами элементов не увенчалась успехом и мне пришла идея сделать вращающиеся барабаны как в автоматах казино. Для этого я использовал уже знакомый
rotation3DEffect
.Результат далёк от идеала, увидеть это можно на видео.
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1👏1🤔1
Проект 19 (день 96). Подготовка к написанию приложения для поиска лыжных курортов.
🔴 🔥
🔴
🔴
🔴 Поиск по вьюхе! Просто добавляем
🔴
Выглядит как глобальные переменные, которые с пелёнок учат не использовать. На бэкэнде с этим хорошо справляется Dependency Injection.
#hackingwithswift
NavigationSplitView
- знакомимся с нюансами разработки под iPad, но очень поверхностно. Рассматривали как можно оптимальнее использовать большой экран. Единая кодовая база - alert()
& sheet()
можно использовать с опциональными значениями.
Button(“Кликай”) {
selectedUser = User()
}
.sheet(item: $selectedUser) { user in
Text(user.id)
}
Group
- view, как следует из названия, для группировки, без влияния на layout. Parent будет ответственным за отображение (вертикально, горизонтально, или по z оси). Можно задавать один стиль для набора вьюшек..searchable
модификатор и появляется search bar
struct ContentView: View {
@State private var searchText = ""
var body: some View {
NavigationStack {
Text("Searching for \(searchText)")
.searchable(text: $searchText, prompt: “Найдём что-нибудь?”)
.navigationTitle("Searching")
}
}
}
@Observable
как Environment элемент. Если не хочется передавать объект во вложенные вьюхи через конструктор (придется передать в каждую вью в иерархии), можно положить в .environment
.Выглядит как глобальные переменные, которые с пелёнок учат не использовать. На бэкэнде с этим хорошо справляется Dependency Injection.
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Проект 19 (день 97 и день 98)
Решил объединить оба дня в один пост, так как тут сильно нечего рассказывать. Мы сделали приложение, используя подходы из предыдущего урока. Впереди нас ждёт небольшой челленж.
Это было последнее приложение, и, к сожалению, мы не применили большинство изученных инструментов.
#hackingwithswift
Решил объединить оба дня в один пост, так как тут сильно нечего рассказывать. Мы сделали приложение, используя подходы из предыдущего урока. Впереди нас ждёт небольшой челленж.
Это было последнее приложение, и, к сожалению, мы не применили большинство изученных инструментов.
#hackingwithswift
👍1
Проект 19 (день 99)
Челенж оказался не очень сложным:
🔴 Сортировка по id, имени и стране
🔴 Имя автора на фото
🔴 Сохранение и чтение используя UserDefaults
Самое интересное было в сортировке. Поскольку все поля (id, name, country) имеют одинаковый тип String, я подумал что было бы круто использовать
#hackingwithswift
Челенж оказался не очень сложным:
Самое интересное было в сортировке. Поскольку все поля (id, name, country) имеют одинаковый тип String, я подумал что было бы круто использовать
KeyPath
. Добавил его везде где нужно и прокинул в метод сортировки. Но разочарование не заставило себя долго ждать. Оказывается Picker
не умеет работать с такими типами (или я 🤭). Пришлось добавить enum.#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Всем привет! 👋
Думаю, настало время дать оценку 100-дневному курсу по SwiftUI от hackingwithswift.
https://www.hackingwithswift.com/100/swiftui
🔸 Общее впечатление: 5/5
Мне определенно заходит такой формат. Отличное сочетание теории, самостоятельной работы и тестов для самопроверки.
🔸 Понятность материала: 4/5
В целом почти все темы понятны, но после прохождения курса ощущается наличие некоторых пробелов.
🔸 Подача: 5/5
Формат видео удачно построен, живое общение Пола приятно смотреть. За дублирование темы в виде текста отдельный плюс.
🔸 Полезность: 5/5
Открыл для себя разработку UI приложений. Пришло понимание как это работает на самом базовом уровне.
#hackingwithswift
Думаю, настало время дать оценку 100-дневному курсу по SwiftUI от hackingwithswift.
https://www.hackingwithswift.com/100/swiftui
Мне определенно заходит такой формат. Отличное сочетание теории, самостоятельной работы и тестов для самопроверки.
В целом почти все темы понятны, но после прохождения курса ощущается наличие некоторых пробелов.
Формат видео удачно построен, живое общение Пола приятно смотреть. За дублирование темы в виде текста отдельный плюс.
Открыл для себя разработку UI приложений. Пришло понимание как это работает на самом базовом уровне.
#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2