केंद्र NSTextAttachment छवि एकल पंक्ति UILabel के बगल में


117

मैं NSTextAttachmentअपनी ज़िम्मेदार स्ट्रिंग के लिए एक छवि जोड़ना चाहता हूं और इसे लंबवत रूप से केंद्रित किया है।

मैंने अपनी स्ट्रिंग बनाने के लिए निम्न कोड का उपयोग किया है:

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:DDLocalizedString(@"title.upcomingHotspots") attributes:attrs];
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [[UIImage imageNamed:@"help.png"] imageScaledToFitSize:CGSizeMake(14.f, 14.f)];
cell.textLabel.attributedText = [str copy];

हालाँकि, छवि सेल के शीर्ष पर संरेखित होती है textLabel

पाठ अनुलग्नक ऑफसेट समस्या स्क्रीनशॉट

मैं उस परत को कैसे बदल सकता हूं जिसमें लगाव खींचा गया है?


मेरे पास UIImage और vise versa के साथ NSString होने के लिए एक श्रेणी वर्ग है। github.com/Pradeepkn/TextWithImage आनंद लें।
प्रदीपकेएन

जवाबों:


59

आप सबक्लासिंग NSTextAttachmentऔर ओवरराइडिंग द्वारा रीले को बदल सकते हैं attachmentBoundsForTextContainer:proposedLineFragment:glyphPosition:characterIndex:। उदाहरण:

- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex {
    CGRect bounds;
    bounds.origin = CGPointMake(0, -5);
    bounds.size = self.image.size;
    return bounds;
}

यह एक सही समाधान नहीं है। आपको Y- मूल "आंख से" पता लगाना होगा और यदि आप फ़ॉन्ट या आइकन का आकार बदलते हैं, तो आप संभवतः वाई-मूल को बदलना चाहेंगे। लेकिन मैं एक अलग छवि दृश्य में आइकन को छोड़कर (जो कि इसके अपने नुकसान हैं) को छोड़कर, एक बेहतर तरीका नहीं खोज सका।


2
कोई विचार नहीं कि उन्होंने इसे क्यों वोट दिया, इससे मुझे +1
जैस्पर

Y- मूल फ़ॉन्ट अवरोही है। नीचे मेरा जवाब देखें।
फतमान

4
ट्रैविस का जवाब सबक्लासिंग के बिना एक क्लीनर समाधान है।
स्वामपिंगटॉम

अधिक जानकारी के लिए, @ mg-han का उत्तर stackoverflow.com/a/45161058/280503 पर देखें (मेरी राय में इसे प्रश्न का चयनित उत्तर होना चाहिए।)
गार्डोफ्विन

191

आप फ़ॉन्ट के capHeight का उपयोग कर सकते हैं।

उद्देश्य सी

NSTextAttachment *icon = [[NSTextAttachment alloc] init];
UIImage *iconImage = [UIImage imageNamed:@"icon.png"];
[icon setBounds:CGRectMake(0, roundf(titleFont.capHeight - iconImage.size.height)/2.f, iconImage.size.width, iconImage.size.height)];
[icon setImage:iconImage];
NSAttributedString *iconString = [NSAttributedString attributedStringWithAttachment:icon];
[titleText appendAttributedString:iconString];

तीव्र

let iconImage = UIImage(named: "icon.png")!
var icon = NSTextAttachment()
icon.bounds = CGRect(x: 0, y: (titleFont.capHeight - iconImage.size.height).rounded() / 2, width: iconImage.size.width, height: iconImage.size.height)
icon.image = iconImage
let iconString = NSAttributedString(attachment: icon)
titleText.append(iconString)

अटैचमेंट इमेज को टेक्स्ट के बेसलाइन पर प्रस्तुत किया गया है। और इसका y अक्ष कोर ग्राफिक्स समन्वय प्रणाली की तरह उलट है। यदि आप छवि को ऊपर की ओर ले जाना चाहते हैं, तो bounds.origin.yसकारात्मक को सेट करें ।

छवि को पाठ के कैपहाइट के साथ लंबवत केंद्र में संरेखित किया जाना चाहिए। तो हम करने के लिए सेट करने की जरूरत bounds.origin.yहै (capHeight - imageHeight)/2

छवि पर कुछ दांतेदार प्रभाव से बचने के लिए, हमें y के अंश भाग को गोल करना चाहिए। लेकिन फोंट और छवियां आम तौर पर छोटी होती हैं, यहां तक ​​कि 1px अंतर भी छवि को गलत लगता है। इसलिए मैंने विभाजित होने से पहले राउंड फ़ंक्शन को लागू किया। यह y मान के अंश को .0 या .5 बनाता है

