छवि के साथ UIButton पर टेक्स्ट और छवि को संरेखित करना IEgegeInsets और titleEdgeInsets


249

मैं पाठ की दो पंक्तियों के बायीं ओर एक आइकन रखना चाहूंगा जैसे कि छवि और पाठ की शुरुआत के बीच लगभग 2-3 पिक्सेल का स्थान हो। नियंत्रण स्वयं केंद्र क्षैतिज रूप से संरेखित है (इंटरफ़ेस बिल्डर के माध्यम से सेट)

बटन कुछ इस तरह होगा:

|                  |
|[Image] Add To    |
|        Favorites |

मैं कोई फायदा नहीं होने के लिए इसे contentEdgeInset, imageEdgeInsets और titleEdgeInsets से कॉन्फ़िगर करने का प्रयास कर रहा हूं। मैं समझता हूं कि एक नकारात्मक मूल्य किनारे का विस्तार करता है जबकि एक सकारात्मक मूल्य इसे केंद्र के करीब ले जाने के लिए सिकुड़ता है।

मैंने कोशिश की:

[button setTitleEdgeInsets:UIEdgeInsetsMake(0, -image.size.width, 0, 0)];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, button.titleLabel.bounds.size.width, 0, 0)];

लेकिन यह इसे सही ढंग से प्रदर्शित नहीं करता है। मैं मानों को बदल रहा हूं, लेकिन बाएं इनसेट मूल्य पर -5 से -10 कहना अपेक्षित तरीके से इसे स्थानांतरित करने के लिए प्रकट नहीं होता है। -10 टेक्स्ट को बायीं तरफ स्कूटी देगा इसलिए मैंने उम्मीद की थी कि -5 इसे बायीं तरफ से आधे रास्ते में ले जाएगा लेकिन ऐसा नहीं है।

इनसेट के पीछे क्या तर्क है? मैं छवि प्लेसमेंट और संबंधित शब्दावली से परिचित नहीं हूं।

मैंने एक संदर्भ के रूप में इस SO प्रश्न का उपयोग किया लेकिन मेरे मूल्यों के बारे में कुछ सही नहीं है। UIButton: ImageEdgeInsets और titleEdgeInsets का उपयोग करके एक छवि और एक पाठ को कैसे केंद्र में रखा जाए?

जवाबों:


392

मैं प्रलेखन पर सहमत हूं imageEdgeInsetsऔर titleEdgeInsetsबेहतर होना चाहिए, लेकिन मुझे पता चला कि परीक्षण और त्रुटि का सहारा लिए बिना सही स्थिति कैसे प्राप्त करें।

इस सवाल पर सामान्य विचार यहाँ है , लेकिन अगर आप पाठ और छवि दोनों को केंद्रित करना चाहते थे। हम छवि और पाठ को व्यक्तिगत रूप से केंद्रित नहीं करना चाहते हैं, हम चाहते हैं कि छवि और पाठ एक इकाई के रूप में एक साथ केंद्रित हों। यह वास्तव में है जो UIButton पहले से ही करता है इसलिए हमें केवल रिक्ति को समायोजित करने की आवश्यकता है।

CGFloat spacing = 10; // the amount of spacing to appear between image and title
tabBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
tabBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);

मैंने इसे UIButton के लिए एक श्रेणी में बदल दिया ताकि इसका उपयोग करना आसान हो जाए:

UIButton + Position.h

@interface UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;

@end

UIButton + Position.m

@implementation UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing {
    self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
}

@end

तो अब मुझे सिर्फ इतना करना है:

[button centerButtonAndImageWithSpacing:10];

और मुझे वह मिलता है जिसकी मुझे हर बार जरूरत होती है। मैन्युअल रूप से किनारे इनसेट के साथ कोई और गड़बड़ नहीं होती है।

संपादित करें: स्वैपिंग इमेज और टेक्स्ट

टिप्पणियों में @Javal के जवाब में

