Home > Blockchain >  How to adapt frame of half circle to its size
How to adapt frame of half circle to its size

Time:10-03

I am making an app where I need to use half circle. But I can't make its frame match the real size of the object. Right now I am trimming the circle but I don't really know you to actually crop the view.

Here is how I trimming the circle:

Circle()
   .trim(from: 0, to: 0.5)
   .fill(Color.blue)
   .background(Color.red)

And I am getting colour red as background twice bigger the my new object.

CodePudding user response:

It's probably better to make your own HalfCircle that conforms to Shape instead of trying to bash Circle into the shape you need. Let's go the extra mile and make it conform to InsettableShape, in case you want to use it to stroke a border.

import SwiftUI

struct HalfCircle: InsettableShape {
    var _inset: CGFloat = 0

    func inset(by amount: CGFloat) -> Self {
        var copy = self
        copy._inset  = amount
        return copy
    }

    func path(in rect: CGRect) -> Path {
        var path = Path()

        // This is a half-circle centered at the origin with radius 1.
        path.addArc(
            center: .zero,
            radius: 1,
            startAngle: .zero,
            endAngle: .radians(.pi),
            clockwise: false
        )
        path.closeSubpath()

        // Since it's the bottom half of a circle, we only want
        // to inset the left, right, and bottom edges of rect.
        let rect = rect
            .insetBy(dx: _inset, dy: 0.5 * _inset)
            .offsetBy(dx: 0, dy: -(0.5 * _inset))

        // This transforms bounding box of the path to fill rect.
        let transform = CGAffineTransform.identity
            .translatedBy(x: rect.origin.x   0.5 * rect.size.width, y: 0)
            .scaledBy(x: rect.width / 2, y: rect.height)

        return path.applying(transform)
    }
}

We can use it to draw this:

the bottom half of a circle

using this playground:

import PlaygroundSupport

PlaygroundPage.current.setLiveView(HalfCircle()
    .inset(by: 20)
    .fill(.black)
    .background(.gray)
    .aspectRatio(2, contentMode: .fit)
    .frame(width: 200)
    .padding()
)

CodePudding user response:

You can mask it differently using a GeometryReader:

GeometryReader { proxy in
    Circle()
        .fill(.blue)
        .offset(y: -proxy.size.height) // <- Shows bottom part
        .frame(height: proxy.size.width) // <- Makes the circle match frame
        .background(.red) // <- Just for testing
}
.aspectRatio(2, contentMode: .fit) // <- Makes the frame ration 2 : 1 (landscape rectangle)
.clipped() // <- Removes out of bound drawings

Demo

  • Related