How can I increase the size of a CGRect by a certain percent value?

后端 未结 7 2011
春和景丽
春和景丽 2021-02-12 14:22

How can I increase the size of a CGRect by a certain percent value? Should I use some form of CGRectInset to do it?

Example:

Assume I have a CGRect:

相关标签:
7条回答
  • 2021-02-12 14:39

    In Swift:

    func increaseRect(rect: CGRect, byPercentage percentage: CGFloat) -> CGRect {
        let startWidth = CGRectGetWidth(rect)
        let startHeight = CGRectGetHeight(rect)
        let adjustmentWidth = (startWidth * percentage) / 2.0
        let adjustmentHeight = (startHeight * percentage) / 2.0
        return CGRectInset(rect, -adjustmentWidth, -adjustmentHeight)
    }
    
    let rect = CGRectMake(0, 0, 10, 10)
    let adjusted = increaseRect(rect, byPercentage: 0.1)
    // -0.5, -0.5, 11, 11
    

    In ObjC:

    - (CGRect)increaseRect:(CGRect)rect byPercentage:(CGFloat)percentage
    {
        CGFloat startWidth = CGRectGetWidth(rect);
        CGFloat startHeight = CGRectGetHeight(rect);
        CGFloat adjustmentWidth = (startWidth * percentage) / 2.0;
        CGFloat adjustmentHeight = (startHeight * percentage) / 2.0;
        return CGRectInset(rect, -adjustmentWidth, -adjustmentHeight);
    }
    
    CGRect rect = CGRectMake(0,0,10,10);
    CGRect adjusted = [self increaseRect:rect byPercentage:0.1];
    // -0.5, -0.5, 11, 11
    
    0 讨论(0)
  • 2021-02-12 14:41

    You can use CGRectInset if you like:

    double pct = 0.2;
    CGRect newRect = CGRectInset(oldRect, -CGRectGetWidth(oldRect)*pct/2, -CGRectGetHeight(oldRect)*pct/2);
    

    To decrease the size, remove the -s.

    Side note: A CGRect that is 20% bigger than {10, 10, 100, 100} is {0, 0, 120, 120}.


    Edit: If the intention is to increase by area, then this'll do it (even for rectangles that aren't square):

    CGFloat width = CGRectGetWidth(oldRect);
    CGFloat height = CGRectGetHeight(oldRect);
    double pct = 1.2; // 20% increase
    double newWidth = sqrt(width * width * pct);
    double newHeight = sqrt(height * height * pct);
    CGRect newRect = CGRectInset(oldRect, (width-newWidth)/2, (height-newHeight)/2);
    
    0 讨论(0)
  • 2021-02-12 14:44

    Sure, using CGRectInset works:

    CGRect someRect = CGRectMake(10, 10, 100, 100);
    someRect = CGRectInset(someRect, someRect.size.width * -0.2, someRect.size.height * -0.2);
    
    0 讨论(0)
  • 2021-02-12 14:51

    Using Swift you can retain the center point (relative to the source Rect) and increase/decrease the size as follows using an extension:

    extension CGRect {
        func centerAndAdjustPercentage(percentage p: CGFloat) -> CGRect {
            let x = self.origin.x
            let y = self.origin.y
            let w = self.width
            let h = self.height
    
            let newW = w * p
            let newH = h * p
            let newX = (w - newW) / 2
            let newY = (h - newH) / 2
    
            return CGRect(x: newX, y: newY, width: newW, height: newH)
        }
    }
    let newRect = oldRect.centerAndAdjustPercentage(percentage: 0.25)
    
    0 讨论(0)
  • 2021-02-12 14:52

    I'm using CGRect > insetBy in my Swift code

    https://developer.apple.com/documentation/coregraphics/cgrect/1454218-insetby

    With this, your percent value will be the scaleX as my example.

        let dx = rectWidth*scaleX
        let dy = rectHeight*scaleX
        let rectangle = CGRect(x: rectX,
                               y: rectY,
                               width: rectWidth,
                               height: rectHeight).insetBy(dx: -dx, dy: -dy)
    
    • use positive value to scale down
    • use negative value to scale up
    0 讨论(0)
  • 2021-02-12 14:57

    Swift 4 extension inspired by several of the answers here with simplified calculations:

    extension CGRect {
        func scaleLinear(amount: Double) -> CGRect {
            guard amount != 1.0, amount > 0.0 else { return self }
            let ratio = ((1.0 - amount) / 2.0).cgFloat
            return insetBy(dx: width * ratio, dy: height * ratio)
        }
    
        func scaleArea(amount: Double) -> CGRect {
            return scaleLinear(percent: sqrt(amount))
        }
    
        func scaleLinear(percent: Double) -> CGRect {
            return scaleLinear(amount: percent / 100)
        }
    
        func scaleArea(percent: Double) -> CGRect {
            return scaleArea(amount: percent / 100)
        }
    }
    

    Usage is simply:

    rect.scaleLinear(percent: 120.0)  OR (amount: 1.2)
    rect.scaleArea(percent: 120.0)  OR (amount: 1.2)
    

    If you are interested in trying my testing methods:

    /// Testing
    extension CGRect {
        var area: CGFloat { return width * height }
        var center: CGPoint { return CGPoint(x: origin.x + width/2, y: origin.y + height/2)
        }
    
        func compare(_ r: CGRect) {
            let centered = center.x == r.center.x && center.y == r.center.y
            print("linear = \(r.width / width), area = \(r.area / area) centered \(centered)")
        }
    
        static func ScaleTest() {
            let rect = CGRect(x: 17, y: 24, width: 200, height: 100)
            let percent = 122.6
            rect.compare(rect.scaleLinear(percent: percent))
            rect.compare(rect.scaleArea(percent: percent))
        }
    }
    
    0 讨论(0)
提交回复
热议问题