UINavigationBar Ocultar texto do botão de volta


104

Como posso ocultar o texto do botão Voltar de um controlador UINavigation? Eu terei apenas o "<" e não "<Voltar"


1
você não pode modificar o texto padrão, em vez disso, tente navigationItem.leftBarButtonItem para definir o botão Voltar personalizado
BaSha


Veja minha resposta abaixo, se você deseja uma solução global usando um proxy de aparência.
fl034

Respostas:


107

No construtor de interface , você pode selecionar o item de navegação do controlador anterior e alterar a Back Buttonsequência para o que você gostaria que o botão voltar aparecesse. Se quiser em branco, por exemplo, basta colocar um espaço.

Você também pode alterá-lo com esta linha de código:

[self.navigationItem.backBarButtonItem setTitle:@"Title here"];

Ou em Swift :

self.navigationItem.backBarButtonItem?.title = ""


2
Dica incrível, aquela sobre como definir um espaço vazio no construtor de interface ... :-D
Felipe Ferri

9
O construtor de interface e as rotas programáticas do Swift não funcionaram para mim no XCode 8.3.2, Swift 3
agrippa

Você pode conferir minha solução muito simples para ocultar todos os botões de voltar em todo o aplicativo. PS: Requer zero linha de código próprio
Pratik Jamariya

2
Se Back Buttonjá estiver em branco no IB, basta adicionar um espaço para se livrar Backe apenas mostrar a seta.
Tejas K

3
Este método atualmente funciona apenas no construtor de interface. Definir isso a partir do código não funciona, em vez de definir apenas o título, você precisa definir todo o backBarButtonItem como este: navigationItem.backBarButtonItem = UIBarButtonItem (title: "", style: .plain, target: nil, action: nil)
Leszek Szary

81

Você também pode fazer isso por meio do storyboard. No inspetor de atributos do item de navegação do controlador anterior você pode definir "" no campo do botão Voltar. Consulte a imagem abaixo. Substitua "Seu título aqui" por "". Ao fazer isso, você alcançará o resultado desejado. Você não precisa mais mexer com o 'Título'.

Você pode usar de forma programática

[self.navigationItem.backBarButtonItem setTitle:@" "];

onde self se refere ao controlador que aciona o controlador de visualização desejado.

Item de navegação do controlador de visualização do Xcode

Amostra antes, depois da barra de navegação

Antes Antes

Depois de Depois de


7
Isso funciona perfeitamente se for definido em storyboards. Apenas certifique-se de que a barra de navegação contenha um item de navegação para que possa ser configurada.

11
No iOS 9 / Xcode 7.3, configurar backBarButtonItemprogramaticamente não funciona, mas configurá-lo por meio do storyboard, sim.
Scott Gardner

@ScottGardner, a configuração funcionabackBarButtonItem programaticamente para mim no iOS 9.
Suragch

Se você não tiver uma barra de navegação na tela, talvez porque ela precise ser escondida, você pode adicionar o item de navegação no storyboard, ao controlador de visualização anterior e definir o botão Voltar para "".
Martin Berger

A solução funcionou muito bem e foi muito fácil de implementar no Xcode 9.2 / iOS 11.
Ray Hunter

78

Você pode implementar UINavigationControllerDelegateassim:

Swift mais velho

func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
    let item = UIBarButtonItem(title: " ", style: .Plain, target: nil, action: nil)
    viewController.navigationItem.backBarButtonItem = item
}

Swift 4.x

class MyNavigationController: UINavigationController, UINavigationControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        let item = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
        viewController.navigationItem.backBarButtonItem = item
    }
}

backBarButtonItemé nilpor padrão e afeta o próximo controlador enviado, então basta configurá-lo para todos os controladores


6
Obrigado! Esta é a única solução que funcionou (sem bagunçar mais nada) depois de olhar para 4 perguntas duplicadas e dezenas de respostas.
entrada em

1
Eu já tinha uma subclasse de controlador de navegação que transformei em seu próprio delegado e funcionou perfeitamente. Deve atualizar para Swift 3 embora.
Dean Kelly

Ótima solução, obrigado, a única que funcionou de forma consistente para mim.
Elliott Davies

Woks como um encanto.
tounaobun

48

Definindo o título do botão Voltar para @""ounil não funcionará. Você precisa definir todo o botão vazio (sem um título ou imagem):

Objective-C

[self.navigationItem setBackBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]];

Rápido

self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)

Isso deve ser feito no controlador de visualização que está no topo de seu controlador de visualização na pilha de navegação (ou seja, de onde você navega para o seu VC via pushViewControllermétodo)


