Рамка iOS меняет одно свойство (например, ширина) - PullRequest
39 голосов
/ 02 марта 2012

Этот вопрос изначально задавался для языка программированияjective-c. На момент написания статьи swift еще даже не существовало.

Вопрос

Можно ли изменить только одно свойство CGRect?

Например:

self.frame.size.width = 50;

вместо

self.frame = CGRectMake(self.frame.origin.x, 
                        self.frame.origin.y, 
                        self.frame.size.width, 
                        50);

конечно, я понимаю, что self.frame.size.width это только для чтения , поэтому мне интересно, как это сделать?

АНАЛОГИЯ CSS действуйте на свой страх и риск

для тех из вас, кто знаком с CSS, идея очень похожа на использование:

margin-left: 2px;

вместо того, чтобы менять целое значение:

margin: 5px 5px 5px 2px;

Ответы [ 9 ]

95 голосов
/ 02 марта 2012

Чтобы ответить на ваш первоначальный вопрос: да, можно изменить только одного члена структуры CGRect.Этот код не выдает ошибок:

myRect.size.width = 50;

То, что невозможно , возможно, однако, это изменение одного члена CGRect, который сам является свойством другого объекта.В этом очень распространенном случае вам придется использовать временную локальную переменную:

CGRect frameRect = self.frame;
frameRect.size.width = 50;
self.frame = frameRect;

Причина этого заключается в том, что использование свойства accessor self.frame = ... эквивалентно [self setFrame:...], и этот метод доступа всегда ожидаетвсего CGRect.Смешивание доступа в стиле C struct с точечной нотацией свойства Objective-C в этом случае не работает.

28 голосов
/ 02 января 2013

Мне понравился Ответ Ахмеда Халафа , но мне пришло в голову, что вы также можете просто написать несколько функций на Си ... главное преимущество в том, что будет легче отслеживать ошибки событие, которое вы используете неправильный тип.

Сказав это, я написал файл .h с такими объявлениями функций:

CGRect CGRectSetWidth(CGRect rect, CGFloat width);
CGRect CGRectSetHeight(CGRect rect, CGFloat height);
CGRect CGRectSetSize(CGRect rect, CGSize size);
CGRect CGRectSetX(CGRect rect, CGFloat x);
CGRect CGRectSetY(CGRect rect, CGFloat y);
CGRect CGRectSetOrigin(CGRect rect, CGPoint origin);

И соответствующий файл .m с этими реализациями функций:

CGRect CGRectSetWidth(CGRect rect, CGFloat width) {
    return CGRectMake(rect.origin.x, rect.origin.y, width, rect.size.height);
}

CGRect CGRectSetHeight(CGRect rect, CGFloat height) {
    return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, height);
}

CGRect CGRectSetSize(CGRect rect, CGSize size) {
    return CGRectMake(rect.origin.x, rect.origin.y, size.width, size.height);
}

CGRect CGRectSetX(CGRect rect, CGFloat x) {
    return CGRectMake(x, rect.origin.y, rect.size.width, rect.size.height);
}

CGRect CGRectSetY(CGRect rect, CGFloat y) {
    return CGRectMake(rect.origin.x, y, rect.size.width, rect.size.height);
}

CGRect CGRectSetOrigin(CGRect rect, CGPoint origin) {
    return CGRectMake(origin.x, origin.y, rect.size.width, rect.size.height);
}

Итак, теперь, чтобы делать то, что вы хотите, вы можете просто сделать:

self.frame = CGRectSetWidth(self.frame, 50);

Получить даже Любитель (обновление я сделал год спустя)

Это имеет избыточный self.frame в нем, хотя. Чтобы это исправить, вы можете добавить category на UIView с помощью методов, которые выглядят так:

- (void) setFrameWidth:(CGFloat)width {
    self.frame = CGRectSetWidth(self.frame, width); // You could also use a full CGRectMake() function here, if you'd rather.
}

А теперь вы можете просто набрать:

[self setFrameWidth:50];

Или, еще лучше:

self.frameWidth = 50;

И просто так вы можете сделать что-то вроде этого:

self.frameWidth = otherView.frameWidth; // as opposed to self.frameWidth = otherView.frame.size.width;

Вы также должны иметь это в своей категории:

- (CGFloat) frameWidth {
    return self.frame.size.width;
}

Наслаждайтесь.

6 голосов
/ 05 сентября 2014

Основано на решении ArtOfWarfare (что действительно здорово). Я создал категорию UIView без Си-функций.

Примеры использования:

[self setFrameWidth:50];
self.frameWidth = 50;
self.frameWidth += 50;
self.frameWidth = otherView.frameWidth; // as opposed to self.frameWidth = otherView.frame.size.width;

Заголовочный файл UIView+easy_frame.h:

@interface UIView (easy_frame)

- (void) setFrameWidth:(CGFloat)width;
- (void) setFrameHeight:(CGFloat)height;
- (void) setFrameX:(CGFloat)x;
- (void) setFrameY:(CGFloat)y;

- (CGFloat) frameWidth;
- (CGFloat) frameHeight;
- (CGFloat) frameX;
- (CGFloat) frameY;

Файл реализации UIView+easy_frame.m:

#import "UIView+easy_frame.h"
@implementation UIView (easy_frame)

# pragma mark - Setters

- (void) setFrameWidth:(CGFloat)width
{
  self.frame = CGRectMake(self.frame.origin.x,
                          self.frame.origin.y,
                          width,
                          self.frame.size.height);
}

- (void) setFrameHeight:(CGFloat)height
{
  self.frame = CGRectMake(self.frame.origin.x,
                          self.frame.origin.y,
                          self.frame.size.width,
                          height);
}

