sonja
sonja

Reputation: 934

SwiftUI: How to overlay an image with multiple shapes and dependent positioning

I'd like to place several shapes(Rectangles) over an image but the rectangles should have fixed positions on the image. So no matter what screen-size or screen-orientation, a rectangle should always cover the same content of the image. So in the following image, I for instance would like a rectangle covering the legs, another one covering the arms and a third one covering the abs and back.

Example image

My ImageView looks like that:

struct ImageView: View {
    @ObservedObject var imageName: ImageName
    var size: CGSize
    var body: some View {
        VStack {
            Image(self.imageName.name)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: size.width, height: size.width, alignment: .center)

        }
    }
}

And together with the rectangles it is embedded in my main view:

struct MuscleGuy: View {
    @ObservedObject var imageName = ImageName()
    var body: some View {
        VStack(alignment: .center) {
            Spacer()
            ZStack(alignment: .center) {
                GeometryReader { geometry in
                    RectangleView( imageName: self.imageName).zIndex(10)
                    ImageView(imageName: self.imageName, size: geometry.size).zIndex(2)
                        .position(x: geometry.size.width/2, y: geometry.size.height/2)
                }
            }
        }
    }
}

Currently, I'm kind of hardcoding the size and position of the rectangles, for instance the legs:

Rectangle().foregroundColor(.blue)
    .frame(width: size.width, height: size.height/7)
    .position(x: size.width/2, y: size.height/2+80)

But obviously that doesn't work as soon as the screen size/orientation changes.

What's the best attempt to adjust the size and position of the rectangles to the image?

//UPDATE

VStack {
    Spacer()
    ZStack {
        Rectangle()
         .frame(width:self.imageProperties.width, height:  self.imageProperties.height/2)
         .border(Color.pink, width: 3)
         .zIndex(20)
         .foregroundColor(Color.clear)
         .position(x: self.imageProperties.minX, y: self.imageProperties.maxY)

        ImageView(imageName: self.imageName, imageProps: self.imageProperties).zIndex(2)
       }
    Spacer()
}

Leading to the following outcome: updated image

so I assume, the positioning is done according to the whole screen, and not the image position itself..

Upvotes: 0

Views: 6989

Answers (2)

Chris
Chris

Reputation: 8116

you could also use relativeWidth/height, which existed some time ago and which is shown here https://vmanot.com/reimplementing-swiftui-s-deprecated-relative-view-sizing-functions as reimplentation

Upvotes: 0

Ralf Ebert
Ralf Ebert

Reputation: 4092

Placing a View relative to an Image (at 90% of the width/height in the example):

struct RelativePositionExampleView: View {
    var body: some View {
        Image("cookies")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .overlay(
                GeometryReader { geometry in
                    Text("Hello")
                        .background(Color.red)
                        .position(x: geometry.size.width * 0.9, y: geometry.size.height * 0.9)
                }
            )
    }
}

Upvotes: 1

Related Questions