İçeriğe geç / Skip to content / Zum Inhalt

Flutter: Bilder einbinden – Assets und Image.asset

Ahmet Balaman

Zuletzt aktualisiert:

7 Min. Lesezeit

FlutterAssetsImagepubspec.yamlResources
Flutter: Bilder einbinden – Assets und Image.asset

Um Bilder in Ihr Flutter-Projekt aufzunehmen, legen Sie sie zunächst in einem Ordner ab und definieren sie anschließend in der Datei pubspec.yaml als Assets. Das klingt einfach, doch eine der häufigsten „Warum funktioniert das nicht?“-Fragen im Unterricht geht auf kleine Fehler in genau diesen beiden Schritten zurück. Dieser Beitrag behandelt die Schritte, die Unterstützung verschiedener Auflösungen, SVG- und Netzwerkbilder und wie Sie diese Fehler aufspüren.

Schritt 1: Bilderordner anlegen

Legen Sie im Wurzelverzeichnis Ihres Flutter-Projekts (auf derselben Ebene wie der Ordner lib) einen Bilderordner an. Sehen Sie die Projektstruktur zum ersten Mal, erklärt der Leitfaden zu den ersten Schritten mit Flutter, wozu die einzelnen Ordner dienen:

my_flutter_app/
  ├── lib/
  ├── assets/
  │   └── images/
  │       ├── logo.png
  │       ├── profile.jpg
  │       └── banner.png
  ├── pubspec.yaml
  └── ...

Hinweis: Üblich sind die Ordnernamen assets, images oder assets/images. Sie können einen beliebigen Namen wählen, im Team erwartet aber jeder die Struktur assets/images/.

Schritt 2: pubspec.yaml konfigurieren

Öffnen Sie pubspec.yaml und ergänzen Sie unter dem Abschnitt flutter: die Asset-Definition; die vollständige Syntax dieses Abschnitts beschreibt Flutters Leitfaden „Adding assets and images“:

Ein einzelnes Bild hinzufügen

flutter:
  uses-material-design: true

  assets:
    - assets/images/logo.png

Einen ganzen Ordner hinzufügen

flutter:
  uses-material-design: true

  assets:
    - assets/images/

Endet der Ordnerpfad mit /, werden alle Dateien in diesem Ordner als Assets aufgenommen. Unterordner sind in dieser Angabe nicht enthalten; die einzige Ausnahme sind Auflösungsordner wie 2.0x und 3.0x, die wir weiter unten ansehen.

Mit Unterordnern

flutter:
  assets:
    - assets/images/
    - assets/images/icons/
    - assets/images/backgrounds/

Beispiel für pubspec.yaml

name: my_app
description: My Flutter application.

environment:
  sdk: ^3.9.0

dependencies:
  flutter:
    sdk: flutter

flutter:
  uses-material-design: true

  assets:
    - assets/images/
    - assets/icons/

Die Zeile sdk unter environment müssen Sie nicht von Hand schreiben; flutter create füllt sie anhand der installierten Dart-Version aus. Das ^3.9.0 hier entspricht der Dart-Version, die mit Flutter 3.35 ausgeliefert wird.

Schritt 3: Bilder verwenden

Das Widget Image.asset

Image.asset ist einer der Konstruktoren, die in der API-Dokumentation des Image-Widgets aufgeführt sind, und wie die anderen ein ganz normales Widget; Sie können es im Widget-Baum in eine Row, Column oder einen Container setzen:

Image.asset('assets/images/logo.png')

Größe festlegen

Image.asset(
  'assets/images/logo.png',
  width: 200,
  height: 200,
)

Einpassen mit BoxFit

Image.asset(
  'assets/images/banner.png',
  width: double.infinity,
  height: 200,
  fit: BoxFit.cover, // Fläche ausfüllen
)

BoxFit-Werte:

  • cover: Füllt die Fläche vollständig und schneidet Überstehendes ab
  • contain: Das ganze Bild ist sichtbar; es kann Leerraum bleiben
  • fill: Füllt die Fläche; das Seitenverhältnis kann verzerrt werden
  • fitWidth: Passt an die Breite an
  • fitHeight: Passt an die Höhe an
  • none: Zeigt das Bild in Originalgröße
  • scaleDown: Verhält sich wie contain, vergrößert das Bild aber nie

Praktische Beispiele

Beispiel 1: Ein Logo anzeigen

class LogoWidget extends StatelessWidget {
  const LogoWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Image.asset(
        'assets/images/logo.png',
        width: 150,
        height: 150,
      ),
    );
  }
}

