Must-have SUI-frame extension
Весьма удобные модификаторы, позволяющие избегать
Забрать можно отсюда
Useful modifiers to avoid
#howto #getsources
Весьма удобные модификаторы, позволяющие избегать
Spacer()
и .frame()
. Взял у Kavsoft :)Забрать можно отсюда
Useful modifiers to avoid
Spacer()
and .frame()
. Check out here.#howto #getsources
List vs LazyVStack
Что лучше использовать и когда?
Зависит, конечно, от поставленной задачи. Например, если приложение на UIKit, и хотите подтянуть SwiftUI, то необходимо учитывать, что разделители у ячеек в List, если они не нужны, до iOS 15 убираются весьма костыльным способом:
Тем самым можно зааффектить дизайн UITableView во всем приложении. В iOS 15 для этого уже появился специальный модификатор
Но, на мой взгляд, ключевой особенностью является рендеринг у
Начиная с iOS 15, List рендерит уже только элементы, видимые на экране. Получается, что пагинацию на List для iOS < 15 можно сделать только, если загружать > 20 элементов. Это не всем может подойти, в приоритете окажется LazyVStack.
Which one is best to use and when?
It depends, of coz, on the task. For ex, if the app based on on UIKit, and you want to add SwiftUI, then you should be considered that the separators between cells in the List, if they are not needed, are removed in a very “crutch” way before iOS 15:
This can affect the design of the UITableView throughout the whole application. Beginning with iOS 15 a special modifier
Imho the key feature is the difference in the rendering (which depend on iOS versions) of
Beginning with iOS 15 List renders only items that are visible on the screen. Turns out that in iOS < 15 using List pagination can only be done if you should load > 20 items. This may not suit for everyone and LazyVStack should be used.
#readthis
Что лучше использовать и когда?
Зависит, конечно, от поставленной задачи. Например, если приложение на UIKit, и хотите подтянуть SwiftUI, то необходимо учитывать, что разделители у ячеек в List, если они не нужны, до iOS 15 убираются весьма костыльным способом:
.onAppear {
UITableView.appearance().separatorStyle = .none
}
Тем самым можно зааффектить дизайн UITableView во всем приложении. В iOS 15 для этого уже появился специальный модификатор
.listRowSeparator(.hidden)
.Но, на мой взгляд, ключевой особенностью является рендеринг у
List
и LazyVStack
, который отличается в зависимости от версий iOS. В iOS < 15 List рендерит ячейки “с запасом”, а именно, если List растянут на весь экран, то ленивой загрузки нет у первых 15 (iPhone 6s) - 20 элементов, при этом без разницы, какая высота фрейма у элемента. Напротив, LazyVStack рендерит только те элементы, которые видны на экране. Таким образом, например, вешая модификатор .onAppear{…}
, мы получаем ожидаемое поведение только у LazyVStack. Начиная с iOS 15, List рендерит уже только элементы, видимые на экране. Получается, что пагинацию на List для iOS < 15 можно сделать только, если загружать > 20 элементов. Это не всем может подойти, в приоритете окажется LazyVStack.
Which one is best to use and when?
It depends, of coz, on the task. For ex, if the app based on on UIKit, and you want to add SwiftUI, then you should be considered that the separators between cells in the List, if they are not needed, are removed in a very “crutch” way before iOS 15:
.onAppear {
UITableView.appearance().separatorStyle = .none
}
This can affect the design of the UITableView throughout the whole application. Beginning with iOS 15 a special modifier
.listRowSeparator(.hidden)
has already appeared for this.Imho the key feature is the difference in the rendering (which depend on iOS versions) of
List
and LazyVStack
. In iOS < 15 List renders cells “with a margin”, namely, if the List is stretched to full screen, then the first 15 (iPhone 6s) - 20 elements do not have lazy loading, and it doesn’t matter what the element’s frame height is. Opp. LazyVStack renders only elements that are visible on the screen. Thus, for ex, by setting the .onAppear{…}
modifier, we get the expected behavior only for LazyVStack
.Beginning with iOS 15 List renders only items that are visible on the screen. Turns out that in iOS < 15 using List pagination can only be done if you should load > 20 items. This may not suit for everyone and LazyVStack should be used.
#readthis
SwiftUI dev
List vs LazyVStack Что лучше использовать и когда? Зависит, конечно, от поставленной задачи. Например, если приложение на UIKit, и хотите подтянуть SwiftUI, то необходимо учитывать, что разделители у ячеек в List, если они не нужны, до iOS 15 убираются весьма…
This media is not supported in your browser
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
У
Сделал пример, как можно это реализовать
This tutorial demonstrate how we could implement it easily.
#howto #getsources
LazyVGrid
отсутствует возможность объединения столбцов. Сделал пример, как можно это реализовать
LazyVGrid
does not have a column span feature. This tutorial demonstrate how we could implement it easily.
#howto #getsources
This media is not supported in your browser
VIEW IN TELEGRAM
Сделал package с примером реализации показа всплывающих окон/alert-ов/popover-ов/sheet-ов из любого места в приложении на SwiftUI.
Перед просмотром советую освежить в памяти про EnvironmentValues и прочитать эту статью.
Made a package with an example of the implementation of showing pop-up windows / alerts / popovers / sheets from anywhere in the application on SwiftUI.
Before watching, I advise you to refresh in memory for EnvironmentValues and read this article.
#swiftpm #getsources
Перед просмотром советую освежить в памяти про EnvironmentValues и прочитать эту статью.
Made a package with an example of the implementation of showing pop-up windows / alerts / popovers / sheets from anywhere in the application on SwiftUI.
Before watching, I advise you to refresh in memory for EnvironmentValues and read this article.
#swiftpm #getsources
This media is not supported in your browser
VIEW IN TELEGRAM
Весьма интересный момент отрисовки анимации в SwiftUI 👇🏻
Interesting case of SwiftUI-animation rendering👇🏻
#readthis
Interesting case of SwiftUI-animation rendering👇🏻
#readthis
SwiftUI dev
Весьма интересный момент отрисовки анимации в SwiftUI 👇🏻 Interesting case of SwiftUI-animation rendering👇🏻 #readthis
Рассмотрим следующий код:
Весьма стандартная ситуация: имеется скролл вью с листом, при выборе из этого листа объекта нужно анимировать (в данном случае, просто поменять
Возможны несколько вариантов фикса.
Один из которых ввести искусственную задержку, например, в 0.2 - 0.3 секунды, не заметную для пользователя, но ее будет хватать на загрузку изображения:
В большинстве случаев, этот фикс работает, но при плохом интернете, понятно, что нет.
Предпочтительным, на мой взгляд, будет другой сценарий: возвращать стейт загрузки изображения:
#readthis
...
@State var selectedGood: Good?
var body: some View {
ZStack(alignment: .bottom) {
// List with goods
ScrollList(selection: $selectedGood)
.zIndex(0)
// animated panel view:
...
AsyncImage(url: URL(string: selectedGood.image.url)) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}
...
.offset(y: selectedGood != nil ? 0 : -2 * height)
.animation(.spring(…), value: selectedGood != nil)
.zIndex(1)
}
}
...
Весьма стандартная ситуация: имеется скролл вью с листом, при выборе из этого листа объекта нужно анимировать (в данном случае, просто поменять
offset
) панель. Менять offset
начинаем сразу после выбора. На панели выведены два изображения, одно из которых выбранный объект из списка. Изображения рендерим через AsyncImage
, используя placeholder
. Если кэша изображения нет, то какое-то время необходимо потратить на его загрузку по сети. Здесь и сталкиваемся с неожиданным поведением отрисовки анимации в SwiftUI: замена placeholder-а на изображение происходит в финальной точке положения View после анимации, а не во время. Сразу укажу, что добавление .delay на анимацию ситуацию не исправляет.Возможны несколько вариантов фикса.
Один из которых ввести искусственную задержку, например, в 0.2 - 0.3 секунды, не заметную для пользователя, но ее будет хватать на загрузку изображения:
...
@State var startAnimation: Bool = false
@State var selectedGood: Good?
...
AsyncImage(url: URL(string: selectedGood.image.url)) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}.onChange(of: selectedGood) { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
withAnimation {
startAnimation = true
}
}
}
.offset(y: startAnimation ? 0 : -2 * height)
.animation(.spring(...), value: startAnimation)
...
В большинстве случаев, этот фикс работает, но при плохом интернете, понятно, что нет.
Предпочтительным, на мой взгляд, будет другой сценарий: возвращать стейт загрузки изображения:
...
@State var startAnimation: Bool = false
@State var selectedGood: Good?
...
CustomAsyncImage(url: URL(string: selectedGood.image.url),
startAnimation: $startAnimation ) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}.offset(y: startAnimation ? 0 : -2 * height)
.animation(.spring(...), value: startAnimation)
...
struct CustomAsyncImage: View {
...
@Binding var startAnimation: Bool
...
var body: some View {
AsyncImage(url: URL(string: url)) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
.onAppear {
isLoaded.toggle()
}
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}
}
}
...
#readthis
SwiftUI dev
Весьма интересный момент отрисовки анимации в SwiftUI 👇🏻 Interesting case of SwiftUI-animation rendering👇🏻 #readthis
Look at following code:
Very standard case: there is a scroll view with a panel view, when you select an object from list, you should animate (in this case, just change the offset) the panel view. We start changing offset immediately after selection. The panel displays two images, one of which is the selected object from the list. Images are rendered via
Several options for fix this are possible.
One of which is to add some
In most cases this fix works but not with poor Internet.
IMHO the preferred fix option would be to return the state of the image loading:
#readthis
...
@State var selectedGood: Good?
var body: someView {
ZStack(alignment: .bottom) {
// List with goods
ScrollList(selection: $selectedGood)
.zIndex(0)
// animated panel view:
...
AsyncImage(url: URL(string: selectedGood.image.url)) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}
...
.offset(y: selectedGood != nil ? 0 : -2 * height)
.animation(.spring(...), value: selectedGood != nil)
.zIndex(1)
}
}
...
Very standard case: there is a scroll view with a panel view, when you select an object from list, you should animate (in this case, just change the offset) the panel view. We start changing offset immediately after selection. The panel displays two images, one of which is the selected object from the list. Images are rendered via
AsyncImage
using placeholder
. If there is no image cache then some time should be spent for downloading. This is where unexpected rendering animation behavior in SwiftUI appears: the placeholder is replaced with an image at the final position of the View after the animation (not during it). I’ll point out that adding .delay
to the animation does not fix the situation.Several options for fix this are possible.
One of which is to add some
delay
, for example, in 0.2 - 0.3 seconds, which is not noticeable for user but it will be enough to load the image:...
@State var startAnimation: Bool = false
@State var selectedGood: Good?
...
AsyncImage(url: URL(string: selectedGood.image.url)) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}.onChange(of: selectedGood) { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
withAnimation {
startAnimation = true
}
}
}
.offset(y: startAnimation ? 0 : -2 * height)
.animation(.spring(...), value: startAnimation)
...
In most cases this fix works but not with poor Internet.
IMHO the preferred fix option would be to return the state of the image loading:
...
@State var startAnimation: Bool = false
@State var selectedGood: Good?
...
CustomAsyncImage(url: URL(string: selectedGood.image.url),
startAnimation: $startAnimation ) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}.offset(y: startAnimation ? 0 : -2 * height)
.animation(.spring(...), value: startAnimation)
...
struct CustomAsyncImage: View {
...
@Binding var startAnimation: Bool
...
var body: someView {
AsyncImage(url: URL(string: url)) { image in
image.resizable()
.aspectRatio(contentMode: .fit)
.onAppear {
isLoaded.toggle()
}
} placeholder: {
Color.Background.secondary.cornerRadius(8)
}
}
}
...
#readthis
Проект с примерами различных анимаций на SwiftUI с лицензией бесплатного коммерческого использования.
A repository containing a variety of animations and Animated components created in SwiftUI that you can use in your own projects.
#howto #getsources
A repository containing a variety of animations and Animated components created in SwiftUI that you can use in your own projects.
#howto #getsources
GitHub
GitHub - Shubham0812/SwiftUI-Animations: A repository containing a variety of animations and Animated components created in SwiftUI…
A repository containing a variety of animations and Animated components created in SwiftUI that you can use in your own projects. - Shubham0812/SwiftUI-Animations
Nice article about SwiftUI Flow Coordinator pattern to coordinate navigation between views
#readthis
#readthis
Medium
SwiftUI Flow Coordinator pattern to coordinate navigation between views
This article covers navigation in SwiftUI pre-iOS 16. If you are interested with implementing flow coordinators for newer versions of iOS…
Patched Yandex maps mobile as SwiftPM working on Xcode > 13.3 on M1, however waiting for official release announced last week))
Пропатченная версия Яндекс карт, собранная как SwiftPM, работающая на Xcode старше 13.3 на M1, так или иначе ждём официального релиза, который пообещали на прошлой неделе))
UPD: upgraded to Yandex maps mobile 4.1.0, worked on Apple Silicone without rosetta mode, manual is here.
Обновил до 4.1.0, полноценно работает на m1, мануал по поддержке здесь.
UPD2: add Yandex lite maps mobile
Добавил Yandex maps mobile версии lite
#switfpm #getsources
Пропатченная версия Яндекс карт, собранная как SwiftPM, работающая на Xcode старше 13.3 на M1, так или иначе ждём официального релиза, который пообещали на прошлой неделе))
UPD: upgraded to Yandex maps mobile 4.1.0, worked on Apple Silicone without rosetta mode, manual is here.
Обновил до 4.1.0, полноценно работает на m1, мануал по поддержке здесь.
UPD2: add Yandex lite maps mobile
Добавил Yandex maps mobile версии lite
#switfpm #getsources
GitHub
GitHub - c-villain/YandexMapsMobile: Yandex Maps Mobile full Swift package
Yandex Maps Mobile full Swift package. Contribute to c-villain/YandexMapsMobile development by creating an account on GitHub.
This media is not supported in your browser
VIEW IN TELEGRAM
Possible implementation of waterfall grid with row spanning-trick effect based on LazyVStack.
Реализация грида с ячейками разной высоты на LazyVStack.
#howto #getsources
Реализация грида с ячейками разной высоты на LazyVStack.
#howto #getsources
This media is not supported in your browser
VIEW IN TELEGRAM
Implementation SwiftUI tab bar instead of UIKit’s.
Написал статью, как мы внедряли SwiftUI таб-бар взамен UIKit.
#readthis #howto
Написал статью, как мы внедряли SwiftUI таб-бар взамен UIKit.
#readthis #howto
Статья на тему, как лучше подключать тяжелые зависимости в SwiftPM на примере Firebase.
От себя хочу сказать, что подключив Firebase как набор XCFramework файлов через бинарную зависимость в SwiftPM, скорость сборки проекта (после очистки кэша) повысилась на 15%: со 184 сек до 157.
Репозиторий с бинарниками Firebase.
Nice article on how to add heavy dependencies like Firebase using SwiftPM.
On my own I have to say that we improved Xcode project build time from 184 sec to 157 sec (15%) after adding Firebase as XCFrameworks as
Repository with Firebase binaries is here.
#switfpm #readthis
От себя хочу сказать, что подключив Firebase как набор XCFramework файлов через бинарную зависимость в SwiftPM, скорость сборки проекта (после очистки кэша) повысилась на 15%: со 184 сек до 157.
Репозиторий с бинарниками Firebase.
Nice article on how to add heavy dependencies like Firebase using SwiftPM.
On my own I have to say that we improved Xcode project build time from 184 sec to 157 sec (15%) after adding Firebase as XCFrameworks as
.binaryTarget
in package.Repository with Firebase binaries is here.
#switfpm #readthis
This media is not supported in your browser
VIEW IN TELEGRAM
Увидел этот пример в ленте linkedin (первоисточник — Eran Lunenfeld, который реализовал на jetpack compose). Решил воспроизвести сам 😊 Думаю, хороший челендж и пример для тестовых заданий на SwiftUI. Попробуйте сверстать сами: есть интересные моменты. Посмотреть код здесь
Saw this example in news feed on linkedin, author was Shai Mishali (who originally saw it from Eran Lunenfeld in his turn) and decided to reproduce myself ))
Think it was nice challenge ))
Try to make it yourself!Anyway code is here
#trytodo #howto #tasty #groovy #getsources
Saw this example in news feed on linkedin, author was Shai Mishali (who originally saw it from Eran Lunenfeld in his turn) and decided to reproduce myself ))
Think it was nice challenge ))
Try to make it yourself!
#trytodo #howto #tasty #groovy #getsources