Composing View with ViewModifier

Muhammad Alfiansyah
2 min readSep 28, 2024

--

Instagram Story

Why we Composing View ?

As you know when we deal with view there are reusable component or expandable component, so we can expand or add new view component to current view.

Rather than we repeating code we can expand the view with Builder Pattern. Like you see on the image above when can expand Avatar view by composing them.

From just AvatarView we add RingView on top of that view then we can add ComposeView on top all view before.

So we create view level on our component.

How to Compose View ?

We can composing view using ViewModifer from SwiftUI. With that we can create view with component that we need.

Now we can go to the sample bellow

struct AvatarView: View {
let name: String

var body: some View {
Image(name)
.resizable()
.scaledToFit()
.clipShape(Circle())
}
}
struct RingView: ViewModifier {
@Binding var isLoading: Bool

private let gradient = LinearGradient(
gradient: Gradient(colors: [
Color.yellow,
Color.storyOrange,
Color.storyPink,
Color.storyPurple,
Color.storyDarkPurple
]),
startPoint: .bottomLeading,
endPoint: .topTrailing
)

func body(content: Content) -> some View {
content
.padding(.all, 4)
.overlay {
Circle()
.stroke(
gradient,
style: StrokeStyle(
lineWidth: 2,
dash: [isLoading ? 8 : 0]
)
)
.rotationEffect(.degrees(isLoading ? 360 : 0))
.animation(.default.speed(0.4).repeatForever(autoreverses: false), value: isLoading)
}
}
}
struct ComposeView: ViewModifier {
let systemName: String
let alignment: Alignment
let size: CGSize

init(
systemName: String = "plus",
alignment: Alignment = .bottomTrailing,
size: CGSize = CGSize(width: 24, height: 24)
) {
self.systemName = systemName
self.alignment = alignment
self.size = size
}

func body(content: Content) -> some View {
content
.overlay(alignment: alignment) {
Button {

} label: {
Circle()
.foregroundStyle(.blue)
.frame(width: size.width, height: size.height)
.overlay(Circle().stroke(.white, lineWidth: 2))
.overlay {
Image(systemName: systemName)
.font(.caption.bold())
.foregroundStyle(.white)
}
}
}
}
}

How to Use it ?

AvatarView(name: "img_avatar_1")
.modifier(RingView(isLoading: .constant(false)))
.modifier(ComposeView())
  • First we call AvatarView
  • Second we Add modifier with RingView
  • Third we Add ComposeView to add plus button on top of All

What if I just need AvatarView ?

Just use AvatarView without adding modifier

AvatarView(name: "img_avatar_1")

--

--

No responses yet