इसी तंत्र का उपयोग करके, हम छवि और पाठ को स्वैप कर सकते हैं। स्वैप को पूरा करने के लिए, बस एक नकारात्मक रिक्ति का उपयोग करें, लेकिन पाठ की चौड़ाई और छवि भी शामिल करें। इसके लिए फ़्रेमों को जानना होगा और लेआउट पहले से ही प्रदर्शन करना होगा।

[self.view layoutIfNeeded];
CGFloat flippedSpacing = -(desiredSpacing + button.currentImage.size.width + button.titleLabel.frame.size.width);
[button centerButtonAndImageWithSpacing:flippedSpacing];

बेशक आप शायद इसके लिए एक अच्छी विधि बनाना चाहते हैं, संभवतः दूसरी श्रेणी की विधि जोड़ सकते हैं, यह पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है।


यदि मेरे पास सामान्य और हाइलाइट किए जाने के लिए अलग-अलग शीर्षक हैं, तो उपयोगकर्ता द्वारा हाइलाइट और अन-हाइलाइट किए जाने पर मैं इसे कैसे फिर से केंद्र कर सकता हूं?
user102008

@ user102008 पूरी तरह से अलग शीर्षक? या सिर्फ अलग रंग? यदि आप उपयोग कर रहे हैं [UIButton setTitleColor:forState:], या यहां तक ​​कि स्थिति में बदलाव नहीं होना चाहिए [UIButton setTitle:forState:]
काकोआ

5
आप [बटन का आकार कैसे ठीक करते हैं] इसे ठीक से आकार दें?
RonLugge

@RonLugge मुझे यकीन नहीं है कि आपको sizeToFit की आवश्यकता क्यों है, इसलिए मैं आपके प्रश्न का उत्तर नहीं दे सकता। यह sizeToFit का उपयोग किए बिना मेरे लिए ठीक काम करता है।
कोकोआ

मुझे sizeToFit की आवश्यकता है क्योंकि बटन / पाठ गतिशील हैं, इसलिए मुझे (उपयोगकर्ता परिभाषित) लेबल फिट करने के लिए बटन को आकार देने की आवश्यकता है। मुद्दा यह है कि यह जोड़ा स्थान के लिए क्षतिपूर्ति नहीं करता है। मैं इसे ओवरराइड कर रहा हूं, और मैन्युअल रूप से फ्रेम की चौड़ाई 10 से
बढ़ा

397

मुझे इस पार्टी में थोड़ी देर हो गई है, लेकिन मुझे लगता है कि मुझे जोड़ने के लिए कुछ उपयोगी है।

केकोआ का जवाब बहुत अच्छा है लेकिन, जैसा कि रॉनलुग ने उल्लेख किया है, यह बटन को अब सम्मान नहीं दे सकता है sizeToFitया इससे भी महत्वपूर्ण बात यह है कि बटन को इसकी सामग्री को क्लिप करने का कारण बन सकता है जब यह आंतरिक रूप से आकार का होता है। ओह!

हालांकि, पहले,

मेरा विश्वास imageEdgeInsetsऔर titleEdgeInsetsकाम करने का संक्षिप्त विवरण :

के लिये दस्तावेजimageEdgeInsets भाग में, निम्नलिखित में क्या कहना है:

बटन छवि के लिए प्रभावी ड्राइंग आयत का आकार बदलने और बदलने के लिए इस संपत्ति का उपयोग करें। आप चार इनसेट्स (ऊपर, बाएं, नीचे, दाएं) में से प्रत्येक के लिए एक अलग मूल्य निर्दिष्ट कर सकते हैं। एक सकारात्मक मूल्य सिकुड़ता है, या इनसेट करता है, वह किनारा-इसे बटन के केंद्र के करीब ले जाता है। एक नकारात्मक मान विस्तृत होता है, या बाहरी, वह किनारा।

मेरा मानना ​​है कि यह दस्तावेज यह कल्पना करते हुए लिखा गया था कि बटन का कोई शीर्षक नहीं है, बस एक छवि है। यह इस तरह से बहुत अधिक समझ में आता है, और व्यवहार करता है कि UIEdgeInsetsआमतौर पर कैसे करते हैं। मूल रूप से, छवि के फ्रेम (या शीर्षक, के साथ titleEdgeInsets) सकारात्मक इनसेट के लिए अंदर की ओर और नकारात्मक इनसेट के लिए बाहर की ओर ले जाया जाता है।

