Widget — vad är det, typer och komposition i Flutter

Författare: IT Sectr Publicerad: 2026-06-30 Lästid: 10 min

Widget — är det centrala begreppet i Flutter-ramverket, som beskriver konfigurationen av ett användargränssnittselement. Varje visuell komponent, från en knapp till en komplex animation, är en Widget. Till skillnad från andra ramverk, där UI beskrivs i separata XML-filer eller ritas imperativt, bygger Flutter gränssnittet genom Widget-komposition — sammanslagning av små odelbara element i ett hierarkiskt träd. Enligt Flutter Documentation (2025) innehåller Flutter SDK-biblioteket över 260 inbyggda Widgets som täcker Material Design, Cupertino och anpassade stilar.

Huvudpunkter

  • Widget — den grundläggande byggstenen för UI i Flutter, som beskriver konfigurationen av ett element.
  • Komposition — UI byggs genom att Widgets kapslas in i varandra, inte genom arv.
  • StatelessWidget — widget som inte ändras efter rendering (text, ikon, mellanrum).
  • StatefulWidget — widget med föränderligt tillstånd (formulär, animationer, listor med data).
  • Element tree — Flutter underhåller tre träd: Widget, Element och RenderObject.

Vad är Widget i Flutter

Widget i Flutter är en oföränderlig (immutable) beskrivning av en del av användargränssnittet. Varje Widget innehåller konfigurationsegenskaper: storlek, färg, position, text, händelsehanterare och underordnade Widgets. Widgets i sig själva renderas inte direkt — de är recept (blueprints) som Flutter Engine använder för att skapa ett RenderObject — ett verkligt grafiskt objekt på skärmen.

Flutters filosofi säger: “Everything is a Widget”. Detta innebär att inte bara synliga element (Text, Image, Button) är Widgets, utan även strukturella block (Padding, Center, Column, Stack), beteendeblock (GestureDetector, AnimatedBuilder) och till och med själva applikationen (MaterialApp, CupertinoApp). Detta tillvägagångssätt säkerställer enhetlighet: vilket skärmelement som helst kan kombineras med vilket annat som helst genom enkel inkapsling.

Enligt data från Google I/O 2024 — Flutter Widgets Deep Dive innehåller en genomsnittlig Flutter-applikation mellan 200 och 1500 Widgets vid en given tidpunkt. Trots detta antal upprätthåller Flutter 60 FPS även på budgetenheter tack vare optimeringar på C++-nivå i Skia/Impeller-motorn. Widgets är lätta objekt (40–80 byte var), så att skapa dem är ingen prestandaflaskhals.

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text('Hej, Flutter!'),
        ),
      ),
    );
  }
}

Flutters tre träd: Widget, Element och RenderObject

För att förstå hur Widget fungerar måste du känna till Flutters arkitektur som består av tre sammankopplade träd. Det första — Widget tree — beskriver UI-konfigurationen. Det är ett lätt träd som kan byggas om helt vid varje bildruta (garbage collector tar bort gamla Widgets och skapar nya). Widgets är oföränderliga (immutable): om textfärgen ändras skapas en ny Text Widget med den nya färgen, den gamla kasseras.

Det andra trädet — Element tree — är länken mellan Widget och RenderObject. Element innehåller en referens till Widget (konfiguration) och till RenderObject (rendering). När Widget ändras jämför Flutter den nya Widget med det gamla Elementet och beslutar: uppdatera den befintliga RenderObject (om Widget är av samma typ) eller skapa en ny (om Widget-typen har ändrats). Denna process kallas Reconciliation och är motsvarigheten till React Virtual DOM.

Det tredje trädet — RenderObject tree — ansvarar för den faktiska renderingen på skärmen. RenderObject innehåller konkreta dimensioner, positioner och paint-metoder. Flutter Engine (C++ Skia eller Impeller) går igenom RenderObject tree och renderar varje nod. RenderObject tree är det tyngsta trädet, därför minimerar Flutter dess förändringar genom att återanvända RenderObject vid byte av Widget av samma typ.

TrädSyfteImmutable?Livscykel
WidgetUI-konfiguration (recept)JaÅterskapas vid varje build
ElementAnslutning Widget ↔ RenderObjectNejFinns så länge widgeten är i trädet
RenderObjectRendering och layoutNejTung, återanvänds om möjligt

StatelessWidget vs StatefulWidget

Flutter delar in Widgets i två grundläggande typer: StatelessWidget och StatefulWidget. StatelessWidget är en widget som inte innehåller föränderligt tillstånd. Utseendet på StatelessWidget bestäms helt av dess konstruktor och kan inte ändras efter rendering. Exempel: Text, Icon, Divider, Padding. Alla egenskaper för StatelessWidget deklareras som final i konstruktorn och är skrivskyddade.

