0

I created a form in SwiftUI. There's one place I can't make round. Can you help?

This is my code :

struct BannerShape: Shape {
    func path(in rect: CGRect) -> Path {
        return Path { path in
            path.move(to: .zero)
            path.addLine(to: CGPoint(x: 0, y: 100))
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 100))
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 0))
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width / 2 + 48, y: 0))
            path.addCurve(to: CGPoint(x: UIScreen.main.bounds.width / 2 - 48, y: 0),
                          control1: CGPoint(x: UIScreen.main.bounds.width / 2 + 80, y: 105),
                          control2: CGPoint(x: UIScreen.main.bounds.width / 2 - 80, y: 105))
            path.addLine(to: .zero)
            path.closeSubpath()
        }
    }
}

In my preview :

struct TabBarBackgroundView_Previews: PreviewProvider {
    
//    @State static var selectedTabPreview: Int = 0
    
    static var previews: some View {
//        TabBarBackgroundView(selectedTab: $selectedTabPreview)
        
        BannerShape()
            .cornerRadius(15, corners: [.topLeft, .topRight])
            .previewLayout(.sizeThatFits)
            .frame(width: UIScreen.main.bounds.width, height: 100)
            .padding()
    }
}

The result :

Result

And I want to round off the two corners near the circle, for the moment it forms a point.

I haven't found anything to do this.

That's what I tried :

struct MyShape : Shape {
    func path(in rect: CGRect) -> Path {
        
        return Path { path in
            path.move(to: .zero)
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width / 2 - 48, y: 0))
            
            path.addArc(center: CGPoint(x: UIScreen.main.bounds.width / 2 - 48, y: 10),
                        radius: 10,
                        startAngle: .degrees(-90),
                        endAngle: .degrees(0),
                        clockwise: false)
            
            path.addCurve(to: CGPoint(x: UIScreen.main.bounds.width / 2 + 48, y: 0),
                          control1: CGPoint(x: UIScreen.main.bounds.width / 2 - 80, y: 105),
                          control2: CGPoint(x: UIScreen.main.bounds.width / 2 + 80, y: 105))
                        
            path.addArc(center: CGPoint(x: UIScreen.main.bounds.width / 2 + 48, y: 10),
                        radius: 10,
                        startAngle: .degrees(-90),
                        endAngle: .degrees(-180),
                        clockwise: true)
            
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 0))
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 100))
            path.addLine(to: CGPoint(x: 0, y: 100))
            path.addLine(to: .zero)
            path.closeSubpath()
        }
    }
}

And the result...

Result test

KaayZenn
  • 103
  • 7
  • Take a look at this answer -- https://stackoverflow.com/a/71960280/6257435 – DonMag Jun 10 '23 at 11:23
  • What a perfect answer to this question! (Although in this question there are circles of different radii. The OP may well want corners near the circle with the same rounding radius as the outer 2 rounded corners.) – Duncan C Jun 10 '23 at 18:21
  • @DonMag I've updated the post with what I've tried. One corner is OK but the second is no good. – KaayZenn Jun 10 '23 at 19:33

1 Answers1

2

Soooo close :)

The center.x of your first .addArc is at:

UIScreen.main.bounds.width / 2 - 48

and you put the center.x of your second .addArc at:

UIScreen.main.bounds.width / 2 + 48

which is logical.

However, when you add the first arc with a radius of 10, your quad-curve x will be starting 10-points farther (to the right) ... so, you need to end the quad-curve 10-points shorter (to the left):

// need to subtract an additional 10-points
//  for the 10-point radius
path.addCurve(to: CGPoint(x: UIScreen.main.bounds.width / 2 + (48 - 10), y: 10),
              control1: CGPoint(x: UIScreen.main.bounds.width / 2 - 80, y: 105),
              control2: CGPoint(x: UIScreen.main.bounds.width / 2 + 80, y: 105))

And, your second .addArc also needs clockwise: false (I think SwiftUI is quirky with clockwise, but you can find the explanation here: https://stackoverflow.com/a/57226474/6257435)

Here's your code with those modifications:

struct MyShape : Shape {
    func path(in rect: CGRect) -> Path {
        
        return Path { path in
            path.move(to: .zero)
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width / 2 - 48, y: 0))

            path.addArc(center: CGPoint(x: UIScreen.main.bounds.width / 2 - 48, y: 10),
                        radius: 10,
                        startAngle: .degrees(-90),
                        endAngle: .degrees(0),
                        clockwise: false)

            // need to subtract an additional 10-points
            //  for the 10-point radius
            path.addCurve(to: CGPoint(x: UIScreen.main.bounds.width / 2 + (48 - 10), y: 10),
                          control1: CGPoint(x: UIScreen.main.bounds.width / 2 - 80, y: 105),
                          control2: CGPoint(x: UIScreen.main.bounds.width / 2 + 80, y: 105))

            path.addArc(center: CGPoint(x: UIScreen.main.bounds.width / 2 + 48, y: 10),
                        radius: 10,
                        startAngle: .degrees(-180),
                        endAngle: .degrees(-90),
                        clockwise: false)

            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 0))
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 100))
            path.addLine(to: CGPoint(x: 0, y: 100))
            path.addLine(to: .zero)
            path.closeSubpath()
        }

    }
    
}

and we get this:

enter image description here

You can get a bit smoother of a curve if you use the .addArc(tangent1End:tangent2End:radius:) format:

struct MyShape2 : Shape {
    func path(in rect: CGRect) -> Path {
        
        return Path { path in
            path.move(to: .zero)
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width / 2 - 48, y: 0))
            
            var pt1: CGPoint = .zero
            var pt2: CGPoint = .zero
            
            pt1 = .init(x: UIScreen.main.bounds.width / 2 - 48 + 10, y: 0)
            pt2 = .init(x: UIScreen.main.bounds.width / 2 - 48 - 10, y: 105)
            path.addArc(tangent1End: pt1, tangent2End: pt2, radius: 10)
            
            let p3 = path.currentPoint!
            path.addCurve(to: CGPoint(x: UIScreen.main.bounds.width - p3.x, y: p3.y),
                          control1: CGPoint(x: UIScreen.main.bounds.width / 2 - 80, y: 105),
                          control2: CGPoint(x: UIScreen.main.bounds.width / 2 + 80, y: 105))
            
            pt1 = .init(x: UIScreen.main.bounds.width / 2 + 48 - 10, y: 0)
            pt2 = .init(x: UIScreen.main.bounds.width / 2 + 48 + 10, y: 0)
            path.addArc(tangent1End: pt1, tangent2End: pt2, radius: 10)
            
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 0))
            path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 100))
            path.addLine(to: CGPoint(x: 0, y: 100))
            path.addLine(to: .zero)
            path.closeSubpath()
        }
        
    }
    
}

which gives us this result:

enter image description here

DonMag
  • 69,424
  • 5
  • 50
  • 86