Imagens e Assets
Assets estáticos, require, buckets de densidade e carregamento com expo-asset.
Busque em todas as páginas da documentação
Assets estáticos, require, buckets de densidade e carregamento com expo-asset.
Cartão de receita de referência rápida - pronto para copiar e colar.
import { Image, View, StyleSheet } from "react-native";
import { Asset } from "expo-asset";
// Asset local - Metro escolhe o bucket de densidade correto em tempo de compilação
const logo = require("./assets/logo.png");
// Pré-carregar antes da primeira renderização (splash / inicialização do app)
async function preloadAssets() {
await Asset.loadAsync([
require("./assets/logo.png"),
require("./assets/hero@2x.png"),
]);
}
function Avatar({ uri }: { uri: string }) {
return (
<View style={styles.row}>
<Image source={logo} style={styles.logo} resizeMode="contain" />
<Image
source={{ uri }}
style={styles.avatar}
resizeMode="cover"
accessibilityLabel="Avatar do usuário"
/>
</View>
);
}
const styles = StyleSheet.create({
row: { flexDirection: "row", alignItems: "center", gap: 12 },
logo: { width: 120, height: 40 },
avatar: { width: 48, height: 48, borderRadius: 24 },
});Quando usar isso: Qualquer tela que exiba ícones, ilustrações, avatares ou arte de splash - assets locais via require(), URLs remotas via { uri } e expo-asset quando você precisar de assets prontos antes da navegação.
import { useEffect, useState } from "react";
import { ActivityIndicator, Image, StyleSheet, Text, View } from "react-native";
import { Asset } from "expo-asset";
import * as SplashScreen from "expo-splash-screen";
SplashScreen.preventAutoHideAsync();
const ASSETS = [
require("./assets/icon.png"),
require("./assets/onboarding-hero.png"),
];
type Props = { avatarUrl: string };
export default function ProfileHeader({ avatarUrl }: Props) {
const [ready, setReady] = useState(false);
useEffect(() => {
(async () => {
await Asset.loadAsync(ASSETS);
setReady(true);
await SplashScreen.hideAsync();
})();
}, []);
if (!ready) {
return (
<View style={styles.center}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.header}>
<Image source={ASSETS[0]} style={styles.icon} resizeMode="contain" />
<Image
source={{ uri: avatarUrl }}
defaultSource={require("./assets/avatar-placeholder.png")}
style={styles.avatar}
resizeMode="cover"
onError={() => console.warn("Falha ao carregar avatar")}
/>
<Text style={styles.title}>Seu perfil</Text>
</View>
);
}
const styles = StyleSheet.create({
center: { flex: 1, justifyContent: "center", alignItems: "center" },
header: { alignItems: "center", padding: 24, gap: 12 },
icon: { width: 64, height: 64 },
avatar: { width: 96, height: 96, borderRadius: 48 },
title: { fontSize: 20, fontWeight: "600" },
});O que isso demonstra:
require() estático e dimensões explícitas.Asset.loadAsync() antes de ocultar a tela de splash.{ uri } remotas com um placeholder defaultSource local.resizeMode para comportamento de dimensionamento e onError para falhas de carregamento de rede.require('./assets/logo.png') em tempo de compilação e emite um ID numérico de asset. Em tempo de execução, o Image do React Native resolve esse ID para o arquivo correto para a densidade de pixels do dispositivo.@Nx: logo.png (1x), logo@2x.png, logo@3x.png. O Metro escolhe a correspondência mais próxima; você só precisa usar require() com o nome base do arquivo.expo-asset envolve o mesmo registro de assets, mas adiciona helpers de download/cache para URLs remotas e uma API de pré-carregamento baseada em promessas usada na inicialização do app.@3x podem aumentar o uso de RAM - dimensione os assets para suas dimensões de exibição, não para a resolução nativa do dispositivo.| Arquivo | Densidade do Dispositivo | Quando usado |
|---|---|---|
icon.png | ~1x (mdpi) | Android de baixa densidade, fallback |
icon@2x.png | ~2x (xhdpi) | A maioria dos iPhones, muitos telefones Android |
icon@3x.png | ~3x (xxhdpi) | iPhone Pro Max, Android de ponta |
Coloque todas as variantes no mesmo diretório. Referencie apenas o nome base no código:
// Metro resolve icon@2x.png / icon@3x.png automaticamente
<Image source={require("./assets/icon.png")} style={{ width: 32, height: 32 }} />resizeMode| Modo | Comportamento |
|---|---|
cover | Preenche o quadro; corta o excesso (avatares, banners principais) |
contain | Cabe dentro do quadro; adiciona barras laterais se necessário (logos) |
stretch | Distorce para preencher (raramente desejável) |
center | Sem escala; centraliza no tamanho natural |
repeat | Repete (apenas iOS para Image; use ImageBackground no Android) |
expo-assetimport { Asset } from "expo-asset";
import { useFonts } from "expo-font";
export async function loadAppResources() {
const imageAssets = Asset.loadAsync([
require("./assets/splash-art.png"),
require("./assets/tab-home.png"),
]);
const fontAssets = useFonts({
Inter: require("./assets/fonts/Inter-Regular.ttf"),
});
await Promise.all([imageAssets, fontAssets]);
}Chame isso no seu layout raiz ou portão de splash antes de renderizar telas que dependem dos assets.
import type { ImageSourcePropType, ImageStyle, StyleProp } from "react-native";
// require() retorna um número (ID do módulo de asset) no RN
const localSource: ImageSourcePropType = require("./assets/logo.png");
// Fonte remota é um objeto
const remoteSource: ImageSourcePropType = {
uri: "https://cdn.example.com/avatar.jpg",
width: 200,
height: 200,
cache: "force-cache", // opcional: 'default' | 'reload' | 'force-cache' | 'only-if-cached'
};
type AvatarProps = {
source: ImageSourcePropType;
style?: StyleProp<ImageStyle>;
};width/height (ou aspectRatio), Image renderiza em 0×0 e parece invisível. Correção: Sempre defina o layout explícito para fontes { uri }.require() dinâmico de caminhos - require('./assets/' + name + '.png') falha em tempo de compilação porque o Metro precisa analisar estaticamente as importações. Correção: Use um mapa de consulta de require() estáticos ou busque URLs remotas.@3x em UI pequena - Um PNG de 3000×3000 exibido em um avatar de 48×48 desperdiça tempo de decodificação e RAM. Correção: Exporte no tamanho de exibição × proporção de pixels, ou use WebP com compressão..svg em require() não funciona "out of the box". Correção: Use react-native-svg com SvgUri / SVG inline, ou exporte para PNG/WebP.Image core não anima GIFs no Android. Correção: Use expo-image (suporta formatos animados) ou uma biblioteca de animação dedicada.?t=${Date.now()}) anula o cache HTTP e causa cintilação. Correção: URIs estáveis; chame Image.prefetch(uri) ou as APIs de cache do expo-image quando precisar de uma atualização.await Asset.loadAsync(...) e depois SplashScreen.hideAsync().| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
Image Core (react-native) | Imagens locais/remotas simples, dependências mínimas | Você precisa de cache em disco, blurhash, transições ou suporte a GIF |
expo-image | Apps com muitas imagens em produção, listas com avatares, placeholders | Você precisa de zero módulos Expo em um app RN bare sem prebuild |
ImageBackground | Fundos de tela inteira com filhos sobrepostos | Você só precisa de uma imagem simples (use Image - mais leve) |
expo-file-system + URI local | Fotos geradas pelo usuário salvas em disco | Assets empacotados estáticos (use require()) |
react-native-fast-image (comunidade) | RN bare com necessidades agressivas de cache | Fluxo de trabalho gerenciado do Expo onde expo-image já cobre o cache |
O bundler do Metro escaneia sua fonte em tempo de compilação e inclui apenas os assets que ele consegue resolver estaticamente. A construção dinâmica de caminhos não pode ser analisada, então o bundler gera um erro. Use um mapa constante:
const icons = {
home: require("./assets/home.png"),
settings: require("./assets/settings.png"),
} as const;Nomeie os arquivos com sufixos @2x e @3x ao lado do arquivo base. O Metro seleciona a melhor correspondência para o PixelRatio do dispositivo em tempo de execução. Você sempre usa require() com o nome base do arquivo - nunca a variante com sufixo diretamente.
Sim. O React Native não infere o tamanho do layout dos metadados da imagem, nem para fontes locais nem remotas. Defina width/height em StyleSheet ou use aspectRatio com uma dimensão.
defaultSource (focado em iOS; suporte limitado no Android) exibe uma imagem empacotada enquanto o { uri } remoto carrega. Para uma experiência de placeholder multiplataforma, prefira expo-image com as props placeholder / blurhash ou renderize um View esqueleto até que onLoad seja acionado.
import { Image } from "react-native";
import { Asset } from "expo-asset";
// Pré-busca da Imagem Core (apenas remota)
await Image.prefetch("https://cdn.example.com/hero.jpg");
// expo-asset (IDs de require locais e URLs remotas)
await Asset.loadAsync([require("./assets/card-bg.png")]);Sim. iOS e Android nas builds atuais do Expo SDK decodificam WebP. WebP geralmente resulta em bundles menores que PNG para fotos e ilustrações. Mantenha PNG para imagens que requerem transparência sem perdas em tamanhos pequenos.
Referências instáveis ao objeto source={{ uri }} podem acionar re-buscas. Memorize o objeto de fonte ou passe uma string de URI estável através da prop source do expo-image. Evite parâmetros de consulta de quebra de cache, a menos que seja intencional.
Use useFonts do expo-font ou Font.loadAsync na mesma rotina de bootstrap que Asset.loadAsync. Ambos devem ser concluídos antes de você ocultar a tela de splash e renderizar UI com muito texto.
cover preenche o quadro e corta - bom para círculos de avatar uniformes. contain encaixa a imagem inteira dentro do quadro - bom para logos com proporções variadas onde o corte é inaceitável.
const [error, setError] = useState(false);
<Image
source={error ? require("./assets/fallback.png") : { uri }}
onError={() => setError(true)}
style={{ width: 48, height: 48 }}
/>Projetos Expo convencionalmente usam uma pasta assets/ de nível superior para ícones de app e imagens de splash (referenciados em app.json), e pastas ./assets/ co-localizadas ao lado das telas para imagens específicas de recursos. Ambos funcionam - a consistência dentro de um recurso é mais importante que o nome exato da pasta.
Ele registra assets no sistema de assets do Expo, baixa URLs remotas para um diretório de cache quando necessário e garante que os recursos nativos estejam disponíveis antes que seu JS os referencie. Para assets require() empacotados, ele garante principalmente a conclusão do pré-carregamento através de promessas.
Imagens decorativas devem definir accessible={false} para que os leitores de tela as ignorem. Imagens significativas (avatares, gráficos) precisam de accessibilityLabel descrevendo o conteúdo. Ícones empacotados puramente decorativos geralmente não precisam de rótulo.
React Native não serve uma pasta public/ como a web. Todas as imagens empacotadas devem ser importadas com require() (ou pré-carregadas via expo-asset). Imagens remotas usam URLs HTTPS.
ImageVersões do Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026