StatefulWidget är en widget med föränderligt tillstånd. Den består av två klasser: själva Widget (oföränderlig konfiguration, precis som StatelessWidget) och State (föränderligt tillstånd). Att separera Widget från State är ett viktigt arkitekturbeslut i Flutter. Widget återskapas vid varje build, men State-objektet förblir levande under widgetens hela livscykel i trädet och bevarar sitt tillstånd.

När setState() anropas markerar Flutter State som “smutsigt” och vid nästa bildruta anropar den build()-metoden för att återbygga underträdet. Viktigt: setState() återskapar inte själva Widget — den utlöser bara build()-anropet i det befintliga State. Detta innebär att StatefulWidget kan uppdatera UI utan att förlora tillståndet för underordnade Widgets, så länge nycklarna (Key) för underordnade element förblir stabila.

dart
// StatelessWidget — utseende ändras aldrig
class GreetingWidget extends StatelessWidget {
  const GreetingWidget({super.key, required this.name});
  final String name;

  @override
  Widget build(BuildContext context) {
    return Text('Hej, $name');
  }
}

// StatefulWidget — räknare med föränderligt tillstånd
class CounterWidget extends StatefulWidget {
  const CounterWidget({super.key});

  @override
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Räkning: $_count'),
        ElevatedButton(
          onPressed: () => setState(() => _count++),
          child: const Text('Öka'),
        ),
      ],
    );
  }
}

Typer av Widget: layout, painting, interactive

Alla Widgets i Flutter kan delas in i tre huvudkategorier baserat på funktionellt syfte. Layout Widget — ansvarar för placering av underordnade element på skärmen. Row och Column placerar barnen i en rad, Stack lägger en ovanpå en annan, Expanded och Flexible fördelar tillgängligt utrymme. Layout Widgets har ingen egen visuell representation — de hanterar position och storlek på underordnade widgets.

Painting Widget — ansvarar för visuellt utseende. Container kombinerar dekorationer (färg, gradient, skugga, kant) med layout-egenskaper. Padding lägger till mellanrum, DecoratedBox ritar bakgrund, Transform tillämpar transformationer (rotation, skalning). Painting Widgets är byggstenarna för visuell stil och används ofta tillsammans med layout Widgets för att uppnå önskat utseende.

Interactive Widget — bearbetar användarinmatning. GestureDetector upptäcker gester (tap, swipe, pinch), InkWell lägger till Material-rippeleffekt, TextField tar emot textinmatning, Slider och Switch tillhandahåller standardkontroller. Interactive Widgets höjer händelser via callback-funktioner som skickas till konstruktorn eller hanteras via tillståndsleverantörer.

KategoriExempel på WidgetSyfte
LayoutRow, Column, Stack, Expanded, Flexible, AlignPlacering och storlek på underordnade element
PaintingContainer, Padding, DecoratedBox, RotatedBoxFärg, bakgrund, kanter, skuggor, transformationer
InteractiveGestureDetector, InkWell, TextField, SliderBearbetning av beröring, inmatning, gester
PlatformMaterialApp, CupertinoApp, Theme, MediaQueryIntegration med plattform, teman, anpassning
AsyncFutureBuilder, StreamBuilder, ValueListenableBuilderReaktiv uppdatering från asynkron data

Enligt data från Flutter Widget of the Week (Google, 2025) använder Flutter-communityt aktivt kombinationen av layout + painting + interactive Widgets för att bygga nästan vilket gränssnitt som helst. Till exempel en knapp: InkWell (interactive) + Container (painting) + Text (static) + Padding (layout). Sådan modularitet möjliggör återanvändning av standardblock i olika sammanhang utan kodduplicering.

Widget-komposition och BuildContext

Widget-komposition är processen att bygga UI genom att kapsla in Widgets i varandra. Till skillnad från klassiskt arv (extends), där den underordnade klassen ärver beteendet från föräldern, använder Flutter aggregering: varje Widget innehåller andra Widgets via parametern child (för en) eller children (för flera). Detta tillvägagångssätt ger större flexibilitet och återanvändbarhet.

BuildContext är det näst viktigaste konceptet efter Widget. BuildContext är en deskriptor för Widgets position i elementträdet. Genom BuildContext kan Widget komma åt förfäders Widgets (Theme.of(context), MediaQuery.of(context), Navigator.of(context)). BuildContext skickas till build()-metoden och används för interaktion med föräldra- och underordnade element. Varje Widget har exakt en BuildContext som unikt identifierar dess position i trädet.

Enligt Flutter Architectural Overview (Google, 2025) är BuildContext grunden för InheritedWidget — en mekanism som tillåter data att skickas nedåt i trädet utan explicit överföring via konstruktorer. Theme, MediaQuery, Navigator och Provider använder InheritedWidget under huven. Varje djupt kapslad Widget kan komma åt förfäders data via BuildContext.dependOnInheritedWidgetOfExactType, vilket gör BuildContext till nyckeln till Flutters reaktiva arkitektur.

