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 da 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. O desenvolvedor adiciona um arquivo de mapeamento chamado play_bar.json que mapeia o pacote de interface 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 busca arquivos de mapeamento durante o build.

Arquivo de mapeamento na visualização
do projeto

Gerar um arquivo de mapeamento

O Relay pode gerar um arquivo de mapeamento para qualquer pacote de interface 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 do 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 personalizado que será usado no lugar do elemento gerado. Você tem a opção de usar um elemento combinável existente ou criar um novo na caixa de diálogo. A criação de um novo elemento combinável cria outro com os mesmos parâmetros definidos no pacote de interface.

    • Arquivo gerado:define as opções generateImplementation e generatePreview no arquivo de mapeamento. Consulte Como mapear o conteúdo do arquivo abaixo para mais detalhes.
  3. Clique em Gerar arquivo de mapeamento. Um novo arquivo de mapeamento é criado dentro da pasta ui-package-resources/mapping com as configurações especificadas.

Você também pode abrir a caixa de diálogo Generate mapping file na interface do módulo do pacote do Relay seguindo estas etapas:

  1. Clique em qualquer arquivo para um pacote de interface dentro da pasta ui-package de destino.

  2. Se a janela de ferramentas do Relay não abrir automaticamente, clique no ícone do Relay.

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

    Gerar affordance do 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.

Mapeamento de 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á localizado. Por padrão, esse é o pacote da função criado 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, isso é verdadeiro.

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

    "generatePreviews" : true
    

Variantes mapeadas

Se um componente do Figma tiver variantes, o elemento combinável gerado vai conter parâmetros de tipo enumerado que codificam a variante, conforme 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 do elemento gerado. Por exemplo, para um componente do Figma chamado Chip com uma variante que tem a propriedade da assinatura combinável gerada por ChipType, Chip, tem esta aparência:

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

Se você quiser que o componente Chip do Figma seja mapeado para um MyChip combinável atual, a assinatura de MyChip vai precisar ter a mesma assinatura do elemento combinável gerado, supondo que nenhuma outras diretivas sejam especificadas. 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 "Pacote de interface" para um parâmetro de código.
    • source: nome do parâmetro conforme especificado no pacote de interface.
    • target: nome do parâmetro conforme especificado no componente do código de destino.
  • lambda: mapeia um campo de pacote de interface para uma lambda de conteúdo.
    • source: nome do parâmetro conforme especificado no pacote de interface.
    • target: nome do parâmetro conforme especificado no componente do código de destino.
  • modifier: mapeia um campo de pacote de interface para um método modificador.

    • source: nome do parâmetro conforme especificado no pacote de 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.