iOS框架更改一个属性(例如宽度)

这个问题最初被要求用于Objective-C编程语言。 在写作的时候,斯威夫特还没有存在。

是否有可能只改变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 ANALOGY需要 您自担风险

对于那些熟悉CSS ,这个想法与使用非常类似:

 margin-left: 2px; 

而不必改变整个价值:

 margin: 5px 5px 5px 2px; 

回答你的原始问题:是的,可以改变一个CGRect结构的一个成员。 此代码不会引发错误:

 myRect.size.width = 50; 

然而,不可能改变CGRect的单个成员本身是另一个对象的属性。 在这种常见的情况下,你将不得不使用一个临时的局部variables:

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

原因是使用属性访问器self.frame = ...相当于[self setFrame:...]并且此访问器总是期待整个CGRect 。 在这种情况下,将C风格struct访问与Objective-C属性点符号混合使用效果不佳。

我喜欢艾哈迈德·卡拉夫的回答 ,但是我想到你可能只是写出几个C函数……关键的优势是,如果你使用错误的话会更容易追踪错误types。

话虽如此,我用这些函数声明写了一个.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); 

甚至Fancier (更新我做了一年后)

不过,这里有一个冗余的self.frame 。 为了解决这个问题,你可以用下面的方法在UIView上添加一个category

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

现在你可以input:

 [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; } 

请享用。

基于ArtOfWarfare的解决scheme (这真是太棒了),我已经构build了没有C函数的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; } 

如果你发现自己需要做这种单独的组件修改,那么可能有这样的macros可以访问你的所有代码:

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

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

基于n0_quarter答案,这是一个用Swift编写的UIView扩展:

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

希望我不晚到派对,这是我在ObjC的解决scheme。

对于我来说,我更喜欢坚持一个function,而不是几个function,我喜欢海报显示的CSS方法。 下面是我添加到我的UIView类别的function。

 - (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,则意味着我们要replace该值。 因此,你可以做CGRect(0,0,100,0),它会假设我们只想replace宽度。

经常调用setFrame方法是不是很好,如: setFrameX(x) setFrameY(y) setFrameWidth(width) ...

相反,在swift中,我们可以使用默认参数只在一个调用中设置多个参数:

 func setFrame(xx: 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)