如何将CGRect的尺寸按一定百分比增加?

22
如何按照一定的百分比值增加CGRect的大小?我应该使用某种形式的CGRectInset吗?
示例: 假设我有一个CGRect:{10, 10, 110, 110} 我想将其大小增加20%(保持相同的中心点)以获得: {0, 0, 120, 120}

4
2017年,它是“insetBy”。 - Fattie
7个回答

43

如果你喜欢的话,你可以使用CGRectInset

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

为了缩小尺寸,请删除 -

Side note: 比 {10, 10, 100, 100} 大 20% 的 CGRect{0, 0, 120, 120}


Edit: 如果意图是通过面积增加大小,则可以这样做(即使对于不是正方形的矩形也可以):

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);

关于旁注:我认为Remus是正确的,(110,110)比(100,100)的面积大20%。 - thelaws
1
我想这取决于你对“20%更大”一词的理解。根据面积计算,得到的正方形边长为109.5445,这并不像假设他只是增加了边长20%那样简单明了。 - Ian MacDonald
1
我的意思是增加边缘大小,但你说得对,面积将是完全不同的计算,这是一个好答案。 - brandonscript
好在我都包含了。 :) - Ian MacDonald
因为被选为答案 ^ - brandonscript
这是最新的Swift中的insetBy,感谢@IanMacDonald。 - Fattie

12

在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
在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

1
这个问题标记为Objective-C。最好用所需语言给出答案。 - rmaddy
2
目前为止,您是唯一遵守苹果声明的回答者之一:“您的应用程序应避免直接读写存储在CGRect数据结构中的数据。而是使用此处描述的函数来操作矩形并检索其特征。”-https://developer.apple.com/Library/ios/documentation/GraphicsImaging/Reference/CGGeometry/index.html - Tommy
2
苹果公司的声明很荒谬。不过我还是更新了我的回答以符合它。:/ - Ian MacDonald
1
紧随其后,我实际上也喜欢这个答案,因为它既有 Objc 又有 Swift ;) - brandonscript
再看一遍,输出矩形应该是 -1,-1,11,11 吧? - brandonscript

6

这是一款受此处多个答案启发的Swift 4扩展,其中简化了计算:

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)
    }
}

使用方法很简单:

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

如果您有兴趣尝试我的测试方法:

/// 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))
    }
}

6
当然,使用CGRectInset是可行的:
CGRect someRect = CGRectMake(10, 10, 100, 100);
someRect = CGRectInset(someRect, someRect.size.width * -0.2, someRect.size.height * -0.2);

3
我在我的Swift代码中使用了CGRect > insetBy。
使用这个方法,你的百分比值将会是像我例子中的scaleX
参考链接:https://developer.apple.com/documentation/coregraphics/cgrect/1454218-insetby
    let dx = rectWidth*scaleX
    let dy = rectHeight*scaleX
    let rectangle = CGRect(x: rectX,
                           y: rectY,
                           width: rectWidth,
                           height: rectHeight).insetBy(dx: -dx, dy: -dy)
  • 使用正值进行缩小
  • 使用负值进行放大

2

使用Swift,您可以使用扩展保留中心点(相对于源矩形),并按以下方式增加/减少大小:

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)

CGRect扩展很方便,但是这段代码不正确。newX和newY应该添加到原点(x,y)中。让newX = x +(w-newW)/ 2 - gheclipse

0
let scale = percent / 100
let newRect = oldRect.applying(CGAffineTransform(scaleX: scale, y: scale))

请注意,这种方法也会改变矩形的 x 和 y 值。


1
这似乎与矩形中心的比例不一致,因此不会改变x,y原点。 - lhunath
1
正如上面的评论所述,这并没有保持矩形的中心点! - Harry Bloom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接