A string atribuída com fontes personalizadas no storyboard não carrega corretamente

100

Estamos usando fontes personalizadas em nosso projeto. Funciona bem no Xcode 5. No Xcode 6, funciona em texto simples, string atribuída no código. Mas todas as sequências atribuídas definidas no storyboard revertem para Helvetica quando executadas no simulador ou dispositivo, embora pareçam bem no storyboard.

Não tenho certeza se é um bug do Xcode 6 ou iOS 8 SDK, ou a forma de usar fontes personalizadas foi alterada no Xcode 6 / iOS 8?

Allen Hsu
fonte
Mesmo problema aqui. Adoraria saber o que está acontecendo.
obeattie
1
Por enquanto, criamos um UILabel customizado, denominado GLMarkdownLabel, e exportamos algumas propriedades com IBInspectable, em seguida, definimos as sequências de marcação no storyboard e traduzimos as sequências de marcação de volta para as sequências atribuídas ao acordar do bico.
Allen Hsu
Agora é uma solução de longo prazo, espero que a Apple conserte esse bug na próxima versão do Xcode.
Allen Hsu
Caramba, que cruft. Obrigado por nos informar que não é um problema isolado. Existe um radar?
obeattie
1
Nossa solução alternativa foi, eventualmente, voltar a usar IBCustomFonts para nossos rótulos atribuídos.
yonix,

Respostas:

30

A solução para mim foi usar uma IBDesignableclasse:

import UIKit

@IBDesignable class TIFAttributedLabel: UILabel {

    @IBInspectable var fontSize: CGFloat = 13.0

    @IBInspectable var fontFamily: String = "DIN Light"

    override func awakeFromNib() {
        var attrString = NSMutableAttributedString(attributedString: self.attributedText)
        attrString.addAttribute(NSFontAttributeName, value: UIFont(name: self.fontFamily, size: self.fontSize)!, range: NSMakeRange(0, attrString.length))
        self.attributedText = attrString
    }
}

Fornecendo isso no Interface Builder:

Fonte personalizada do Interface Builder com string atribuída

Você pode configurar sua string de atribuição como faz normalmente, mas terá que configurar seu tamanho de fonte e família de fonte mais uma vez nas novas propriedades disponíveis.

Como o Interface Builder está trabalhando com a fonte personalizada por padrão, isso resulta em um o que você vê é o que obtém , o que eu prefiro ao criar aplicativos.

Nota

O motivo pelo qual estou usando isso em vez de apenas a versão simples é que estou definindo propriedades no rótulo atribuído, como o espaçamento de linha, que não estão disponíveis ao usar o estilo simples.

Antoine
fonte
1
Sua solução suporta apenas uma família de fontes e tamanho para uma etiqueta, então por que não usar apenas texto simples?
Allen Hsu
Da mesma forma, estamos usando @IBInspectableatributos temporariamente, em vez de fonte e tamanho. Temos uma markdownTextpropriedade porque, na maioria das vezes, usamos string atribuída para texto em negrito ou sublinhado. Em seguida, analise o texto marcado para a string atribuída com as informações de fonte e tamanho definidas para texto simples.
Allen Hsu
@AllenHsu, você está certo. Não mencionei isso, mas estou usando o espaçamento de linha atribuído para minha etiqueta. Claro, senão você usaria o estilo simples :)
Antoine
bom ponto, exportamos lineSpacing também: p Acho que aceitaria sua resposta, pois na verdade é um bug no Xcode e não há solução melhor por enquanto. Vamos esperar pela próxima versão do Xcode.
Allen Hsu
2
Isso não funcionará se eu quiser colocar em negrito uma parte do texto
xtrinch
28

A resposta mais simples que funcionou é arrastar as fontes para o FontBook. Se as fontes estão em seu projeto, mas não no FontBook do seu computador, o IB às vezes tem problemas para encontrá-las. Estranho, mas funcionou para mim em várias ocasiões.

Alan Scarpa
fonte
17
Embora isso permita que o Xcode selecione a fonte personalizada, na verdade não funciona. Em tempo de execução, a fonte não será usada como você esperava.
Daniel
Infelizmente, não fui capaz de encontrar uma solução alternativa. O melhor que pude fazer foi registrar um bug na Apple.
Daniel
Sim, essa é a solução. Meu storyboard foi projetado por outro desenvolvedor, svn update ok, mas nunca obtive a fonte na IU. A fonte estava nos recursos, mas não era mostrada na IU do dispositivo / simulador. Como ele usa string atribuída, devo colocá-la no Font Book. Isso resolve o problema.
karim
Sim. isso me ajuda a resolver o mesmo problema. Quando adiciono uma fonte personalizada ao livro de fontes, as coisas funcionam perfeitamente.
Sushant Jagtap de
1
Embora essa solução funcione em alguns casos, também enfrentei o mesmo problema que @Daniel no mesmo projeto com a mesma família de fontes. O XCode precisa resolver esse problema.
dey.shin
16

