DevSirius
DevSirius

Reputation: 137

SwiftUI simple view, need a push into right direction

I am complete beginner with SwiftUI and I can't wrap my head around how to connect these images with views that represents lines. Now I simply have 3 VStacks with image and text and put them into a HStack, but don't know how to connect these images with a line shown in red in the picture I attached. Note that there's some space between the line and the image. I need general direction and some hints, full working code not necessary.

Thank you.

3 boxes, arranged horizontally, with image inside. Below each box there is a Text. In between each box is red line.

Upvotes: 0

Views: 443

Answers (3)

swiftPunk
swiftPunk

Reputation: 1

Version 1.0.0

I decided to give my answer which is same like aheze answer with this difference that you can have CustomVerticalAlignment as well! As I see in your Image in question you want that also:


with CustomVerticalAlignment: In center! enter image description here

without CustomVerticalAlignment: off center!

enter image description here


import SwiftUI

struct ContentView: View {
    var body: some View {
        
        HStack(alignment: .customVerticalAlignment) {
            
            VStack {
                Image(systemName: "star")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 50, height: 50, alignment: .center)
                    .padding()
                    .border(Color.black, width: 5)
                    .alignmentGuide(.customVerticalAlignment) { d in d[VerticalAlignment.center] }
                
                Text("Text")
            }
            
            Capsule()
                .fill(Color.red)
                .frame(height: 5)
                .alignmentGuide(.customVerticalAlignment) { d in d[VerticalAlignment.center] }
            
            VStack {
                Image(systemName: "star")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 50, height: 50, alignment: .center)
                    .padding()
                    .border(Color.black, width: 5)
                    .alignmentGuide(.customVerticalAlignment) { d in d[VerticalAlignment.center] }
                
                Text("Text")
            }
            
            Capsule()
                .fill(Color.red)
                .frame(height: 5)
                .alignmentGuide(.customVerticalAlignment) { d in d[VerticalAlignment.center] }
            
            VStack {
                Image(systemName: "star")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 50, height: 50, alignment: .center)
                    .padding()
                    .border(Color.black, width: 5)
                    .alignmentGuide(.customVerticalAlignment) { d in d[VerticalAlignment.center] }
                
                Text("Text")
            }
            
        }
        .padding()
    }
}


extension VerticalAlignment {
    
    struct CustomVerticalAlignment: AlignmentID {
        
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            d[VerticalAlignment.center]
        }
        
    }
    
    static let customVerticalAlignment = VerticalAlignment(CustomVerticalAlignment.self)
    
}

Update Version 2.0.0

About this version: I would say it does the same job of version 1.0.0 in less code and also Text and Line are not depending on VStack or eachother any moere!


enter image description here


import SwiftUI

struct ContentView: View {
    
    var body: some View {
        
        HStack {
            
            image.overlay(text.offset(y: 40), alignment: .bottom)
            
            capsule
            
            image.overlay(text.offset(y: 40), alignment: .bottom)
            
            capsule
            
            image.overlay(text.offset(y: 40), alignment: .bottom)
            
        }
        .padding(50)
    }

    var image: some View {
        
        return Image(systemName: "star.fill")
            .resizable()
            .scaledToFit()
            .padding(10)
            .shadow(radius: 10)
            .frame(width: 50, height: 50, alignment: .center)
            .foregroundColor(Color.red)
            .background(Color.yellow)
            .border(Color.black, width: 5)
        
    }
    
    var capsule: some View {
        
        return Capsule()
            .fill(Color.red)
            .frame(height: 5)
        
    }
    
    var text: some View {
        
        return Text("Hello World!")
            .lineLimit(1)
            .fixedSize()
        
    }
    
}

Upvotes: 2

aheze
aheze

Reputation: 30336

How's this?

3 boxes with smiley inside and text below. Red line between boxes

In SwiftUI, you use HStacks and VStacks to stack your Views. For the red line, a Rectangle should do. Here's the code:

struct ContentView: View {
    var body: some View {
        
        HStack { /// horizontal stack
            
            VStack {
                Image(systemName: "face.smiling")
                    .font(.system(size: 80))
                    .padding()
                    .border(Color.black, width: 5)
                    
                Text("Text TEXTEXT")
            }
            
            Rectangle()
                .fill(Color.red)
                .frame(height: 5)
            
            VStack {
                Image(systemName: "face.smiling")
                    .font(.system(size: 80))
                    .padding()
                    .border(Color.black, width: 5)
                    
                Text("Text TEXTEXT")
            }
            
            Rectangle()
                .fill(Color.red)
                .frame(height: 5)
            
            VStack {
                Image(systemName: "face.smiling")
                    .font(.system(size: 80))
                    .padding()
                    .border(Color.black, width: 5)
                    
                Text("Text TEXTEXT")
            }
            
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewLayout(.fixed(width: 800, height: 200))
    }
}

Upvotes: 2

jnpdx
jnpdx

Reputation: 52407

You could define a Shape that represents your line.

I used the spacing parameter of HStack to do the spacing:

struct MyLine : Shape {
    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: CGPoint(x: 0, y: rect.midY))
            path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
        }
    }
}

struct ContentView: View {
    var body: some View {
        HStack(spacing: 10) {
            VStack {
                Image(systemName: "pencil")
                Text("Label")
            }
            MyLine().stroke(Color.red)
            VStack {
                Image(systemName: "pencil")
                Text("Label 2")
            }
            MyLine().stroke(Color.red)
            VStack {
                Image(systemName: "pencil")
                Text("Label 3")
            }
        }
    }
}

You could add a lineWidth parameter to make the stroke thicker:

.stroke(Color.red, lineWidth: 4)

Also, if you didn't using spacing on the HStack, you could using a padding modifier on either the VStacks or the MyLines to get the spacing.

Upvotes: 1

Related Questions