iOS frame change one property (eg width)

前端 未结 9 1031
日久生厌
日久生厌 2020-12-14 00:20

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

Question

Is it po

相关标签:
9条回答
  • 2020-12-14 00:36

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

    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:

    @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:

    #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;
    }
    
    0 讨论(0)
  • 2020-12-14 00:37
    -(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 :)

    0 讨论(0)
  • 2020-12-14 00:42

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

    myRect.size.width = 50;
    

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

    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 struct access with Objective-C property dot notation does not work well in this case.

    0 讨论(0)
  • 2020-12-14 00:44

    Based on n0_quarter answer, here's a UIView Extension written in 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 讨论(0)
  • 2020-12-14 00:45

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

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

    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)
    
    0 讨论(0)
  • 2020-12-14 00:54

    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.

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

    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:

    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.frame in it, though. To fix that, you could add a category on UIView with methods that look like this:

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

    0 讨论(0)
提交回复
热议问题