Mapear componentes para códigos existentes

Os desenvolvedores podem personalizar o processo de geração de código fornecendo um mapeamento entre um pacote da IU e um componente de código existente em vez do código gerado. Isso é benéfico quando a implementação atual tem recursos que não podem ser obtidos pelo código gerado, como animação ou comportamento complexo (como um menu suspenso).

Os desenvolvedores especificam como mapear componentes usando um arquivo de mapeamento. Um arquivo de mapeamento informa ao gerador de código, no mínimo, como alcançar a função combinável de destino para que o código de cliente correto possa ser criado.

Diagrama de visão geral do componente mapeado

Confira um exemplo:

No Figma, um designer cria um componente Card que contém uma instância de um componente Play Bar, empacota os dois componentes e os envia a um desenvolvedor.

Quando o desenvolvedor importa os pacotes de interface do Figma, dois diretórios são criados em ui-packages: card e play_bar. Ao criar o projeto, duas funções de composição são criadas: Card e PlayBar. Normalmente, como Card contém uma instância de Play Bar no Figma, no código a função combinável Card contém uma chamada para o elemento combinável PlayBar.

No entanto, o designer e o desenvolvedor querem que o Card use um elemento combinável o MyExistingPlaybar, que tem uma funcionalidade difícil de descrever no Figma. Portanto, o desenvolvedor adiciona um arquivo de mapeamento chamado play_bar.json que mapeia o pacote de IU do play_bar para MyExistingPlaybar:

{
    "target": "MyExistingPlaybar",
    "package": "com.example.myApp"
}

Agora, quando o desenvolvedor cria o projeto, o Card chama MyExistingPlaybar, em vez de PlayBar. Observe que MyExistingPlaybar precisa ter os mesmos parâmetros que PlayBar, embora possa haver algumas diferenças, conforme descrito em Diretivas adicionais abaixo.

Arquivo de mapeamento

Nos projetos do Android Studio, os arquivos de mapeamento são adicionados em ui-package-resources/mappings ao lado da pasta ui-packages. O Relay procura arquivos de mapeamento durante a criação.

Como mapear arquivos na visualização
do projeto

Gerar um arquivo de mapeamento

O Relay pode gerar um arquivo de mapeamento para qualquer pacote de IU importado. Siga estas etapas:

  1. Clique com o botão direito do mouse na pasta do pacote ou em qualquer arquivo dentro da pasta ui-package de destino. Selecione Gerar arquivo de mapeamento.

    Gerar affordance de
arquivo de mapeamento

  2. Configure as seguintes opções na caixa de diálogo:

    Caixa de diálogo para gerar arquivos de mapeamento

    • Local do arquivo:define o local do arquivo de mapeamento gerado.

    • Elemento combinável de destino:define o elemento combinável personalizado que é usado em vez do elemento combinável gerado. Você tem a opção de usar um combinável existente ou criar um novo na caixa de diálogo. A criação de um elemento combinável cria um elemento combinável com os mesmos parâmetros definidos no pacote de interface.

  3. Clique em Gerar arquivo de mapeamento. Um novo arquivo de mapeamento é criado na pasta ui-package-resources/mapping com as configurações especificadas.

Também é possível abrir a caixa de diálogo Generate mapping file na interface do módulo de pacote do Relay seguindo estas etapas:

  1. Clique em qualquer arquivo de um pacote de interface na pasta ui-package de destino.

  2. Se a janela da ferramenta de retransmissão não abrir automaticamente, clique no ícone de retransmissão para abrir a janela.

  3. Clique no botão Generate mapping file em Package Options.

    Gerar affordance de
arquivo de mapeamento

Nome do arquivo de mapeamento

O nome de um determinado arquivo de mapeamento precisa corresponder ao nome da pasta do pacote de IU para o componente substituído. Portanto, o play_bar.json mapeia o pacote da IU na pasta ui-packages/mappings para um componente de código.