ठीक है तो क्या हुआ?

मैं वहाँ पहुँच रहा हूँ! यहां आपके पास डिफ़ॉल्ट रूप से, एक छवि और एक शीर्षक सेट करना है (बटन बॉर्डर हरे रंग का है जहां यह दिखाना है):

छवि शुरू करना;  शीर्षक और छवि के बीच कोई स्थान नहीं है।

जब आप किसी छवि और शीर्षक के बीच रिक्ति चाहते हैं, तो या तो क्रश किए बिना, आपको चार अलग-अलग इनसेट्स सेट करने की आवश्यकता है, प्रत्येक छवि और शीर्षक पर दो। ऐसा इसलिए है क्योंकि आप उन तत्वों के फ्रेम के आकार को बदलना नहीं चाहते हैं , लेकिन सिर्फ उनके पदों को। जब आप इस तरह से सोचना शुरू करते हैं, तो कोको की उत्कृष्ट श्रेणी में आवश्यक परिवर्तन स्पष्ट हो जाता है:

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
}

@end

लेकिन रुकिए , आप कहते हैं, जब मैं ऐसा करता हूं, मुझे यह मिलता है:

रिक्ति अच्छी है, लेकिन छवि और शीर्षक दृश्य के फ्रेम के बाहर हैं।

अरे हां! मैं भूल गया, डॉक्स ने मुझे इस बारे में चेतावनी दी है। वे कहते हैं, भाग में:

इस संपत्ति का उपयोग केवल लेआउट के दौरान छवि की स्थिति के लिए किया जाता है। बटन इस संपत्ति का उपयोग करने intrinsicContentSizeऔर निर्धारित करने के लिए नहीं करता है sizeThatFits:

लेकिन वहाँ है एक संपत्ति है कि कर सकते हैं मदद, और कहा कि के contentEdgeInsets। उस भाग के लिए डॉक्स कहते हैं:

बटन इस संपत्ति का उपयोग करने के लिए निर्धारित करता है intrinsicContentSizeऔर sizeThatFits:

यह अच्छा रहेगा। तो चलिए श्रेणी को एक बार फिर से देखते हैं:

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
    self.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
}

@end

और आपको क्या मिलता है?

रिक्ति और फ्रेम अब सही हैं।

मुझे एक विजेता की तरह लगता है।


स्विफ्ट में काम करना और किसी भी तरह की सोच नहीं करना चाहते हैं? यहां स्विफ्ट में एक्सटेंशन का अंतिम संस्करण है:

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
        contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

25
क्या शानदार जवाब है! हाँ पार्टी में कुछ साल देर हो गई, लेकिन इसने intrinsicContentSizeगलत होने के मुद्दे को हल कर दिया , जो मूल उत्तर स्वीकार किए जाने के बाद से इन ऑटो-लेआउट दिनों में बहुत महत्वपूर्ण है।
Acey

2
और यदि आप बटन और छवि और लेबल के बाहर के बीच समान दूरी चाहते हैं, तो spacingself.contentEdgeInsets के चार मूल्यों में से प्रत्येक में जोड़ें , जैसे:self.contentEdgeInsets = UIEdgeInsetsMake(spacing, spacing + insetAmount, spacing, spacing + insetAmount);
एरिक वैन डेर न्यूट

1
महान जवाब, एक दया यह बहुत अच्छी तरह से काम नहीं करती है जब छवि सही संरेखित होती है और पाठ की लंबाई भिन्न हो सकती है।
jlpiedrahita

2
लगभग सही जवाब! केवल गायब होने वाली बात यह है कि छवि और शीर्षक के इनसेट को राइट-टू-लेफ्ट इंटरफ़ेस पर चलने पर उल्टा होना चाहिए।
जीयूल

छवि अनुपात 1 से 1 तक कैसे सेट करें
Yestay Muratov

39

इंटरफ़ेस बिल्डर में। UIButton का चयन करें -> इंस्पेक्टर का गुण -> एज = शीर्षक और एज इनसेट को संशोधित करें