2
obrigado, funciona! Em rápida: self.navigationItem.backBarButtonItem = UIBarButtonItem (título: "", estilo: .Plain, alvo: nulo, ação: nulo)
mostworld77

excelente resposta .. corretamente aponta que apenas alterar o título do backBarButtonItem padrão não será suficiente. Pontos de bônus por mencionar que backBarButtonItem deve ser definido no controlador de visualização anterior.
Crazed'n'Dazed

30

Outra solução para esse problema para situações em que você tem muitos controladores de visualização é usar um UIAppearanceproxy para ocultar efetivamente o texto do título do botão Voltar, como este:

UIBarButtonItem *navBarButtonAppearance = [UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil];

[navBarButtonAppearance setTitleTextAttributes:@{
    NSFontAttributeName:            [UIFont systemFontOfSize:0.1],
    NSForegroundColorAttributeName: [UIColor clearColor] }
                                      forState:UIControlStateNormal];

Essa solução renderizará o texto como um pequeno ponto claro, semelhante a definir manualmente o título do botão Voltar como @" ", exceto que afeta todos os botões da barra de navegação.

Não sugiro isso como uma solução geral para o problema porque afeta todos os botões da barra de navegação. Ele inverte o paradigma para que você escolha quando mostrar os títulos dos botões, em vez de quando ocultar os títulos.

Para escolher quando mostrar os títulos, restaure manualmente os atributos do texto do título conforme necessário ou crie uma subclasse especializada UIBarButtonItemque faça o mesmo (potencialmente com outro UIAppearanceproxy).

Se você tem um aplicativo em que a maioria dos títulos dos botões Voltar precisa ser ocultada e apenas alguns (ou nenhum) dos botões de navegação são botões do sistema com títulos, isso pode ser para você!

(Observação: a alteração do tamanho da fonte é necessária, embora a cor do texto seja clara, a fim de garantir que títulos longos não façam com que o título da barra de navegação central se desloque)


Foi a solução mais fácil para minha implementação. Obrigado.
Trevor Panhorst

3
Isso também não cobre os itens do botão da barra esquerda que não são botões de voltar?
kevinl

1
Sim, eu notei isso. "afeta todos os botões da barra de navegação"
Adam Kaplan

2
não deveria afetar todos os outros botões nas barras de navegação, incluindo itens de botão da barra esquerda / direita?
Fyodor Volchyok

Sim, ele não especificou um requisito mais abrangente.
Adam Kaplan

30

Adicione o seguinte código em viewDidLoad ou loadView

self.navigationController.navigationBar.topItem.title = @"";  

Testei no iPhone e iPad com iOS 9


20
Isso não limpou o título do controlador de visão anterior?
CalZone

6
Não use porque isso removerá o último título da tela
evya

Se precisar fazer isso a partir do controlador de visualização atual, para evitar a remoção do título do vc anterior, você deve preferir: navigationController? .NavigationBar.topItem? .BackBarButtonItem = UIBarButtonItem (title: "", style: .plain, target: nil, ação: zero)
Leszek Szary

15

Você pode adicionar esta categoria Objective-C para fazer com que todos os botões "Voltar" criados por um controlador de navegação não tenham texto. Acabei de adicioná-lo ao meu arquivo AppDelegate.m.

@implementation UINavigationItem (Customization)

/**
 Removes text from all default back buttons so only the arrow or custom image shows up.
 */
-(UIBarButtonItem *)backBarButtonItem
{
    return [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
}

@end

PS - (Não sei como fazer esta extensão funcionar com Swift, estava tendo erros estranhos. Edições bem-vindas para adicionar uma versão Swift)


Isso dá o título "Voltar" e não esconde o título
Raj Aggrawal

Realmente, como fazer overrideisso rapidamente. Pergunta muito interessante
Andrey Gagan

@teradyl é a melhor resposta.
aks.knit1108

@Andrey Gagan, veja minha resposta
Abirami Bala

Isso funciona no iOS 9.0 - 10.3.3, mas no iOS 11+ não funciona.
Sihad Begovic

14

Tentei alguns acima e abaixo, mas não funcionaram. Isso funcionou para mim:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.navigationBar.topItem?.title = ""
}

1
Se precisar fazer isso a partir do controlador de visualização atual, para evitar a remoção do título do vc anterior, você deve preferir: navigationController? .NavigationBar.topItem? .BackBarButtonItem = UIBarButtonItem (title: "", style: .plain, target: nil, ação: zero)
Leszek Szary

11