आपके मामले में, छवि की ऊंचाई फ़ॉन्ट की कैपहाइट से बड़ी है। लेकिन आप उसी तरह का उपयोग कर सकते हैं। ऑफसेट y मान ऋणात्मक होगा। और इसे आधार रेखा के नीचे से बाहर रखा जाएगा।

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


धन्यवाद!!!!!!!!!!!!!!
एलेक्स

107

कोशिश करो - [NSTextAttachment bounds]। कोई उपवर्ग आवश्यक नहीं है।

संदर्भ के लिए, मैं UILabelअनुलग्नक छवि के रूप में उपयोग के लिए प्रतिपादन कर रहा हूं , फिर इस तरह की सीमाएं निर्धारित कर रहा हूं : attachment.bounds = CGRectMake(0, self.font.descender, attachment.image.size.width, attachment.image.size.height)लेबल छवि के भीतर पाठ की आधार रेखाएं और वांछित स्ट्रिंग लाइन में पाठ को वांछित के रूप में।


यह तब तक काम करता है जब तक आपको छवि को स्केल करने की आवश्यकता नहीं है।
फतमान

12
स्विफ्ट 3.0 के लिए:attachment.bounds = CGRect(x: 0.0, y: self.font.descender, width: attachment.image!.size.width, height: attachment.image!.size.height)
एंडी

बहुत अच्छे धन्यवाद! descenderUIFont की संपत्ति के बारे में नहीं पता था !
बेन

61

मुझे इसका एक सही समाधान मिला, हालांकि मेरे लिए एक आकर्षण की तरह काम करता है, हालांकि आपको इसे खुद से आज़माना होगा (शायद स्थिर डिवाइस के संकल्प पर निर्भर करता है और शायद जो भी हो;)

func textAttachment(fontSize: CGFloat) -> NSTextAttachment {
    let font = UIFont.systemFontOfSize(fontSize) //set accordingly to your font, you might pass it in the function
    let textAttachment = NSTextAttachment()
    let image = //some image
    textAttachment.image = image
    let mid = font.descender + font.capHeight
    textAttachment.bounds = CGRectIntegral(CGRect(x: 0, y: font.descender - image.size.height / 2 + mid + 2, width: image.size.width, height: image.size.height))
    return textAttachment
}

काम करना चाहिए और किसी भी तरह से धुंधला नहीं होना चाहिए (धन्यवाद CGRectIntegral)


इसे पोस्ट करने के लिए धन्यवाद, यह मुझे बहुत अच्छे दृष्टिकोण की ओर ले जाता है। मैंने देखा कि आप अपने y समन्वय गणना में कुछ जादू 2 जोड़ रहे हैं।
बेन

2
यहाँ मैंने अपनी y- गणना के लिए क्या उपयोग किया है: descender + (abs (descender) + capHeight) / 2 - iconHeight / 2
बेन

Y मूल के लिए +2 क्यों?
विलियम लेगेट

@WilliamLeGate मुझे वास्तव में नहीं पता है, बस इसे आज़माया और यह उन सभी फ़ॉन्ट आकारों के लिए काम करता है जिनकी मैंने जांच की (जिनकी मुझे ज़रूरत थी) ..
बोरोफेरो

अच्छा लानत है ... यह जवाब आश्चर्यजनक है।
Giroiroo

38

व्हाट अबाउट:

CGFloat offsetY = -10.0;

NSTextAttachment *attachment = [NSTextAttachment new];
attachment.image = image;
attachment.bounds = CGRectMake(0.0, 
                               offsetY, 
                               attachment.image.size.width, 
                               attachment.image.size.height);

कोई उपवर्ग की जरूरत है


2
Self.font.descender का उपयोग करने से बेहतर काम करता है (जिसमें iOS 8 पर चलने वाले iPhone 4s सिम्युलेटर पर ~ 4 ​​का डिफ़ॉल्ट मान है)। -10 डिफ़ॉल्ट फॉन्ट स्टाइल / आकार के लिए एक बेहतर सन्निकटन की तरह दिखता है।
केदार परांजपे

10

@ ट्राविस सही है कि ऑफसेट फ़ॉन्ट डिसेंडर है। यदि आपको छवि को स्केल करने की आवश्यकता है, तो आपको NSTextAttachment के उपवर्ग का उपयोग करने की आवश्यकता होगी। नीचे वह कोड है, जो इस लेख से प्रेरित था । मैंने इसे एक जिस्ट के रूप में भी पोस्ट किया ।

import UIKit

