Working with SwiftUI is a joy and help you build quite a bunch of great stuff. From an idea to a real word application, SwiftUI is really fast at implementing, coding. Unfortunately, there is some downside. Some old libraries, stable and offer the functionality we are looking for, are no problem free.
Apple’s support method for using UIKit or AppKit components in SwiftUI is called ViewRepresentable
which can be tricky and sometimes does not really work as intended. You can read about it here. But when blockage happen, all you have to do is write it yourself. This was the story behind the component I will introduce you in this article.
HyCarousel
Completely written in SwiftUI, using native components and methods. HyCarousel is a real simple to use, simple to reproduce, modify the way you want and integrate to your application. It’s basically a ForEach structure, computes a set of given views but re-renders differently.
While making these components available as CocoaPod and OpenSource, I tried to make it as easy as Apple does with their structures implementations and calls.
Requirements
Unfortunately, HyCarousel requires SwiftUI 2.0. Available with Xcode 12 and will run only on iOS 14, watchOS 7 and macOS 11 Big Sur.
Apple’s first version of SwiftUI had all the components that we need to build and publish an application. But those core components were basic and were missing some key functionalities to be tagged as fully usable.
Core Components
SwiftUI 2.0's updated ScrollView and ScrollViewReader were the main components that made this view achievable. Precisely the second, offers a proxyReader
which let us control the carousel programmatically and report the current offset. It’s basically UIKit’s ScrollViewDelegate
which you implement, so you can manage a Scrollview inside your view.
The idea
Simple as it may sound, the idea was to use a GeometryReader as a parent view and holds the multiple array of subviews which are wrapped in GeometryReader by their own and thanks to SwiftUI, we can actually access the subview’s position in its parent.
This is a graphic representation of the Carousel component, labeling all the views described above.
GeometryReader’s proxy was the key to this view layout. It contains the proposed container size, safe area insets and methods for reading frame values as a CGRect
where we can access (x,y)
positioning properties in custom or global coordinate space
and of course (width,height)
size properties. You can read more about GeometryReader here and coordinate space here.
Using each subview GeometryReader wrapper’s midX
from proxyReader parameter, I was able to compute an Angle(degrees:_)
property and assign it to .rotation3DEffect
modifier on y
axis. View in Red background are considered in the center of the Parent GeometryReader.
Final behavior