38

अगर आप भी कुछ ऐसा ही बनाना चाहते हैं

यहां छवि विवरण दर्ज करें

आप की जरूरत है

1. बटन के लिए क्षैतिज और ऊर्ध्वाधर संरेखण सेट करें

यहां छवि विवरण दर्ज करें

  1. सभी आवश्यक मान प्राप्त करें और सेट करें UIImageEdgeInsets

            CGSize buttonSize = button.frame.size;
            NSString *buttonTitle = button.titleLabel.text;
            CGSize titleSize = [buttonTitle sizeWithAttributes:@{ NSFontAttributeName : [UIFont camFontZonaProBoldWithSize:12.f] }];
            UIImage *buttonImage = button.imageView.image;
            CGSize buttonImageSize = buttonImage.size;
    
            CGFloat offsetBetweenImageAndText = 10; //vertical space between image and text
    
            [button setImageEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 - offsetBetweenImageAndText,
                                                        (buttonSize.width - buttonImageSize.width) / 2,
                                                        0,0)];                
            [button setTitleEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 + buttonImageSize.height + offsetBetweenImageAndText,
                                                        titleSize.width + [button imageEdgeInsets].left > buttonSize.width ? -buttonImage.size.width  +  (buttonSize.width - titleSize.width) / 2 : (buttonSize.width - titleSize.width) / 2 - buttonImage.size.width,
                                                        0,0)];

यह आपके शीर्षक और छवि को बटन पर व्यवस्थित करेगा।

कृपया प्रत्येक रिलेआउट पर इसे अपडेट करें


तीव्र

import UIKit

extension UIButton {
    // MARK: - UIButton+Aligment

    func alignContentVerticallyByCenter(offset:CGFloat = 10) {
        let buttonSize = frame.size

        if let titleLabel = titleLabel,
            let imageView = imageView {

            if let buttonTitle = titleLabel.text,
                let image = imageView.image {
                let titleString:NSString = NSString(string: buttonTitle)
                let titleSize = titleString.sizeWithAttributes([
                    NSFontAttributeName : titleLabel.font
                    ])
                let buttonImageSize = image.size

                let topImageOffset = (buttonSize.height - (titleSize.height + buttonImageSize.height + offset)) / 2
                let leftImageOffset = (buttonSize.width - buttonImageSize.width) / 2
                imageEdgeInsets = UIEdgeInsetsMake(topImageOffset,
                                                   leftImageOffset,
                                                   0,0)

                let titleTopOffset = topImageOffset + offset + buttonImageSize.height
                let leftTitleOffset = (buttonSize.width - titleSize.width) / 2 - image.size.width

                titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset,
                                                   leftTitleOffset,
                                                   0,0)
            }
        }
    }
}

29

इसके इस्तेमाल से आप बहुत परेशानी से बच सकते हैं -

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;   
myButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;

यह आपकी सभी सामग्री को स्वचालित रूप से बाईं ओर संरेखित करेगा (या जहां भी आप चाहते हैं)

स्विफ्ट 3:

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;   
myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;

myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center; // टाइपो सही
Naishta

25

में Xcode 8.0 आप बस बदलकर यह कर सकते हैं insetsआकार निरीक्षक में।

UIButton का चयन करें -> इंस्पेक्टर को अट्रैक्ट करता है -> साइज इंस्पेक्टर के पास जाएं और कंटेंट, इमेज और टाइटल इनसेट को संशोधित करें।

यहां छवि विवरण दर्ज करें

और यदि आप दाईं ओर की छवि बदलना चाहते हैं, तो आप Force Right-to-leftएट्रीब्यूट इंस्पेक्टर में सिमेंटिक संपत्ति को बदल सकते हैं ।

यहां छवि विवरण दर्ज करें


मेरे केस बटन की छवि xcode 10 के साथ पाठ के दाईं ओर कभी नहीं चलती है? क्या आप मदद कर सकते हैं?
सतीश मवानी

