ios - आईओएस फ्रेम एक संपत्ति को बदलते हैं(उदाहरण के लिए चौड़ाई)




objective-c cgrect (6)

यह प्रश्न मूल रूप से ऑब्जेक्टिव-सी प्रोग्रामिंग लैंग्वेज के लिए पूछा गया था। लेखन के समय, स्विफ्ट अभी तक मौजूद नहीं थी।

सवाल

क्या 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;

N0_quarter के उत्तर के आधार पर, यहां स्विफ्ट में लिखा गया एक 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)
    }
}

अपने मूल प्रश्न का उत्तर देने के लिए: हाँ, CGRect संरचना के सिर्फ एक सदस्य को बदलना संभव है। यह कोड कोई त्रुटि नहीं फेंकता है:

myRect.size.width = 50;

हालांकि, जो संभव नहीं है, वह एक CGRect एकल सदस्य को बदलना है जो स्वयं किसी अन्य ऑब्जेक्ट की संपत्ति है। बहुत ही सामान्य स्थिति में, आपको एक अस्थायी स्थानीय चर का उपयोग करना होगा:

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

इसका कारण यह है कि प्रॉपर्टी self.frame = ... का उपयोग करना [self setFrame:...] बराबर है और यह [self setFrame:...] हमेशा पूरे CGRect अपेक्षा करता है। ऑब्जेक्टिव-सी प्रॉपर्टी डॉट नोटेशन के साथ सी-स्टाइल struct एक्सेस को मिलाना इस मामले में अच्छा काम नहीं करता है।


बार-बार कॉल सेटफ्रेम विधि इतनी अच्छी नहीं है, जैसे: setFrameX(x) setFrameY(y) setFrameWidth(width) ...

इसके बजाय, स्विफ्ट में हम कई मापदंडों को केवल एक कॉल में सेट करने के लिए डिफ़ॉल्ट मापदंडों का उपयोग कर सकते हैं:

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)

मुझे अहमद ख़ालफ़ का जवाब पसंद आया, लेकिन मेरे साथ यह हुआ कि आप कुछ सी फ़ंक्शंस लिख सकते हैं ... महत्वपूर्ण लाभ यह है कि इस घटना में त्रुटियों को ट्रैक करना आसान होगा जो आप गलत का उपयोग कर रहे हैं प्रकार।

ऐसा कहने के बाद, मैंने इन फ़ंक्शन घोषणाओं के साथ एक .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 है, हालांकि। इसे ठीक करने के लिए, आप 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.
}

और अब आप में टाइप कर सकते हैं:

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

का आनंद लें।


स्विफ्ट में आप ऐप के लिए यूआईवीईवाई क्लास का विस्तार कर सकते हैं, जैसे कि आप कर सकते हैं, उदाहरण के लिए, टेबल हेडर दृश्य को इस तरह 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)
    }
}

ArtOfWarfare के समाधान (जो वास्तव में बहुत बढ़िया है) के आधार पर मैंने 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;
}




cgrectmake