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

问题描述 投票:39回答:9

这个问题最初是针对objective-c编程语言提出的。在撰写本文时,swift甚至还没有存在。

Question

是否有可能只更改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;
ios objective-c cgrect cgrectmake
9个回答
95
投票

回答你原来的问题:是的,可以只改变一个CGRect结构的一个成员。此代码不会抛出任何错误:

myRect.size.width = 50;

然而,不可能的是改变CGRect的一个成员,它本身就是另一个对象的属性。在这种非常常见的情况下,您必须使用临时局部变量:

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

原因是使用属性访问器self.frame = ...相当于[self setFrame:...],这个访问器总是需要一个完整的CGRect。在这种情况下,将C风格的struct访问与Objective-C属性点表示法混合使用效果不佳。


28
投票

我喜欢Ahmed Khalaf's answer,但我想到你也可以写出一些C函数......关键的好处是,如果你使用了错误的类型,它会更容易追踪错误。

话虽如此,我用这些函数声明写了一个.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。要解决这个问题,您可以使用如下所示的方法在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
投票

基于ArtOfWarfare's solution(这真的很棒)我建立了没有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;
}

4
投票

如果您发现自己需要对这些单独的组件进行修改,那么在所有代码都可以访问的地方使用这些宏可能是值得的:

#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
投票

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

1
投票

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

0
投票

希望我对派对来说还不晚,这是我在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),它将假设我们只想替换宽度。


0
投票

经常调用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)

-1
投票
-(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;

}

它的工作对我很好:)

© www.soinside.com 2019 - 2024. All rights reserved.