Как я могу увеличить размер CGRect на определенное процентное значение?

Как я могу увеличить размер CGRect на определенное процентное значение? Должен ли я использовать какую-либо форму CGRectInset для этого?

Пример:

Предположим, у меня есть CGRect: {10, 10, 110, 110}

Я хочу увеличить его размер (сохранив ту же центральную точку) на 20% до:

{0, 0, 120, 120}


person brandonscript    schedule 13.11.2014    source источник
comment
в 2017 году это insetBy   -  person Fattie    schedule 12.02.2017


Ответы (7)


Вы можете использовать CGRectInset, если хотите:

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

Чтобы уменьшить размер, удалите -s.

Примечание. Число CGRect, которое на 20 % больше числа {10, 10, 100, 100}, равно {0, 0, 120, 120}.


Редактировать: если предполагается увеличить площадь, то это будет сделано (даже для прямоугольников, которые не являются квадратными):

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);
person Ian MacDonald    schedule 13.11.2014
comment
Побочное примечание: я думаю, что Ремус прав в том, что (110 110) дает площадь на 20% больше, чем (100 100). - person thelaws; 14.11.2014
comment
Я полагаю, это зависит от вашей интерпретации на 20% больше. По площади результирующий квадрат имеет ребра длиной 109.5445, что не так красиво, как просто предположить, что он хотел увеличить размер ребра на 20%. - person Ian MacDonald; 14.11.2014
comment
Я имел в виду увеличение размеров ребер, но вы правы, площадь будет совершенно другим расчетом, и это хороший ответ. - person brandonscript; 14.11.2014
comment
Хорошо, что я включил оба. :) - person Ian MacDonald; 14.11.2014
comment
Выбрано в качестве ответа, потому что ^ - person brandonscript; 14.11.2014
comment
это insetBy в последней версии Swift, приветствую @IanMacDonald - person Fattie; 12.02.2017

В Свифте:

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
person Logan    schedule 13.11.2014
comment
Вопрос помечен как Objective-C. Лучше всего давать ответы на желаемом языке. - person rmaddy; 14.11.2014
comment
+1 за то, что до сих пор был единственным ответившим, который подчинился заявлению Apple о том, что ваши приложения должны избегать прямого чтения и записи данных, хранящихся в структуре данных CGRect. Вместо этого используйте описанные здесь функции для управления прямоугольниками и получения их характеристик.developer.apple.com/Library/ios/documentation/GraphicsImaging/ - person Tommy; 14.11.2014
comment
Заявление Apple глупо. Я обновил свой ответ, чтобы соответствовать ему в любом случае. :/ - person Ian MacDonald; 14.11.2014
comment
Близко второе, и мне действительно нравится этот ответ, так как в нем есть и Objc, и Swift;) - person brandonscript; 14.11.2014
comment
Глядя на это снова, разве выходной прямоугольник не должен быть -1, -1, 11, 11? - person brandonscript; 18.11.2016

Конечно, использование CGRectInset работает:

CGRect someRect = CGRectMake(10, 10, 100, 100);
someRect = CGRectInset(someRect, someRect.size.width * -0.2, someRect.size.height * -0.2);
person rmaddy    schedule 13.11.2014

Расширение 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))
    }
}
person gheclipse    schedule 25.10.2018

Я использую CGRect > insetBy в своем коде Swift.

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

При этом ваше процентное значение будет scaleX, как в моем примере.

    let dx = rectWidth*scaleX
    let dy = rectHeight*scaleX
    let rectangle = CGRect(x: rectX,
                           y: rectY,
                           width: rectWidth,
                           height: rectHeight).insetBy(dx: -dx, dy: -dy)
  • используйте положительное значение для уменьшения масштаба
  • используйте отрицательное значение для масштабирования
person ihsanberahim    schedule 28.01.2019

Используя 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)
person Nick    schedule 16.03.2015
comment
Расширение CGRect удобное, но этот код работает некорректно. newX и newY должны быть добавлены к началу координат (x, y). пусть newX = x + (w - newW)/2 - person gheclipse; 25.10.2018

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

Остерегайтесь, что этот подход также изменит x и y прямоугольника.

person Taras    schedule 28.08.2017
comment
Кажется, что это не масштабируется относительно центра прямоугольника, поэтому не меняет начало координат x, y. - person lhunath; 12.02.2018
comment
Как говорится в приведенном выше комментарии, это не сохраняет центральную точку прямоугольника! - person Harry Bloom; 22.04.2018