'SwiftUI - Add Border to One Edge of an Image

It's a pretty straight-forward question - How does one apply a border effect to only the wanted edges of an Image with SwiftUI?

For example, I only want to apply a border to the top and bottom edges of an image because the image is taking up the entire width of the screen.

Image(mission.missionImageString)
    .resizable()
    .aspectRatio(contentMode: .fit)
    .border(Color.white, width: 2) //Adds a border to all 4 edges

Any help is appreciated!



Solution 1:[1]

Demo

Demo


Implementation

You can use this modifier on any View:

.border(width: 5, edges: [.top, .leading], color: .yellow)

With the help of this simple extension:

extension View {
    func border(width: CGFloat, edges: [Edge], color: Color) -> some View {
        overlay(EdgeBorder(width: width, edges: edges).foregroundColor(color))
    }
}

And here is the magic struct behind this:

struct EdgeBorder: Shape {

    var width: CGFloat
    var edges: [Edge]

    func path(in rect: CGRect) -> Path {
        var path = Path()
        for edge in edges {
            var x: CGFloat {
                switch edge {
                case .top, .bottom, .leading: return rect.minX
                case .trailing: return rect.maxX - width
                }
            }

            var y: CGFloat {
                switch edge {
                case .top, .leading, .trailing: return rect.minY
                case .bottom: return rect.maxY - width
                }
            }

            var w: CGFloat {
                switch edge {
                case .top, .bottom: return rect.width
                case .leading, .trailing: return self.width
                }
            }

            var h: CGFloat {
                switch edge {
                case .top, .bottom: return self.width
                case .leading, .trailing: return rect.height
                }
            }
            path.addPath(Path(CGRect(x: x, y: y, width: w, height: h)))
        }
        return path
    }
}

Solution 2:[2]

If somebody ever needs to just add a quick 1 (or more) sided border to a view (e.g., the top edge, or any random combination of edges), I've found this works well and is tweakable:

top edge:

.overlay(Rectangle().frame(width: nil, height: 1, alignment: .top).foregroundColor(Color.gray), alignment: .top)

leading edge:

.overlay(Rectangle().frame(width: 1, height: nil, alignment: .leading).foregroundColor(Color.gray), alignment: .leading)

etc.

Just tweak the height, width, and edge to produce the combination of borders you want.

Solution 3:[3]

If you don't need to control thickness, you can do this:

.overlay(Divider(), alignment: .top)
.overlay(Divider(), alignment: .bottom)

Set the color of the divider using:

.overlay(Divider().background(.red), alignment: .left)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 smakus
Solution 3 pkamb