A única coisa que funciona sem efeitos colaterais é criar um botão Voltar personalizado. Contanto que você não forneça uma ação personalizada, até mesmo o gesto de deslizar funciona.

extension UIViewController {
func setupBackButton() {
    let customBackButton = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
    navigationItem.backBarButtonItem = customBackButton
}}

Infelizmente, se você quiser que todos os botões de voltar no não tenham títulos, você precisa configurar este botão de voltar personalizado em todos os seus controladores de visualização: /

override func viewDidLoad() {
    super.viewDidLoad()

    setupBackButton()
}

É muito importante que você defina um espaço em branco como título e não a string vazia.


9

para remover o texto do botão de fundo programaticamente, usado abaixo do Código, isso funcionará no xcode7 e acima.

self.navigationController.navigationBar.topItem.title = @ "";

ou

manualmente em storyboards, selecione a barra de navegação no controlador de visualização e coloque "" no texto do botão Voltar.

isso vai funcionar. obrigado


2
Este também removerá o título do
item de

Editei sua resposta para isso: self.navigationController?.navigationBar.topItem?.title = " "no Xcode 9 e funcionou!
MHSFisher de

Se precisar fazer isso a partir do controlador de visualização atual, para evitar a remoção do título do vc anterior, você deve preferir: navigationController? .NavigationBar.topItem? .BackBarButtonItem = UIBarButtonItem (title: "", style: .plain, target: nil, ação: zero)
Leszek Szary

8

A resposta atual não estava funcionando. eu queria remover o título inteiramente, mas o texto "voltar" não estava indo embora.

Volte para o controlador de visualização anterior e defina sua propriedade de título:

self.title = @" ";

funciona quando o View Controller anterior não tem um título


@ZevEisenberg certifique-se de que a propriedade esteja sendo definida antes de ser exibida no ciclo de vida do View Controller. Significa defini-lo nos métodos viewDidLoad ou viewWillAppear.
ChrisHaze

1
Além disso, certifique-se de incluir um espaço entre as aspas.
ChrisHaze

1
Na verdade, acabou funcionando para mim sem espaços; apenas a boa e velha string vazia:@"" .
Zev Eisenberg

1
@ZevEisenberg, Quando eu criei a solução pela primeira vez, ela estava no Xcode 5. Com um espaço era a única maneira de funcionar, é por isso que o incluí no código de amostra. A atualização do Xcode 6 deve tê-lo incluído. Bom saber - thx
ChrisHaze,

Também usei minha abordagem, que ainda está funcionando, e também removi a seta padrão para trás.
ChrisHaze,

5

Maneira alternativa - use a classe NavigationBar personalizada.

class NavigationBar: UINavigationBar {

    var hideBackItem = true
    private let emptyTitle = ""

    override func layoutSubviews() {
        if let `topItem` = topItem,
            topItem.backBarButtonItem?.title != emptyTitle,
            hideBackItem {
            topItem.backBarButtonItem = UIBarButtonItem(title: emptyTitle, style: .plain, target: nil, action: nil)
        }

        super.layoutSubviews()
    }

}

Ou seja, isso remove títulos de todo o projeto. Basta definir a classe personalizada para UINavigationController.


4

Defina o Título do VC anterior como string "" com espaço. e o título com o botão Voltar será substituído por uma string de espaço simples.

Self.title = " "

Em Voltar, pressione novamente para redefinir o título para o original no viewWillAppear.


4

Use um costume NavigationControllerque substituipushViewController

class NavigationController: UINavigationController {  
  override func pushViewController(_ viewController: UIViewController, animated: Bool) {
    viewController.navigationItem.backBarButtonItem =
      UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    super.pushViewController(viewController, animated: animated)
  }
}

4

Muitas respostas já, aqui estão meus dois centavos sobre o assunto. Achei essa abordagem realmente robusta. Você só precisa colocar isso em viewController antes de seguir.

Swift 4:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}

2
Sim! Obrigado :)
Hews

3

Tentei de tudo neste post. A única solução de trabalho é @VoidLess's

Aqui está a mesma resposta, mas mais completa

class CustomNavigationController: UINavigationController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.delegate = self
    }
}


// MARK:UINavigationControllerDelegate
extension CustomNavigationController {
    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        viewController.navigationItem.backBarButtonItem = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
    }
}

3

Esta é minha resolução para iOS11, eu mudo a aparência de UIBarButtonItem em applicationDidFinishLaunchingWithOptions:

UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(-100, 0), for:UIBarMetrics.default)