हाय सतीश, यह भी xcode 10 के साथ ठीक काम कर रहा है। आशा है कि आप छवि नहीं पृष्ठभूमि छवि सेट कर रहे हैं और आप आकार निरीक्षक का उपयोग करके छवि कीड़े भी बदल सकते हैं।
साहिल

18

मुझे इस पार्टी में थोड़ी देर हो गई है, लेकिन मुझे लगता है कि मुझे जोड़ने के लिए कुछ उपयोगी है: ओ)।

मैंने एक UIButtonउपवर्ग बनाया जिसका उद्देश्य यह चुनने में सक्षम होना है कि बटन की छवि लेआउट कहां है, या तो लंबवत या क्षैतिज रूप से।

इसका मतलब है कि आप इस तरह के बटन बना सकते हैं: विभिन्न प्रकार के बटन

यहाँ मेरी कक्षा के साथ इन बटनों को बनाने का विवरण दिया गया है:

func makeButton (imageVerticalAlignment:LayoutableButton.VerticalAlignment, imageHorizontalAlignment:LayoutableButton.HorizontalAlignment, title:String) -> LayoutableButton {
    let button = LayoutableButton ()

    button.imageVerticalAlignment = imageVerticalAlignment
    button.imageHorizontalAlignment = imageHorizontalAlignment

    button.setTitle(title, for: .normal)

    // add image, border, ...

    return button
}

let button1 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .left, title: "button1")
let button2 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .right, title: "button2")
let button3 = makeButton(imageVerticalAlignment: .top, imageHorizontalAlignment: .center, title: "button3")
let button4 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button4")
let button5 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button5")
button5.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

ऐसा करने के लिए, मैंने 2 विशेषताएँ जोड़ीं: imageVerticalAlignmentऔर imageHorizontalAlignment। ऑफ कोर्स, अगर आपके बटन में केवल एक छवि या एक शीर्षक है ... तो इस वर्ग का उपयोग न करें!

मैंने एक विशेषता भी जोड़ी है जिसका नाम imageToTitleSpacingआपको शीर्षक और छवि के बीच स्थान समायोजित करने की अनुमति देता है।

यदि आप उपयोग करना चाहते हैं imageEdgeInsets, titleEdgeInsetsऔर contentEdgeInsetsसीधे या नए लेआउट विशेषताओं के साथ कॉम्बिनेशन में यह वर्ग अपनी पूरी कोशिश करता है ।

जैसा कि @ravron हमें समझाता है, मैं बटन सामग्री किनारे को सही बनाने के लिए अपनी पूरी कोशिश करता हूं (जैसा कि आप लाल सीमाओं के साथ देख सकते हैं)।

आप इसे इंटरफ़ेस बिल्डर में भी उपयोग कर सकते हैं:

  1. एक UIButton बनाएँ
  2. बटन वर्ग बदलें
  3. "केंद्र", "टॉप", "बॉटम", "लेफ्ट" या "राइट" का उपयोग करके लेआउट योग्य विशेषताओं को समायोजित करें बटन विशेषताएँ

यहाँ कोड ( gist ):

@IBDesignable
class LayoutableButton: UIButton {

    enum VerticalAlignment : String {
        case center, top, bottom, unset
    }


    enum HorizontalAlignment : String {
        case center, left, right, unset
    }


    @IBInspectable
    var imageToTitleSpacing: CGFloat = 8.0 {
        didSet {
            setNeedsLayout()
        }
    }


    var imageVerticalAlignment: VerticalAlignment = .unset {
        didSet {
            setNeedsLayout()
        }
    }

    var imageHorizontalAlignment: HorizontalAlignment = .unset {
        didSet {
            setNeedsLayout()
        }
    }

    @available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageVerticalAlignment' instead.")
    @IBInspectable
    var imageVerticalAlignmentName: String {
        get {
            return imageVerticalAlignment.rawValue
        }
        set {
            if let value = VerticalAlignment(rawValue: newValue) {
                imageVerticalAlignment = value
            } else {
                imageVerticalAlignment = .unset
            }
        }
    }

