Центр изображения NSTextAttachment рядом с одной строкой UILabel
Я хотел бы добавить изображение 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];
однако изображение выравнивается по верхней части текстовой метки ячейки.
Как я могу изменить прямую, в которой нарисовано вложение?
9 ответов:
вы можете изменить rect путем подкласса
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-происхождение "на глаз", и если вы измените шрифт или размер значка, вы, вероятно, захотите изменить y-происхождение. Но я не мог найти лучшего способа, кроме как поставить значок в отдельный вид изображения (что имеет свои недостатки).
попробовать
- [NSTextAttachment bounds]
. Нет подклассов не требуется.для контекста, я представляя
UILabel
для использования в качестве изображения вложения, а затем установить границы следующим образом:attachment.bounds = CGRectMake(0, self.font.descender, attachment.image.size.width, attachment.image.size.height)
и базовые линии текста внутри изображения метки и текста в атрибутированной строке выстраиваются по желанию.
вы можете использовать высоту шрифта.
С
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 to .0 или .5
в вашем случае высота изображения больше, чем высота шрифта. Но вы можете использовать тот же способ. Значение смещения y будет отрицательным. И это будет выложены из нижней части базовой линии.
Я нашел идеальное решение для этого, работает как шарм для меня, хотя, однако, вы должны попробовать его самостоятельно (вероятно, константа зависит от разрешения устройства и, возможно, что угодно;)
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
)
о:
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);
подклассы не нужны
@Travis правильно, что смещение является спуском шрифта. Если вам также нужно масштабировать изображение, вам нужно будет использовать подкласс 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
Если у вас очень большой подъем и вы хотите центрировать изображение (центр высоты крышки), как я, попробуйте это
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)
мы можем сделать расширение в swift 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 к attributedString
пожалуйста, используйте-lineFrag.размер.высота / 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; }