Você pode adicionar fontes personalizadas ao livro de fontes.

Passo 1 : Clique em gerenciar fontes. Ele abre o livro de fontes.

insira a descrição da imagem aqui

Passo 2 : Clique em mais e adicione suas fontes.

insira a descrição da imagem aqui

Da próxima vez, quando você clicar na fonte com o texto atribuído, a fonte recém-adicionada também aparecerá na lista. Mas certifique-se de que sua fonte personalizada foi adicionada aos recursos info.plist e bundle.

Mahbaleshwar hegde
fonte
Isso funciona no storyboard, mas depois de executá-lo não mostra a formatação
Van
1
Formatação @Van? Você pode me contar mais? Quando não está funcionando?
mahbaleshwar hegde
Eu tenho que definir o texto que é uma combinação de combinação de rgualr e fonte em negrito. Usei a solução acima, então funcionou no storyboard, mas quando executo o aplicativo, o rótulo não mostra a fonte aplicada, em vez disso, mostra a fonte do sistema
Van
Você adicionou suas fontes personalizadas em info.plist? Depois disso, basta imprimir todas as famílias de fontes
mahbaleshwar hegde
2
sim. Posso definir a fonte personalizada em todo o aplicativo no caso de texto simples, preciso definir para o texto atribuído
Van
5

Graças a este tópico, cheguei a esta solução:

private let fontMapping = [
    "HelveticaNeue-Medium": "ITCAvantGardePro-Md",
    "HelveticaNeue": "ITCAvantGardePro-Bk",
    "HelveticaNeue-Bold": "ITCAvantGardePro-Demi",
]

func switchFontFamily(string: NSAttributedString) -> NSAttributedString {
    var result = NSMutableAttributedString(attributedString: string)
    string.enumerateAttribute(NSFontAttributeName, inRange: NSRange(location: 0, length: string.length), options: nil) { (font, range, _) in
        if let font = font as? UIFont {
            result.removeAttribute(NSFontAttributeName, range: range)
            result.addAttribute(NSFontAttributeName, value: UIFont(name: fontMapping[font.fontName]!, size: font.pointSize)!, range: range)
        }
    }
    return result
}
rexsheng
fonte
1
Boa ideia. É realmente inacreditável que isso esteja quebrado na Apple. Surpreendente.
Fattie
4

Minha solução é meio que uma solução alternativa. A solução real é a apple consertar o Interface Builder.

Com ele, você pode marcar todo o texto em negrito e itálico no construtor de interface usando uma fonte do sistema e, em tempo de execução, renderizar sua fonte personalizada. Pode não ser ideal em todos os casos.

 NSMutableAttributedString* ApplyCustomFont(NSAttributedString *attributedText,
                     UIFont* boldFont,
                     UIFont* italicFont,
                     UIFont* boldItalicFont,
                     UIFont* regularFont)
{

    NSMutableAttributedString *attrib = [[NSMutableAttributedString alloc] initWithAttributedString:attributedText];
    [attrib beginEditing];
    [attrib enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, attrib.length) options:0
                    usingBlock:^(id value, NSRange range, BOOL *stop)
    {
        if (value)
        {
            UIFont *oldFont = (UIFont *)value;
            NSLog(@"%@",oldFont.fontName);

            [attrib removeAttribute:NSFontAttributeName range:range];

            if([oldFont.fontName rangeOfString:@"BoldItalic"].location != NSNotFound && boldItalicFont != nil)
                [attrib addAttribute:NSFontAttributeName value:boldItalicFont range:range];
            else if([oldFont.fontName rangeOfString:@"Italic"].location != NSNotFound && italicFont != nil)
                [attrib addAttribute:NSFontAttributeName value:italicFont range:range];
            else if([oldFont.fontName rangeOfString:@"Bold"].location != NSNotFound && boldFont != nil)
                [attrib addAttribute:NSFontAttributeName value:boldFont range:range];
            else if(regularFont != nil)
                [attrib addAttribute:NSFontAttributeName value:regularFont range:range];
        }
    }];
    [attrib endEditing];

    return attrib;
}

Inspirado por esta postagem

KidA
fonte
4