    @available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageHorizontalAlignment' instead.")
    @IBInspectable
    var imageHorizontalAlignmentName: String {
        get {
            return imageHorizontalAlignment.rawValue
        }
        set {
            if let value = HorizontalAlignment(rawValue: newValue) {
                imageHorizontalAlignment = value
            } else {
                imageHorizontalAlignment = .unset
            }
        }
    }

    var extraContentEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var contentEdgeInsets: UIEdgeInsets {
        get {
            return super.contentEdgeInsets
        }
        set {
            super.contentEdgeInsets = newValue
            self.extraContentEdgeInsets = newValue
        }
    }

    var extraImageEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var imageEdgeInsets: UIEdgeInsets {
        get {
            return super.imageEdgeInsets
        }
        set {
            super.imageEdgeInsets = newValue
            self.extraImageEdgeInsets = newValue
        }
    }

    var extraTitleEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var titleEdgeInsets: UIEdgeInsets {
        get {
            return super.titleEdgeInsets
        }
        set {
            super.titleEdgeInsets = newValue
            self.extraTitleEdgeInsets = newValue
        }
    }

    //Needed to avoid IB crash during autolayout
    override init(frame: CGRect) {
        super.init(frame: frame)
    }


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.imageEdgeInsets = super.imageEdgeInsets
        self.titleEdgeInsets = super.titleEdgeInsets
        self.contentEdgeInsets = super.contentEdgeInsets
    }

    override func layoutSubviews() {
        if let imageSize = self.imageView?.image?.size,
            let font = self.titleLabel?.font,
            let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(attributes: [NSFontAttributeName: font]) {

            var _imageEdgeInsets = UIEdgeInsets.zero
            var _titleEdgeInsets = UIEdgeInsets.zero
            var _contentEdgeInsets = UIEdgeInsets.zero

            let halfImageToTitleSpacing = imageToTitleSpacing / 2.0

            switch imageVerticalAlignment {
            case .bottom:
                _imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0
                _imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0
                _titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0
                _titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
            case .top:
                _imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0
                _imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0
                _titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0
                _titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0
                _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
            case .center:
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
                break
            case .unset:
                break
            }

            switch imageHorizontalAlignment {
            case .left:
                _imageEdgeInsets.left = -halfImageToTitleSpacing
                _imageEdgeInsets.right = halfImageToTitleSpacing
                _titleEdgeInsets.left = halfImageToTitleSpacing
                _titleEdgeInsets.right = -halfImageToTitleSpacing
                _contentEdgeInsets.left = halfImageToTitleSpacing
                _contentEdgeInsets.right = halfImageToTitleSpacing
            case .right:
                _imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing
                _imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing
                _titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing
                _titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing
                _contentEdgeInsets.left = halfImageToTitleSpacing
                _contentEdgeInsets.right = halfImageToTitleSpacing
            case .center:
                _imageEdgeInsets.left = textSize.width / 2.0
                _imageEdgeInsets.right = -textSize.width / 2.0
                _titleEdgeInsets.left = -imageSize.width / 2.0
                _titleEdgeInsets.right = imageSize.width / 2.0
                _contentEdgeInsets.left = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
                _contentEdgeInsets.right = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
            case .unset:
                break
            }

            _contentEdgeInsets.top += extraContentEdgeInsets.top
            _contentEdgeInsets.bottom += extraContentEdgeInsets.bottom
            _contentEdgeInsets.left += extraContentEdgeInsets.left
            _contentEdgeInsets.right += extraContentEdgeInsets.right

            _imageEdgeInsets.top += extraImageEdgeInsets.top
            _imageEdgeInsets.bottom += extraImageEdgeInsets.bottom
            _imageEdgeInsets.left += extraImageEdgeInsets.left
            _imageEdgeInsets.right += extraImageEdgeInsets.right

            _titleEdgeInsets.top += extraTitleEdgeInsets.top
            _titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom
            _titleEdgeInsets.left += extraTitleEdgeInsets.left
            _titleEdgeInsets.right += extraTitleEdgeInsets.right

            super.imageEdgeInsets = _imageEdgeInsets
            super.titleEdgeInsets = _titleEdgeInsets
            super.contentEdgeInsets = _contentEdgeInsets

        } else {
            super.imageEdgeInsets = extraImageEdgeInsets
            super.titleEdgeInsets = extraTitleEdgeInsets
            super.contentEdgeInsets = extraContentEdgeInsets
        }

        super.layoutSubviews()
    }
}