Mapear o conteúdo do arquivo

O arquivo de mapeamento contém as seguintes propriedades:

  • target:obrigatório. O nome da função combinável personalizada. Por padrão, esse é o nome da função criada pelo código gerado.

    "target" : "CustomComposableName"
    
  • package: (obrigatório) nome do pacote em que o elemento combinável personalizado está inserido. Por padrão, é o pacote da função criada pelo código gerado.

    "package" : "com.example.podcastapp.ui.components"
    
  • generateImplementation: (opcional) verdadeiro ou falso. Se verdadeiro, uma implementação desse pacote de interface ainda será criada no arquivo de código gerado. Se for "false", a implementação não será criada. Por padrão, esse valor é verdadeiro.

    "generateImplementation" : true
    
  • generatePreviews: (opcional) verdadeiro ou falso. Se verdadeiro, uma visualização do componente personalizado mapeado é criada no arquivo de código gerado. Se for falso, nenhuma visualização será criada. Por padrão, esse valor é verdadeiro.

    "generatePreviews" : true
    

Variantes mapeadas

Se um componente do Figma tiver variantes, o elemento combinável gerado vai ter parâmetros de tipo enumerado que codificam a variante. Isso foi descrito no tutorial Como processar variantes de design. Se você quiser mapear um componente do Figma com variantes para um código existente, ele precisa ser mapeado para um elemento combinável que use os mesmos parâmetros que o elemento gerado. Por exemplo, para um componente do Figma chamado Chip com uma variante que tem a propriedade ChipType, a assinatura do elemento combinável gerada pelo Chip vai ficar assim:

@Composable
fun Chip(
    modifier: Modifier = Modifier,
    chipType: ChipType = ChipType.Red,
    chipText: String
) { ... }

Se você quiser que o componente do Chip do Figma seja mapeado para um elemento combinável MyChip existente, a assinatura de MyChip vai precisar ter a mesma assinatura do elemento combinável gerado (supondo que nenhuma diretiva adicional seja especificada). Conceitualmente, isso sugere que o componente de código existente é capaz de ter as mesmas variantes de design que o componente do Figma.

Outras diretivas

Por exemplo, se a função combinável que você quer segmentar tiver a seguinte assinatura:

@Composable
fun MyChip(
    modifier: Modifier = Modifier,
    chipType: ChipType = ChipType.Red,
    description: String  // instead of chipText
) { ... }

É possível adicionar um bloco fieldMappings ao arquivo de mapeamento que afeta o mapeamento dos parâmetros. Nesse caso, ele contém um mapeamento do parâmetro chipText no Chip para o parâmetro description em MyChip.

{
    "target": "MyChip",
    "package": "com.example.myApp",
    "fieldMappings": [
        {
            "type": "parameter",
            "source": "chipText",
            "target": "description"
        }
    ]
}

Os tipos para o bloco fieldMappings incluem:

  • parameter: mapeia um campo do pacote de interface para um parâmetro de código.
    • source: nome do parâmetro conforme especificado no pacote da interface.
    • target: nome do parâmetro conforme especificado no componente do código de destino.
  • lambda: mapeia um campo do pacote da IU para uma lambda de conteúdo.
    • source: nome do parâmetro conforme especificado no pacote da interface.
    • target: nome do parâmetro conforme especificado no componente do código de destino.
  • modifier: mapeia um campo de pacote da interface para um método modificador.

    • source: nome do parâmetro conforme especificado no pacote da interface.
    • method: método no objeto modificador que precisa ser invocado no código gerado.
    • parameter: nome do parâmetro no método modificador especificado.
    • library: o nome do pacote qualificado a ser importado para acessar o método modificador.
    • scope: um dos dois valores para indicar o escopo do modificador:
    • any: o modificador pode ser usado em qualquer escopo de receptor.
    • relay: o modificador precisa ser usado no escopo do receptor do objeto RelayContainer do Relay.