Beispiel 2: Profilbild

const CircleAvatar(
  radius: 50,
  backgroundImage: AssetImage('assets/images/profile.jpg'),
)

CircleAvatar erwartet einen ImageProvider und kein Widget; deshalb steht hier AssetImage statt Image.asset.

Beispiel 3: Bannerbild

SizedBox(
  width: double.infinity,
  height: 200,
  child: Image.asset(
    'assets/images/banner.png',
    fit: BoxFit.cover,
  ),
)

Brauchen Sie nur eine Größe, ist SizedBox statt Container leichter und macht die Absicht klarer.

Beispiel 4: Symbolbild

Row(
  children: [
    Image.asset(
      'assets/images/icons/star.png',
      width: 24,
      height: 24,
    ),
    const SizedBox(width: 8),
    const Text('Meine Favoriten'),
  ],
)

Die SizedBox, die den Abstand zwischen Symbol und Text schafft, ist für solche kleinen Zeilen das praktischste Werkzeug.

Beispiel 5: Hintergrundbild

Container(
  decoration: const BoxDecoration(
    image: DecorationImage(
      image: AssetImage('assets/images/background.jpg'),
      fit: BoxFit.cover,
    ),
  ),
  child: const Center(
    child: Text(
      'Willkommen',
      style: TextStyle(
        color: Colors.white,
        fontSize: 32,
        fontWeight: FontWeight.bold,
      ),
    ),
  ),
)

Müssen Sie mehrere Elemente frei über dem Bild platzieren, sind Stack und Positioned der flexiblere Weg.

Bilder für verschiedene Bildschirmdichten

Für unterschiedliche Bildschirmdichten können Sie Bilder in verschiedenen Auflösungen bereitstellen:

logo.png, 2.0x/logo.png und 3.0x/logo.png werden anhand der devicePixelRatio zugeordnet

Ordnerstruktur

assets/
  └── images/
      ├── logo.png          (1x, Hauptdatei)
      ├── 1.5x/
      │   └── logo.png      (1.5x)
      ├── 2.0x/
      │   └── logo.png      (2x)
      ├── 3.0x/
      │   └── logo.png      (3x)
      └── 4.0x/
          └── logo.png      (4x)

Die Datei trägt in jedem Ordner denselben Namen; nur die Pixelmaße unterscheiden sich. Ist logo.png zum Beispiel 100x100 Pixel groß, sollte 2.0x/logo.png 200x200 und 3.0x/logo.png 300x300 Pixel haben.

pubspec.yaml

flutter:
  assets:
    - assets/images/logo.png

Hinweis: Flutter nimmt die Varianten in den Ordnern 1.5x, 2.0x, 3.0x und 4.0x automatisch zusammen mit der Hauptdatei auf; Sie müssen sie nicht einzeln angeben.

Verwendung

Image.asset('assets/images/logo.png')

Flutter wählt automatisch die Variante, die der devicePixelRatio des Geräts am nächsten liegt. Im Code schreiben Sie immer den Pfad der Hauptdatei. Soll dasselbe Bild zwischen zwei Seiten wachsend hinüberfliegen, genügt es, Image.asset in einen Hero zu packen; Details finden Sie im Beitrag über Hero-Animationen.

Tipps zur Benennung von Bildern

Schreiben Sie die Auflösung nicht in den Dateinamen; Namen wie logo_low.png und logo_high.png umgehen Flutters automatische Auswahl und zwingen Sie, im Code zu entscheiden, wann welche Datei verwendet wird. Nutzen Sie für die Auflösung stattdessen die Ordner 2.0x und 3.0x von oben.

Diese Regeln für Dateinamen erleichtern die Arbeit:

onboarding_step1.png   // Kleinbuchstaben, Wörter mit Unterstrich getrennt
icon_cart_24.png       // bei Symbolen in mehreren Größen die Größe ans Ende
bg_login.jpg           // Präfix nach Art (bg_, icon_, img_)

Vermeiden Sie Leerzeichen, Umlaute und Großbuchstaben. Manche Dateisysteme unterscheiden Groß- und Kleinschreibung; ein Logo.PNG, das auf Ihrem Rechner funktioniert, wird in einer anderen Umgebung womöglich nicht gefunden.

Pfade an einer Stelle sammeln

Wiederholen sich Bildpfade als Strings überall im Code, fällt ein Tippfehler erst zur Laufzeit auf. Die Pfade als Konstanten an einer Stelle zu halten, senkt dieses Risiko:

abstract final class AppImages {
  static const logo = 'assets/images/logo.png';
  static const profile = 'assets/images/profile.jpg';
  static const banner = 'assets/images/banner.png';
}