1
मैं कुछ सामान ठीक करता हूं, आईबी को नहीं तोड़ने के लिए error: IB Designables: Failed to update auto layout status: The agent crashed, gist.github.com/nebiros/ecf69ff9cb90568edde071386c6c4ddb
nebiros

@nebiros आपको समझा सकता है कि क्या गलत है और आप इसे कैसे ठीक करते हैं, कृपया?
gbitaudeau

@gbitaudeau जब मैं स्क्रिप्ट को कॉपी और पेस्ट करता हूं, तो मुझे वह त्रुटि मिली error: IB Designables: Failed to update auto layout status: The agent crashed, क्योंकि init(frame: CGRect)ओवरराइड नहीं किया गया था, साथ ही, मैं @availableएनोटेशन भी जोड़ देता हूं ..., diff -Naurअगर आप चाहें तो ;-)
nebiros

9

स्थानीय परिवर्तनों को ध्यान में रखते हुए रिले एवरॉन का एक छोटा सा जवाब:

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        let writingDirection = UIApplication.sharedApplication().userInterfaceLayoutDirection
        let factor: CGFloat = writingDirection == .LeftToRight ? 1 : -1

        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
        self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

6

स्विफ्ट 4.x

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        let writingDirection = UIApplication.shared.userInterfaceLayoutDirection
        let factor: CGFloat = writingDirection == .leftToRight ? 1 : -1

        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
        self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

उपयोग :

button.centerTextAndImage(spacing: 10.0)

कस्टूम छवि आकार के साथ कैसे उपयोग कर सकते हैं?
मध्यरात्रि

2

मैं कोड लिखता हूं। यह उत्पाद संस्करण में अच्छी तरह से काम करता है। सपोट स्विफ्ट 4.2 +

extension UIButton{
 enum ImageTitleRelativeLocation {
    case imageUpTitleDown
    case imageDownTitleUp
    case imageLeftTitleRight
    case imageRightTitleLeft
}
 func centerContentRelativeLocation(_ relativeLocation: 
                                      ImageTitleRelativeLocation,
                                   spacing: CGFloat = 0) {
    assert(contentVerticalAlignment == .center,
           "only works with contentVerticalAlignment = .center !!!")

    guard (title(for: .normal) != nil) || (attributedTitle(for: .normal) != nil) else {
        assert(false, "TITLE IS NIL! SET TITTLE FIRST!")
        return
    }

    guard let imageSize = self.currentImage?.size else {
        assert(false, "IMGAGE IS NIL! SET IMAGE FIRST!!!")
        return
    }
    guard let titleSize = titleLabel?
        .systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) else {
            assert(false, "TITLELABEL IS NIL!")
            return
    }

    let horizontalResistent: CGFloat
    // extend contenArea in case of title is shrink
    if frame.width < titleSize.width + imageSize.width {
        horizontalResistent = titleSize.width + imageSize.width - frame.width
        print("horizontalResistent", horizontalResistent)
    } else {
        horizontalResistent = 0
    }

    var adjustImageEdgeInsets: UIEdgeInsets = .zero
    var adjustTitleEdgeInsets: UIEdgeInsets = .zero
    var adjustContentEdgeInsets: UIEdgeInsets = .zero

    let verticalImageAbsOffset = abs((titleSize.height + spacing) / 2)
    let verticalTitleAbsOffset = abs((imageSize.height + spacing) / 2)

