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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9537573/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:08:36  来源:igfitidea点击:

iOS frame change one property (eg width)

iosobjective-ccgrectcgrectmake

提问by Hymansonkr

This question was originally asked for the objective-c programming language. At the time of writing, swift didn't even exist yet.

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

Question

Is it possible to change only oneproperty of a CGRect?

是否可以只更改a 的一个属性CGRect

For example:

例如:

self.frame.size.width = 50;

instead of

代替

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

of course I understand that self.frame.size.widthis read onlyso I'm wondering how to do this?

当然,我知道这self.frame.size.width只读的,所以我想知道如何做到这一点?

CSS ANALOGYproceed at your own risk

CSS ANALOGY自行承担风险

for those of you who are familiar with CSS, the idea is very similar to using:

对于那些熟悉 的人来说CSS,这个想法非常类似于使用:

margin-left: 2px;

instead of having to change the whole value:

而不必更改整个值:

margin: 5px 5px 5px 2px;

回答by Ole Begemann

To answer your original question: yes, it's possible to change just one member of a CGRectstructure. This code throws no errors:

回答您最初的问题:是的,可以仅更改CGRect结构的一个成员。此代码不会引发任何错误:

myRect.size.width = 50;

What is notpossible, however, is to change a single member of a CGRectthat is itself a property of another object. In that very common case, you would have to use a temporary local variable:

什么是没有可能的,但是,是改变的一个成员CGRect,其本身的另一个对象的属性。在这种非常常见的情况下,您必须使用临时局部变量:

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

The reason for this is that using the property accessor self.frame = ...is equivalent to [self setFrame:...]and this accessor always expects an entire CGRect. Mixing C-style structaccess with Objective-C property dot notation does not work well in this case.

这样做的原因是使用属性访问self.frame = ...器等效于[self setFrame:...]并且此访问器始终需要一个完整的CGRect. struct在这种情况下,将 C 样式访问与 Objective-C 属性点符号混合使用效果不佳。

回答by ArtOfWarfare

I liked Ahmed Khalaf's answer, but it occurred to me that you may as well just write out a few C functions... the key advantage being that it'll be easier to track down errors in the event that you're using the wrong type.

我喜欢Ahmed Khalaf 的回答,但我突然想到,您不妨只写出一些 C 函数……主要优点是,如果您使用错误,则更容易追踪错误类型。

Having said that, I wrote a .h file with these function declarations:

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

And a corresponding .m file with these function implementations:

以及具有这些函数实现的相应 .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);
}

So, now, to do what you want, you can just do:

所以,现在,要做你想做的,你可以这样做:

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

Get even Fancier(update I made a year later)

变得更狂热(我一年后更新)

This has a redundant self.framein it, though. To fix that, you could add a categoryon UIViewwith methods that look like this:

不过,这其中有一个多余self.frame的内容。为了解决这个问题,你可以添加一个categoryUIView有方法是这个样子的:

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

And now you can just type in:

现在你可以输入:

[self setFrameWidth:50];

Or, even better:

或者,甚至更好:

self.frameWidth = 50;

And just so you can do something like this:

这样你就可以做这样的事情:

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

You'll need to also have this in your category:

你还需要在你的类别中有这个:

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

Enjoy.

享受。

回答by n0_quarter

Based on ArtOfWarfare's solution(which is really awesome) I've build the UIViewcategory without C-functions.

基于ArtOfWarfare 的解决方案(这真的很棒),我构建了UIView没有 C 函数的类别。

Usage examples:

用法示例:

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

Header file UIView+easy_frame.h:

头文件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;

Implementation file UIView+easy_frame.m:

实施文件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;
}

回答by pxlshpr

If you find yourself needing to do this sort of individual component modification, it may be worthwhile having macros like these somewhere accessible by all of your code:

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

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

This way, whenever you need to change the width alone - you would simply write

这样,每当您需要单独更改宽度时 - 您只需编写

ViewSetWidth(self, 50);

instead of

代替

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

回答by Robert Wagstaff

Based on n0_quarter answer, here's a UIView Extension written in Swift:

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

回答by clearlight

In Swift you could extend the UIView class for the app, such that you could, for example, move the table header view up by 10 points like this:

在 Swift 中,您可以为应用程序扩展 UIView 类,例如,您可以像这样将表头视图向上移动 10 个点:

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

(of course if you're using AutoLayout, that might not actually do anything... :) )

(当然,如果您使用的是 AutoLayout,那实际上可能不会做任何事情... :) )

By extending UIView (affecting every UIView and subclass of it in your app)

通过扩展 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)
    }
}

回答by wahkiz

Hope I am not too late to the party, here's my solution in ObjC.

希望我参加聚会还不算太晚,这是我在 ObjC 中的解决方案。

For me I prefer to stick to a single function instead of several functions, and I like the CSS approach shown by the poster. Below is the function I add to my UIView Category.

对我来说,我更喜欢坚持使用单个函数而不是多个函数,而且我喜欢海报所示的 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]; }

Shown in the example, it looks at each values in the provided CGRect, and if the value is more than 0, it means we want to replace that value. And therefore, you can do CGRect(0,0,100,0) and it will assume we want to replace the width only.

如示例所示,它查看提供的 CGRect 中的每个值,如果该值大于 0,则表示我们要替换该值。因此,您可以执行 CGRect(0,0,100,0) 并且它会假设我们只想替换宽度。

回答by Bigyelow

frequently call setFrame method is not so good, like: setFrameX(x) setFrameY(y) setFrameWidth(width) ...

频繁调用 setFrame 方法不太好,比如: setFrameX(x) setFrameY(y) setFrameWidth(width) ...

instead, in swift we can make use of default parameters to set multiple parameters only in one call:

相反,在 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)
}

then update parameters of frame only need:

然后更新帧的参数只需要:

setFrame(x: x, width: min(maxX - x, titleLabel.bounds.size.width))
setFrame(width: titleDescriptionLabel.bounds.size.width + 5, height: titleDescriptionLabel.bounds.size.height + 6)

回答by DavidoM

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

}

}

its work great for me :)

它的工作对我来说很棒:)