// Verwendung
Image.asset(AppImages.logo)

abstract final class ist eine Schreibweise aus Dart 3: Die Klasse lässt sich weder instanziieren noch von außen erweitern, es ist also klar, dass sie nur Konstanten gruppiert.

Lade- und Fehlerzustände

Sanftes Einblenden (frameBuilder)

Image.asset(
  'assets/images/logo.png',
  frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
    if (wasSynchronouslyLoaded) {
      return child;
    }
    return AnimatedOpacity(
      opacity: frame == null ? 0 : 1,
      duration: const Duration(milliseconds: 300),
      curve: Curves.easeOut,
      child: child,
    );
  },
)

frame ist null, bis das erste Frame dekodiert ist; dieses Beispiel hält das Bild bis dahin unsichtbar und blendet es danach sanft ein.

Fehlerfall

Image.asset(
  'assets/images/logo.png',
  errorBuilder: (context, error, stackTrace) {
    return Container(
      color: Colors.grey.shade300,
      child: const Center(
        child: Icon(Icons.error, color: Colors.red),
      ),
    );
  },
)

errorBuilder zeigt statt des roten Fehlerbildschirms ein Widget Ihrer Wahl, wenn die Datei nicht gefunden oder nicht dekodiert werden kann. Bei Assets deutet das meist auf einen Konfigurationsfehler hin; prüfen Sie vor dem Verstecken des Fehlers den Abschnitt „Häufige Fehler“ weiter unten.

Image.network und Image.asset

Image.asset (lokales Bild)

Image.asset('assets/images/logo.png')
  • Ist im App-Paket enthalten
  • Braucht keine Internetverbindung
  • Lädt schnell
  • Vergrößert die App

Image.network (Bild aus dem Internet)

Image.network('https://example.com/image.png')
  • Wird zur Laufzeit aus dem Internet geladen
  • Braucht eine Internetverbindung
  • Kann je nach Verbindung verzögert erscheinen
  • Vergrößert die App nicht
  • Flutter hält heruntergeladene Bilder nur im Speicher (ImageCache); nach dem Schließen der App werden sie erneut geladen. Für einen Cache auf der Festplatte verwenden Sie das Paket cached_network_image weiter unten.

Sanftes Laden mit FadeInImage

Um einen lokalen Platzhalter zu zeigen, während ein Bild aus dem Netz lädt:

FadeInImage.assetNetwork(
  placeholder: 'assets/images/placeholder.png',
  image: 'https://example.com/image.png',
  fit: BoxFit.cover,
)

Dasselbe erreichen Sie mit ImageProviders:

FadeInImage(
  placeholder: const AssetImage('assets/images/placeholder.png'),
  image: const NetworkImage('https://example.com/image.png'),
  fit: BoxFit.cover,
)

Da der Platzhalter ein Asset ist, erscheint er sofort; trifft das Netzwerkbild ein, ersetzt es den Platzhalter mit einem weichen Übergang.

SVG-Bilder

Flutters Image-Widget kann kein SVG zeichnen; dafür brauchen Sie das Paket flutter_svg. Fügen Sie es im Terminal hinzu:

flutter pub add flutter_svg

Der Befehl trägt die aktuelle Version des Pakets selbst in den Abschnitt dependencies von pubspec.yaml ein.

Verwendung

import 'package:flutter_svg/flutter_svg.dart';

SvgPicture.asset(
  'assets/images/logo.svg',
  width: 100,
  height: 100,
  semanticsLabel: 'App-Logo',
)

Auch die SVG-Datei muss in pubspec.yaml als Asset definiert sein. Um die Farbe zu ändern, verwenden Sie colorFilter: const ColorFilter.mode(Colors.orange, BlendMode.srcIn).

Cached Network Image

Das Paket cached_network_image speichert Netzwerkbilder auf der Festplatte zwischen:

flutter pub add cached_network_image

Verwendung

import 'package:cached_network_image/cached_network_image.dart';

CachedNetworkImage(
  imageUrl: 'https://example.com/image.png',
  placeholder: (context, url) => const CircularProgressIndicator(),
  errorWidget: (context, url, error) => const Icon(Icons.error),
)

Ist ein Bild einmal heruntergeladen, wird es auf dem Gerät gespeichert und bei späteren Starts ohne Netzzugriff angezeigt.

Häufige Fehler

1. Einrückung in pubspec.yaml

# ❌ FALSCH
flutter:
uses-material-design: true
assets:
  - assets/images/