Tenho lutado com este bug: UILabel é exibido corretamente em IB com fonte personalizada, mas não é exibido corretamente no dispositivo ou simulador (a fonte está incluída no projeto e é usada em UILabels simples).

Finalmente encontrei o Attributed String Creator na App Store (Mac). Gera código a ser colocado em seu aplicativo no local apropriado. Fantástico. Eu não sou o criador, apenas um usuário feliz.

ghr
fonte
3

Encontrou o mesmo problema: a fonte do atributo definida para TextView no storyboard não funcionou em tempo de execução com o XCode 6.1 e iOS 8 SDK.

Foi assim que resolvi esse problema, pode ser uma solução alternativa para você:

  1. abra o inspetor de atributos de sua visualização de texto, altere o texto para "Simples"

  2. clique na cruz para excluir o "wC hR" (vermelho abaixo)

    insira a descrição da imagem aqui

  3. mude o texto para "Atribuído", e então você pode definir a fonte e o tamanho do seu texto.

  4. corra para verificar se funciona
Zhihao Yang
fonte
Parece que por padrão não há nenhuma wC hRpropriedade definida, UILabelnem UITextView.
Allen Hsu
pelo xcode 6, você definiu outro tipo de altura-largura, como "Largura regular | Qualquer altura", "Largura compacta | Altura regular"? porque tenho um projeto desenvolvido em Xcode 5 e seu textview atribuído está funcionando mesmo com iOS 8 SDK, verifiquei as configurações e descobri que a única diferença é que o Xcode 6 permite aos usuários definir a fonte para diferentes tamanhos de dispositivos se você definir o texto em "Avião". Esta nova configuração pode ser o motivo pelo qual definir o texto como "atribuído", mas a fonte não está funcionando.
Zhihao Yang
1
você está usando fontes personalizadas? Refiro-me aos auto-embutidos, não às fontes do sistema.
Allen Hsu
Aha, pensei que as fontes "Custom" que você mencionou são as oferecidas pelo Xcode, desde que tenha a fonte "System".
Zhihao Yang,
Isto não funciona para mim. Funciona para string normal, mas não para string atribuída.
Pratik Somaiya
2

Encontrou o mesmo problema: o atributo fonte para UILabel no storyboard não funcionou em tempo de execução. Usar este UIFont + IBCustomFonts.m funciona para mim https://github.com/deni2s/IBCustomFonts

Praveen Sevta
fonte
2

Tente isso vai funcionar

No meu caso, quando tento definir "Tecnologia Silversky" como texto atribuído para rótulo do construtor de interface, não é mostrado quando executo no simulador, mas é mostrado no construtor de interface. Então eu usei um truque que fiz a fonte Silversky com 1 pixel maior que o texto Tecnologia.

O texto do atributo tem problemas com o mesmo tamanho de fonte, então altere o tamanho de 1 palavra neste que funcione comigo.

Pode ser que seja um bug do xcode, mas esse truque funciona para mim.

Tecnologia Silversky
fonte
1

O mesmo problema.

Resolvido: basta marcar Selecionável em TextView. Sem isso, tenho uma fonte padrão do sistema.

Maselko
fonte
1

Clique duas vezes e instale a fonte no sistema. Vai funcionar (Xcode 8.2)

Ishara Meegahawala
fonte
1
Eu gostaria que fosse. Não está funcionando para mim com FontAwesome.
Peter DeWeese
1

A solução @Hamidptb funciona, certifique-se de obter o nome correto da fonte (depois de adicioná-la ao Catálogo de Fontes)

  • Abra o aplicativo Catálogo de Fontes, navegue até sua fonte e pressione Command + I. O nome PostScript é o nome da fonte que você deseja usar aqui:

    UILabel.appearance (). Font = UIFont (nome: " PostScriptName ", tamanho: 17)

itsmcgh
fonte
0

Eu estava tentando obter células tableView com texto com vários parágrafos. As strings atribuídas pareciam ser uma forma de obter espaço extra entre os parágrafos (algo um pouco mais bonito do que fazer duas alimentações de linha na string). Me deparei com este e outros posts quando descobri que as configurações de IB não se aplicavam no tempo de execução quando você queria colocar um texto diferente na célula.

A principal coisa que eu fiz foi adicionar uma extensão a String (usando Swift) para criar uma string atribuída com certas características. O exemplo aqui usa a fonte Marker Felt, pois é facilmente distinguível da Helvetica. O exemplo também mostra um pouco mais de espaçamento entre os parágrafos para torná-los mais distintos uns dos outros.