Você não pode alterar o deslocamento Y, porque isso mudará a posição do botão da barra traseira também no iOS11, mas está OK no iOS10 e abaixo.


1
Funciona, mas durante a animação você pode ver o título anterior movendo-se para a esquerda. Parece um pouco bugado.
Jonathan

2

Em Swift3,

Se você definir uma configuração global

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    // ..

    let BarButtonItemAppearance = UIBarButtonItem.appearance()
    BarButtonItemAppearance.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: .normal)
    BarButtonItemAppearance.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: .highlighted)


    // ...

}

1
Observe que isso também mudará a cor para transparente de todos os outros botões da barra que você possa ter em algum lugar do seu aplicativo, não apenas os botões Voltar.
Leszek Szary

2

Swift 3.1 Você pode fazer isso implementando o método delegado de UINavigationController.

func navigationController(_ navigationController: UINavigationController, 
                          willShow viewController: UIViewController, animated: Bool) {

    /** It'll hide the Title with back button only,
     ** we'll still get the back arrow image and default functionality.
     */
    let item = UIBarButtonItem(title: " ", style: .plain, target: nil, 
                               action: nil)
    viewController.navigationItem.backBarButtonItem = item
}

A melhor resposta!
evya

2

Para aqueles que desejam ocultar o título do botão Voltar globalmente.

Você pode swizzle viewDidLoadde UIViewControllercomo esta.

+ (void)overrideBackButtonTitle {

    NSError *error;

    // I use `Aspects` for easier swizzling.

    [UIViewController aspect_hookSelector:@selector(viewDidLoad)
                              withOptions:AspectPositionBefore
                               usingBlock:^(id<AspectInfo> aspectInfo)
    {

        UIViewController *vc = (UIViewController *)aspectInfo.instance;

        // Check whether this class is my app's view controller or not.
        // We don't want to override this for Apple's view controllers,
        // or view controllers from external framework.

        NSString *className = NSStringFromClass([vc class]);
        Class class = [NSBundle.mainBundle classNamed:className];
        if (!class) {
           return;
        }

        UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@" " style:UIBarButtonItemStylePlain target:nil action:nil];
        vc.navigationItem.backBarButtonItem = backButton;

    } error:&error];

    if (error) {
        NSLog(@"%s error: %@", __FUNCTION__, error.localizedDescription);
    }

}

Uso:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[self class] overrideBackButtonTitle];
    return YES;
}

2

Se você tem como alvo o iOS 13 e posterior, pode usar esta nova API para ocultar o título do botão Voltar globalmente .

let backButtonAppearance = UIBarButtonItemAppearance()
backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear]

UINavigationBar.appearance().standardAppearance.backButtonAppearance = backButtonAppearance
UINavigationBar.appearance().compactAppearance.backButtonAppearance = backButtonAppearance
UINavigationBar.appearance().scrollEdgeAppearance.backButtonAppearance = backButtonAppearance

1
Isso não é o ideal. Se um usuário tocar no rótulo com o texto não criptografado, a ação de retorno ainda será acionada.
dvdblk

1

Eu estava lutando com isso porque tinha um controlador de navegação personalizado. Consegui remover o texto do item anterior em todos os controladores de visualização com este código na minha classe de controlador de navegação personalizado override func viewDidLayoutSubviews() { self.navigationBar.backItem?.title = "" }

Isso remove todos os títulos dos itens anteriores usando este controlador de navegação personalizado.


1
Atualização para isso: funciona, mas há um atraso estranho no carregamento que me incomoda. Agora adicionei este 'let BarButtonItemAppearance = UIBarButtonItem.appearance () BarButtonItemAppearance.setTitleTextAttributes ([NSAttributedStringKey.foregroundColor: UIColor.clear], para: .Withpearance)' no App delegate funcionou perfeitamente!
Amy.R

0

No iOS 11, descobrimos que definir UIBarButtonItema fonte / cor do texto da aparência para um valor muito pequeno ou cor clara fará com que outro item da barra desapareça (o sistema não honra mais a classe do item UIBarButton, ele irá convertê-lo para a _UIModernBarButton). Além disso, definir o deslocamento do texto de volta para fora da tela resultará em flash durante o pop interativo.

Então, nós swizzled addSubView:

+ (void)load {
    if (@available(iOS 11, *)) {
        [NSClassFromString(@"_UIBackButtonContainerView")     jr_swizzleMethod:@selector(addSubview:) withMethod:@selector(MyiOS11BackButtonNoTextTrick_addSubview:) error:nil];
    }
}