# ✅ RICHTIG
flutter:
  uses-material-design: true
  assets:
    - assets/images/

In YAML hat die Einrückung Bedeutung. Die Zeile assets: muss unter flutter: um zwei Leerzeichen eingerückt sein; verwenden Sie keine Tabulatoren.

2. Falscher Pfad

// ❌ FALSCH
Image.asset('images/logo.png')  // 'assets/' fehlt

// ✅ RICHTIG
Image.asset('assets/images/logo.png')

Der Pfad im Code muss genau so beginnen wie der Pfad in pubspec.yaml.

3. Groß- und Kleinschreibung im Dateinamen

// Heißt die Datei logo.PNG:
Image.asset('assets/images/logo.png') // Wird in manchen Umgebungen nicht gefunden

Ihr Dateisystem kann Groß- und Kleinschreibung unterscheiden; gleichen Sie den Pfad im Code Buchstabe für Buchstabe mit dem Dateinamen ab.

4. Einen Unterordner nicht angeben

Die Angabe assets/images/ umfasst nicht die Dateien in assets/images/icons/. Fügen Sie jeden Unterordner als eigene Zeile hinzu.

5. Das Hot-Reload-Problem

Bei Änderungen an pubspec.yaml:

  • Hot Reload reicht nicht
  • Führen Sie einen Hot Restart aus (die 🔄-Schaltfläche)
  • Sehen Sie weiterhin „Unable to load asset“, beenden Sie die App vollständig und starten Sie sie neu

Zusammenfassung

Bilder in Flutter hinzufügen:

  1. Ordner anlegen: assets/images/
  2. Bilder hinzufügen: PNG, JPG, WebP; für SVG zusätzlich flutter_svg
  3. In pubspec.yaml definieren:
    flutter:
      assets:
        - assets/images/
  4. Hot Restart ausführen
  5. Verwenden:
    Image.asset('assets/images/logo.png')

Empfehlungen:

  • Für mehrere Auflösungen die Ordner 2.0x und 3.0x anlegen
  • Aussagekräftige Dateinamen in Kleinbuchstaben verwenden
  • Bildpfade in einer einzigen Konstantenklasse sammeln
  • Für SVG-Bilder flutter_svg nutzen
  • Netzwerkbilder mit cached_network_image auf der Festplatte zwischenspeichern

Tipps zur Performance:

  • Keine Bilder einbinden, die viel größer sind als ihre Anzeigegröße
  • WebP liefert meist kleinere Dateien als PNG und JPG
  • Zeigen Sie ein großes Bild auf kleiner Fläche, geben Sie cacheWidth oder cacheHeight an, damit es im Speicher kleiner dekodiert wird: Image.asset('assets/images/banner.png', cacheWidth: 600)
  • Für lange Bilderlisten ListView.builder verwenden; es werden nur die sichtbaren Elemente aufgebaut
  • Ungenutzte Bilder aus dem Projekt löschen

Bilder sind ein wichtiger Teil der visuellen Identität einer Flutter-App. In der richtigen Größe, an der richtigen Stelle und im richtigen Format lassen sie Ihre App schnell und sorgfältig gemacht wirken. Das App-Symbol selbst ist dagegen kein Asset, sondern eine Plattformressource; darum geht es gesondert im Beitrag zum Erstellen eines App-Icons.

Häufig gestellte Fragen

Ich habe es in pubspec.yaml eingetragen, bekomme aber „Unable to load asset“ – warum?

Drei Verdächtige gibt es: Die Zeile assets: muss unter flutter: um zwei Leerzeichen eingerückt sein, der Pfad im Code muss vollständig sein wie assets/images/logo.png, und nach einer Änderung an pubspec ist ein Hot Restart nötig. Denken Sie auch daran, dass Unterordner einzeln aufgeführt werden müssen.

Kann ich Bilder statt in assets im Ordner lib ablegen?

Technisch ja, und Sie müssen sie trotzdem in pubspec.yaml deklarieren. Aber lib ist für Code gedacht; Bilder unter assets/ im Projektwurzelverzeichnis zu halten, sorgt für Ordnung und entspricht der Struktur, die Ihre Teamkollegen erwarten.

Die Bilder machen meine App zu groß – was tun?

Verwenden Sie WebP statt PNG, verkleinern Sie Bilder auf die Größe, in der sie tatsächlich angezeigt werden, und löschen Sie ungenutzte Dateien. Große, selten angezeigte Bilder über cached_network_image aus dem Netz zu laden, statt sie einzubetten, senkt die Größe ebenfalls deutlich.

Kommentare