    switch relativeLocation {
    case .imageUpTitleDown:

        adjustImageEdgeInsets.top = -verticalImageAbsOffset
        adjustImageEdgeInsets.bottom = verticalImageAbsOffset
        adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
        adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2

        adjustTitleEdgeInsets.top = verticalTitleAbsOffset
        adjustTitleEdgeInsets.bottom = -verticalTitleAbsOffset
        adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
        adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2

        adjustContentEdgeInsets.top = spacing
        adjustContentEdgeInsets.bottom = spacing
        adjustContentEdgeInsets.left = -horizontalResistent
        adjustContentEdgeInsets.right = -horizontalResistent
    case .imageDownTitleUp:
        adjustImageEdgeInsets.top = verticalImageAbsOffset
        adjustImageEdgeInsets.bottom = -verticalImageAbsOffset
        adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
        adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2

        adjustTitleEdgeInsets.top = -verticalTitleAbsOffset
        adjustTitleEdgeInsets.bottom = verticalTitleAbsOffset
        adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
        adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2

        adjustContentEdgeInsets.top = spacing
        adjustContentEdgeInsets.bottom = spacing
        adjustContentEdgeInsets.left = -horizontalResistent
        adjustContentEdgeInsets.right = -horizontalResistent
    case .imageLeftTitleRight:
        adjustImageEdgeInsets.left = -spacing / 2
        adjustImageEdgeInsets.right = spacing / 2

        adjustTitleEdgeInsets.left = spacing / 2
        adjustTitleEdgeInsets.right = -spacing / 2

        adjustContentEdgeInsets.left = spacing
        adjustContentEdgeInsets.right = spacing
    case .imageRightTitleLeft:
        adjustImageEdgeInsets.left = titleSize.width + spacing / 2
        adjustImageEdgeInsets.right = -titleSize.width - spacing / 2

        adjustTitleEdgeInsets.left = -imageSize.width - spacing / 2
        adjustTitleEdgeInsets.right = imageSize.width + spacing / 2

        adjustContentEdgeInsets.left = spacing
        adjustContentEdgeInsets.right = spacing
    }

    imageEdgeInsets = adjustImageEdgeInsets
    titleEdgeInsets = adjustTitleEdgeInsets
    contentEdgeInsets = adjustContentEdgeInsets

    setNeedsLayout()
}
}

1

यहाँ एक सरल उदाहरण दिया गया है कि imageEdgeInsets का उपयोग कैसे किया जाता है। यह एक 30x30 बटन को हिट करने योग्य क्षेत्र के साथ 10 पिक्सेल बड़ा कर देगा, जो चारों ओर (50x50)

    var expandHittableAreaAmt : CGFloat = 10
    var buttonWidth : CGFloat = 30
    var button = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
    button.frame = CGRectMake(0, 0, buttonWidth+expandHittableAreaAmt, buttonWidth+expandHittableAreaAmt)
    button.imageEdgeInsets = UIEdgeInsetsMake(expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt)
    button.setImage(UIImage(named: "buttonImage"), forState: .Normal)
    button.addTarget(self, action: "didTouchButton:", forControlEvents:.TouchUpInside)

0

स्विफ्ट 3 में एक सुंदर तरीका और समझने के लिए बेहतर:

override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
    let leftMargin:CGFloat = 40
    let imgWidth:CGFloat = 24
    let imgHeight:CGFloat = 24
    return CGRect(x: leftMargin, y: (contentRect.size.height-imgHeight) * 0.5, width: imgWidth, height: imgHeight)
}

override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    let leftMargin:CGFloat = 80
    let rightMargin:CGFloat = 80
    return CGRect(x: leftMargin, y: 0, width: contentRect.size.width-leftMargin-rightMargin, height: contentRect.size.height)
}
override func backgroundRect(forBounds bounds: CGRect) -> CGRect {
    let leftMargin:CGFloat = 10
    let rightMargin:CGFloat = 10
    let topMargin:CGFloat = 10
    let bottomMargin:CGFloat = 10
    return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}
override func contentRect(forBounds bounds: CGRect) -> CGRect {
    let leftMargin:CGFloat = 5
    let rightMargin:CGFloat = 5
    let topMargin:CGFloat = 5
    let bottomMargin:CGFloat = 5
    return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}

-1

समाधान का तेज 4.2 संस्करण निम्नलिखित होगा:

let spacing: CGFloat = 10 // the amount of spacing to appear between image and title
self.button?.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: spacing)
self.button?.titleEdgeInsets = UIEdgeInsets(top: 0, left: spacing, bottom: 0, right: 0)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.