- (void)MyiOS11BackButtonNoTextTrick_addSubview:(UIView *)view {
    view.alpha = 0;
    if ([view isKindOfClass:[UIButton class]]) {
        UIButton *button = (id)view;
        [button setTitle:@" " forState:UIControlStateNormal];
    }
    [self MyiOS11BackButtonNoTextTrick_addSubview:view];
}

0
-(void)setNavigationItems{
     UIBarButtonItem *leftBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"**Your title here**" style:UIBarButtonItemStyleBordered target:self action:@selector(backButtonClicked)];   
     self.navigationController.navigationBar.topItem.backBarButtonItem=leftBarButtonItem;
}
-(void)backButtonClicked{
    [self.navigationController popViewControllerAnimated:YES];
}

0

O texto de volta vem do último View Controller navigationItem.title, e navigationItem.titleé definido automaticamente por self.title. Uma maneira fácil de resolver o problema é o gancho setTitle:, certifique-senavigationItem.title = @""

Coloque este código em AppDelegate.mfará com que fique ok。

    [UIViewController aspect_hookSelector:@selector(setTitle:)
                              withOptions:AspectPositionAfter
                               usingBlock:^(id<AspectInfo> aspectInfo, NSString *title) {
        UIViewController *vc = aspectInfo.instance;
        vc.navigationItem.titleView = ({
            UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
            titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
            titleLabel.text = title;
            titleLabel;
        });
        vc.navigationItem.title = @"";
    } error:NULL];

Mais detalhes em https://www.jianshu.com/p/071bc50f1475(Simple Chinease)


0

Minha solução: - XCode: 10.2.1 - Swift: 5

  • Controlador de visualização pai:
    • self.title = ""
  • Controlador de visão infantil:
    • self.navigationItem.title = "Seu título" // para definir o título para viewcontroller

0

XCode 11.5 Swift 5

Uma maneira muito simples - embora talvez um pouco hackeada - de fazer isso programaticamente se você não precisar do botão voltar personalizado é definir o tamanho da fonte igual a zero no controlador de visualização que você está empurrando para a pilha, chamando algo assim de viewDidLoad

private func setupNavBar() {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithDefaultBackground()
    
    let backButtonAppearance = UIBarButtonItemAppearance()
    backButtonAppearance.normal.titleTextAttributes = [.font: UIFont(name: "Arial", size: 0)!]
    appearance.backButtonAppearance = backButtonAppearance

    navigationItem.standardAppearance = appearance
    navigationItem.scrollEdgeAppearance = appearance
    navigationItem.compactAppearance = appearance
}

-1

Finalmente encontrei a solução perfeita para ocultar o texto de volta padrão em todo o aplicativo.

Basta adicionar uma imagem transparente e adicionar o código a seguir em seu AppDelegate.

UIBarButtonItem.appearance().setBackButtonBackgroundImage(#imageLiteral(resourceName: "transparent"), for: .normal, barMetrics: .default)

-2

O método a seguir funciona no iOS 11 e é seguro para não travar em outras versões do iOS. Fazer isso pode fazer com que seu aplicativo seja rejeitado na revisão da App Store, pois UIModernBarButton e UIBackButtonContainerView são APIs privadas. Coloque em AppDelegate.

    if
        let UIModernBarButton = NSClassFromString("_UIModernBarButton") as? UIButton.Type,
        let UIBackButtonContainerView = NSClassFromString("_UIBackButtonContainerView") as? UIView.Type {

        let backButton = UIModernBarButton.appearance(whenContainedInInstancesOf: [UIBackButtonContainerView.self])
        backButton.setTitleColor(.clear, for: .normal)
    }

Fazer isso pode fazer com que seu aplicativo seja rejeitado na revisão da App Store, pois UIModernBarButton e UIBackButtonContainerView são APIs privadas.
Groot

Obrigado @Groot, adicionado seu aviso.
Patrick,

-5

Versão Swift, funciona perfeitamente globalmente:

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        UIBarButtonItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName:UIColor.clearColor()], forState: UIControlState.Normal)
        UIBarButtonItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName:UIColor.clearColor()], forState: UIControlState.Highlighted)

        return true
    }

7
Você deve adicionar que isso irá ocultar todo o texto também rightBarButtons e leftBarButtons, que não voltam.
limfinity

este não é um solution. Como @limfinity apontou, ele irá alterá-lo universalmente para todos os UIBarButtonItem em todo o aplicativo
Danut Pralea,

concordo com @limfinity e Danut Pralea, ele irá ocultar todo o texto do UIBarButtonItem em todo o aplicativo
Pratik Jamariya
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.