class ImageAttachment: NSTextAttachment {
    var verticalOffset: CGFloat = 0.0

    // To vertically center the image, pass in the font descender as the vertical offset.
    // We cannot get this info from the text container since it is sometimes nil when `attachmentBoundsForTextContainer`
    // is called.

    convenience init(_ image: UIImage, verticalOffset: CGFloat = 0.0) {
        self.init()
        self.image = image
        self.verticalOffset = verticalOffset
    }

    override func attachmentBoundsForTextContainer(textContainer: NSTextContainer, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect {
        let height = lineFrag.size.height
        var scale: CGFloat = 1.0;
        let imageSize = image!.size

        if (height < imageSize.height) {
            scale = height / imageSize.height
        }

        return CGRect(x: 0, y: verticalOffset, width: imageSize.width * scale, height: imageSize.height * scale)
    }
}

निम्नानुसार उपयोग करें:

var text = NSMutableAttributedString(string: "My Text")
let image = UIImage(named: "my-image")!
let imageAttachment = ImageAttachment(image, verticalOffset: myLabel.font.descender)
text.appendAttributedString(NSAttributedString(attachment: imageAttachment))
myLabel.attributedText = text

10

यदि आपके पास बहुत बड़ा चढ़ा हुआ है और मेरी तरह छवि (केंद्र की ऊंचाई का केंद्र) को केंद्र में रखना चाहते हैं

let attachment: NSTextAttachment = NSTextAttachment()
attachment.image = image
if let image = attachment.image{
    let y = -(font.ascender-font.capHeight/2-image.size.height/2)
    attachment.bounds = CGRect(x: 0, y: y, width: image.size.width, height: image.size.height).integral
}

Y गणना नीचे दी गई तस्वीर की तरह है

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

ध्यान दें कि y मान 0 है क्योंकि हम चाहते हैं कि छवि मूल से नीचे की ओर जाए

यदि आप इसे पूरे लेबल के बीच में रखना चाहते हैं। इस y मान का उपयोग करें:

let y = -((font.ascender-font.descender)/2-image.size.height/2)

7

हम स्विफ्ट 4 में विस्तार कर सकते हैं जो इस तरह केंद्रित छवि के साथ एक लगाव उत्पन्न करता है:

extension NSTextAttachment {
    static func getCenteredImageAttachment(with imageName: String, and 
    font: UIFont?) -> NSTextAttachment? {
        let imageAttachment = NSTextAttachment()
    guard let image = UIImage(named: imageName),
        let font = font else { return nil }

    imageAttachment.bounds = CGRect(x: 0, y: (font.capHeight - image.size.height).rounded() / 2, width: image.size.width, height: image.size.height)
    imageAttachment.image = image
    return imageAttachment
    }
}

तब आप छवि और फ़ॉन्ट का नाम भेजने वाले कॉल कर सकते हैं:

let imageAttachment = NSTextAttachment.getCenteredImageAttachment(with: imageName,
                                                                   and: youLabel?.font)

और फिर imageAttachment को एट्रिब्यूटेड स्ट्रिंग में जोड़ें


1

मेरे मामले में sizeToFit () को कॉल करने में मदद मिली। स्विफ्ट में 5.1

अपने कस्टम लेबल के अंदर:

func updateUI(text: String?) {
    guard let text = text else {
        attributedText = nil
        return
    }

    let attributedString = NSMutableAttributedString(string:"")

    let textAttachment = NSTextAttachment ()
    textAttachment.image = image

    let sizeSide: CGFloat = 8
    let iconsSize = CGRect(x: CGFloat(0),
                           y: (font.capHeight - sizeSide) / 2,
                           width: sizeSide,
                           height: sizeSide)
    textAttachment.bounds = iconsSize

    attributedString.append(NSAttributedString(attachment: textAttachment))
    attributedString.append(NSMutableAttributedString(string: text))
    attributedText = attributedString

    sizeToFit()
}

0

सीमा ऊंचाई के लिए कृपया -lineFrag.size.height / 5.0 का उपयोग करें। यह बिल्कुल छवि को केंद्र में रखता है और फोंट के सभी आकार के लिए पाठ के साथ संरेखित करता है

override func attachmentBoundsForTextContainer(textContainer: NSTextContainer, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect
{
    var bounds:CGRect = CGRectZero

    bounds.size = self.image?.size as CGSize!
    bounds.origin = CGPointMake(0, -lineFrag.size.height/5.0);

    return bounds;
}

-lineFrag.size.height/5.0सही नहीं है। इसके बजाय यह फ़ॉन्ट अवरोही है।
फतमान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.