dart
// Widget-komposition via inkapsling
Scaffold(
  appBar: AppBar(title: const Text('Min App')),
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Text('Välkommen till Flutter',
          style: TextStyle(fontSize: 24)),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () { /* nav */ },
          child: const Text('Kom igång'),
        ),
      ],
    ),
  ),
)

// Åtkomst till teman via BuildContext
Text(
  'Stiliserad Text',
  style: Theme.of(context).textTheme.headlineMedium,
)

Vanliga misstag med Widget

Det första och vanligaste misstaget — använda StatefulWidget där StatelessWidget räcker. Många nybörjare Flutter-utvecklare skapar StatefulWidget för alla widgets, även om tillståndet lagras i en extern leverantör (Provider, Riverpod, BLoC). Detta är överflödigt och försämrar prestandan. Regel: använd StatelessWidget om tillståndet hanteras externt eller om widgeten inte har ett eget föränderligt tillstånd.

Det andra misstaget — skapa Widget inuti build-metoden utan const-konstruktor. Varje Widget som skapas utan const allokeras om vid varje build. Om Widgets inuti build() skapas med const-konstruktor kan Flutter återanvända samma instans, vilket minskar belastningen på garbage collectorn. Lägg till const överallt där det är möjligt — särskilt för Text, Icon, SizedBox, Padding och andra StatelessWidgets.

Det tredje misstaget — felaktig hantering av nycklar (Key). Flutter använder Key för att identifiera Widgets vid ombyggnad av trädet. Om en lista med Widgets byggs om utan Key kan Flutter blanda ihop ordningen på elementen, vilket leder till felaktig animation eller förlust av tillstånd. Lägg alltid till Key (t.ex. ValueKey eller ObjectKey) för element i listor, särskilt när du använder ListView.builder med dynamisk data.

Vanliga frågor

Vad är skillnaden mellan StatelessWidget och StatefulWidget?

StatelessWidget — widget utan föränderligt tillstånd, dess utseende bestäms helt av konstruktorn. StatefulWidget — widget med föränderligt tillstånd, som lagras i ett separat State-objekt och kan uppdateras via setState() utan att återskapa själva widgeten. Använd StatelessWidget överallt där det är möjligt, StatefulWidget — när lokalt tillstånd krävs.

Varför kallas Widgets immutable?

Widget immutable — är ett arkitekturbeslut i Flutter för prestanda. Om Widgets var mutable skulle Flutter inte kunna jämföra gammal och ny konfiguration på ett säkert sätt vid varje build. Oföränderlighet gör att Flutter snabbt kan avgöra om en Widget har ändrats (via operatorn ==) och återanvända den befintliga RenderObject, vilket minimerar dyra renderingsoperationer.

Vad är BuildContext och vad används det till?

BuildContext är en deskriptor för Widgets position i elementträdet. Genom det får Widget tillgång till förfäders Widgets (Theme, MediaQuery, Navigator) och InheritedWidget. BuildContext används också för navigering (Navigator.of(context)), visning av SnackBar och interaktion med Provider. Varje Widget får BuildContext via build()-metoden och skickar det vidare till sina efterföljare.

Hur väljer jag mellan Row, Column och Stack för layout?

Använd Row för horisontell placering av element, Column — för vertikal placering, Stack — för att lägga element ovanpå varandra. Row och Column fungerar enligt flexbox-principen: children upptar utrymme enligt mainAxisSize, mainAxisAlignment och crossAxisAlignment. Stack använder positioned-children för exakt positionering i förhållande till kanter eller mitt.

Hur upprätthåller Flutter 60 FPS med tusentals Widgets?

Flutter uppnår hög prestanda genom tre mekanismer: (1) Widget are cheap — lätta immutable objekt (40–80 byte), deras skapande belastar inte GC. (2) RenderObject reuse — vid byte av Widget av samma typ återanvänds RenderObject, vilket undviker dyr återskapning. (3) Skia/Impeller engine — rendering på C++-nivå med minimering av ritningsanrop via repaint boundaries.

Sammanfattning

  • Widget — immutable konfiguration av en del av UI i Flutter, grundläggande byggsten som beskriver utseende och beteende.
  • Tre träd — Flutter använder Widget tree (konfiguration), Element tree (anslutning), RenderObject tree (rendering) för optimal visning.
  • Stateless vs Stateful — StatelessWidget utan tillstånd, StatefulWidget med föränderligt State och setState()-metod för UI-uppdatering.
  • Komposition — UI byggs genom inkapsling av Widget via child/children, utan arv, vilket ger flexibilitet och återanvändbarhet.
  • BuildContext — deskriptor för Widgets position i trädet för åtkomst till Theme, Navigator, MediaQuery och InheritedWidget.
  • Prestanda — Widgets återskapas vid varje build (60 FPS), men RenderObject återanvänds vid typmatchning.
  • Kategorier — Widgets delas in i layout (Row, Column, Stack), painting (Container, Padding), interactive (GestureDetector, TextField) och platform (MaterialApp, Theme).

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också