- (void) setFrameX:(CGFloat)x
{
  self.frame = CGRectMake(x,
                          self.frame.origin.y,
                          self.frame.size.width,
                          self.frame.size.height);
}

- (void) setFrameY:(CGFloat)y
{
  self.frame = CGRectMake(self.frame.origin.x,
                          y,
                          self.frame.size.width,
                          self.frame.size.height);
}

# pragma mark - Getters

- (CGFloat) frameWidth
{
  return self.frame.size.width;
}

- (CGFloat) frameHeight
{
  return self.frame.size.height;
}

- (CGFloat) frameX
{
  return self.frame.origin.x;
}

- (CGFloat) frameY
{
  return self.frame.origin.y;
}
4 голосов
/ 19 сентября 2012

Если вам понадобится выполнить такую ​​модификацию отдельных компонентов, возможно, стоит иметь такие макросы, доступные где-нибудь из вашего кода:

#define CGRectSetWidth(rect, w)    CGRectMake(rect.origin.x, rect.origin.y, w, rect.size.height)
#define ViewSetWidth(view, w)   view.frame = CGRectSetWidth(view.frame, w)

Таким образом, когда вам нужно изменить ширину в одиночку - вы просто напишите

ViewSetWidth(self, 50);

вместо

self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, 50);
2 голосов
/ 13 февраля 2015

В Swift вы можете расширить класс UIView для приложения, так, что вы могли бы, например, переместить представление заголовка таблицы вверх на 10 пунктов, например:

    tableView.tableHeaderView!.frameAdj(0, -20, 0, 0)

(конечно, если вы используете AutoLayout, это может на самом деле ничего не делать ... :))

Расширяя UIView (влияет на каждый UIView и его подкласс в вашем приложении)

extension UIView {
    func frameAdj(x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) {
            self.frame = CGRectMake(
                self.frame.origin.x + x,
                self.frame.origin.y + y,
                self.frame.size.width  + width,
                self.frame.size.height + height)
    }
}
2 голосов
/ 17 сентября 2014

Исходя из ответа n0_quarter, вот расширение UIView, написанное на Swift:

/**
*  Convenience category for manipulating UIView frames
*/
extension UIView {

    //MARK: - Getters
    func frameX() -> CGFloat {
        return frame.origin.x
    }

    func frameY() -> CGFloat {
        return frame.origin.y
    }

    func frameWidth() -> CGFloat {
        return frame.size.width
    }

    func frameHeight() -> CGFloat {
        return frame.size.height
    }

    //MARK: - Setters
    func setFrameX(x: CGFloat) {
        frame = CGRect(x: x, y: frame.origin.y, width: frame.size.width, height: frame.size.height)
    }

    func setFrameY(y: CGFloat) {
        frame = CGRect(x: frame.origin.x, y: y, width: frame.size.width, height: frame.size.height)
    }

    func setFrameWidth(width: CGFloat) {
        frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: width, height: frame.size.height)
    }

    func setFrameHeight(height: CGFloat) {
        frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width, height: height)
    }
}
0 голосов
/ 03 сентября 2018
-(void) sizeScreen : (UIView *) size : (double) width : (double) height : (double) x : (double) y {
CGRect frameRect = size.frame;
frameRect.size.width = width;
frameRect.size.height = height;
frameRect.origin.x = x;
frameRect.origin.y = y;
self.view.frame = frameRect;

}

это прекрасно работает для меня :)

0 голосов
/ 10 декабря 2015

частый вызов метода setFrame не так хорош, как: setFrameX(x) setFrameY(y) setFrameWidth(width) ...

Вместо этого, в swift мы можем использовать параметры по умолчанию для установки нескольких параметров только в одном вызове:

func setFrame(x x: CGFloat = CGFloat.NaN, y: CGFloat = CGFloat.NaN, width: CGFloat = CGFloat.NaN, height: CGFloat = CGFloat.NaN) {
    let newX = x.isNaN ? self.frame.origin.x : x
    let newY = y.isNaN ? self.frame.origin.y : y
    let newWidth = width.isNaN ? self.bounds.size.width : width
    let newHeight = height.isNaN ? self.bounds.size.height : height

    self.frame = CGRect(x: newX, y: newY, width: newWidth, height: newHeight)
}

тогда для обновления параметров фрейма нужно всего лишь:

setFrame(x: x, width: min(maxX - x, titleLabel.bounds.size.width))
setFrame(width: titleDescriptionLabel.bounds.size.width + 5, height: titleDescriptionLabel.bounds.size.height + 6)
0 голосов
/ 20 ноября 2015

Надеюсь, я еще не опоздал на вечеринку, вот мое решение в ObjC.

Для меня я предпочитаю придерживаться одной функции, а не нескольких функций, и мне нравится подход CSS, представленный постером. Ниже приведена функция, которую я добавляю в свою категорию UIView.

- (void)resetFrame:(CGRect)frame {
CGRect selfFrame = self.frame;
selfFrame.origin = CGPointMake(frame.origin.x>0 ? frame.origin.x : selfFrame.origin.x, frame.origin.y>0 ? frame.origin.y : selfFrame.origin.y);
selfFrame.size = CGSizeMake(frame.size.width>0 ? frame.size.width : selfFrame.size.width, frame.size.height>0 ? frame.size.height : selfFrame.size.height);
[self setFrame:selfFrame]; }

Показанный в примере, он просматривает каждое значение в предоставленном CGRect, и если значение больше 0, это означает, что мы хотим заменить это значение. И, следовательно, вы можете сделать CGRect (0,0,100,0), и он будет предполагать, что мы хотим заменить только ширину.

...