extension String {
func toMarkerFelt() -> NSAttributedString {
    var style = NSMutableParagraphStyle()
    style.paragraphSpacing = 5.0
    let markerFontAttributes : [NSObject : AnyObject]? = [
        NSFontAttributeName : UIFont(name: "Marker Felt", size: 14.0)!,
        NSParagraphStyleAttributeName: style,
        NSForegroundColorAttributeName : UIColor.blackColor()
    ]
    let s = NSAttributedString(string: self, attributes: markerFontAttributes)
    return s
    }
}

Então, em meu tableViewCell personalizado, você envia o texto que deseja e ele o converte em uma string atribuída no UILabel.

//  MarkerFeltCell.swift
class MarkerFeltCell: UITableViewCell {
@IBOutlet weak var myLabel: UILabel!
func configureCellWithString(inputString : String) {
    myLabel.attributedText = inputString.toMarkerFelt()
}}

No controlador de visualização com tableView, você deve registrar sua célula em viewDidLoad () - usei uma ponta, então algo como:

let cellName = "MarkerFeltCell"
tableView.registerNib(UINib(nibName: cellName, bundle: nil), forCellReuseIdentifier: cellName)

Para fazer com que a célula descubra a altura que deve ter, faça um protótipo de célula que é usado para obter informações de tamanho e nunca é adicionado ao tableView. Então, nas variáveis ​​do seu controlador de visualização:

var prototypeSummaryCell : MarkerFeltCell? = nil

Então em (provavelmente substituir - dependendo do seu controlador de visualização) heightForRowAtIndexPath:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        // ...
    if xib == "MarkerFeltCell" {
            if prototypeCell == nil {
                prototypeCell = tableView.dequeueReusableCellWithIdentifier(xib) as? MarkerFeltCell
            }
            let width : CGFloat = tableView.bounds.width
            let height : CGFloat = prototypeCell!.bounds.height
            prototypeCell?.bounds = CGRect(x: 0, y: 0, width: width, height: height)
            configureCell(prototypeCell!, atIndexPath: indexPath)
            prototypeSummaryCell?.layoutIfNeeded()
            let size = prototypeSummaryCell!.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
            let nextHeight : CGFloat = ceil(size.height + 1.0)
            return nextHeight
    } else {  // ...

No código acima, o prototypeCell será preenchido na primeira vez que for necessário. O prototypeCell é então usado para descobrir a altura da célula após passar pelo processo de dimensionamento automático. Você precisará arredondar a altura com a função ceil (). Eu também adicionei algum fator de fudge extra.

O bit de código final é como você configura o texto para a célula. Para este exemplo, simplesmente:

func configureCell(cell :UITableViewCell, atIndexPath indexPath: NSIndexPath) {
    if let realCell = cell as? MarkerFeltCell  {
        realCell.configureCellWithString("Multi-line string.\nLine 2.\nLine 3.")    // Use \n to separate lines
    }
}

Além disso, aqui está uma foto do bico. Fixou o rótulo nas bordas da célula (com a margem desejada), mas usou uma restrição "Maior que ou igual", com uma prioridade menor que "Obrigatório" para a restrição inferior.

Restrições de células

Defina a fonte do rótulo como Atribuída. A fonte real do IB não importava.

LabelFont

O resultado neste caso:

CellResults

Anorskdev
fonte
0

No caso de string atribuída, você pode adicionar uma fonte personalizada na lista de fontes como - Clique no ícone da fonte para exibir a seguinte caixa de diálogo. Na caixa de diálogo seguinte, você pode adicionar sua própria categoria ou uma existente para a fonte personalizada. caixa de diálogo de fonte atribuída

Depois de clicar em Gerenciar Fontes, ele abre a seguinte caixa de diálogo, selecione a categoria em que você criou ou já existe. Clique no sinal + para adicionar a fonte na categoria. Gerenciar caixa de diálogo de fonte

Sunil Singh
fonte
0

que tem uma solução simples e rápida e isso funciona no meu caso. essa solução é adicionar uma linha de código na função didFinishLaunchingWithOptions no arquivo AppDelegate.swift:

para textViews :

UITextView.appearance().font = UIFont(name: "IranSans", size: 17)

para etiquetas :

UILabel.appearance().font = UIFont(name: "IranSans", size: 17)

e para o resto do UiView como este dois ☝️

Hamid Reza Ansari
fonte
0

Para qualquer pessoa que aplique fontes personalizadas a strings atribuídas no código: tente configurá-las em viewDidLayoutSubviews. O meu erro foi fazer dentro viewDidLoad, não vai ser aplicado lá.

sergey.syrotynin
fonte