Flutter and Widget Concept

 


When learning Flutter, I think the first thing to do to grasp its general logic is to learn about widgets and their hierarchy. So in this article I wanted to talk about widgets and the widget tree in Flutter.

What is a Widget?

Widgets are the basic building blocks for creating the user interface in Flutter applications. Everything is a widget. A text box, a button, an image, even icons. Everything is represented as a widget in Flutter.

Widget Types

There are two types of widgets used in Flutter.

1. Stateless Widget

Stateless: Does not contain any state. That is, once created, the information it contains cannot be changed. The widget’s appearance depends on its initial properties and the widget itself does not change unless these properties change.

Build Method Only: Usually contains only the “build” method. This method specifies how the widget will be displayed.

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter and Widget Concept'),
),
body: Center(
child: Text('Stateless Widget'),
),
),
);
}
}

In the example above, the text placed in appBar and body is written as immutable, so there is no state change here. StatelessWidget should be preferred because it does not need to be built again and again every time the application is refreshed.

2. Stateful Widget

Stateful: It can track the state thanks to a “State” object it contains. That is, after the widget is created, its state can change and these state changes are used to update the UI.

State Class: Stateful Widget is a class, but the actual state is contained in a separate “State” class. The “State” class contains the state of the widget and when it is updated, the “build” method is called again.

class CounterApp extends StatefulWidget {
@override
_CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
int _counter = 0;

void _incrementCounter() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Count Value: $_counter'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increase'),
),
],
),
),
),
);
}
}

In this example, a State management is required in CounterApp. There is a counter operation and the value of this counter is initially displayed on the screen and when the “Increase” button is clicked, the value of the counter increases. In this example, the _CounterAppState class keeps track of state changes and displays the current value of the counter on the screen. This means that there are changes in the background and UI and this piece of code needs to be rebuilt every time the application is refreshed. This is why StatefulWidget should be used.

At the beginning of my learning process, while I was frequently making inquiries such as what is state, what does it mean to build, I thought the following. If we can’t decide which part of the application to use stateful and which part to use stateless, we can use stateful. Because stateless can’t do the operations of stateful, but stateful does everything :) You may have thought like this too. However, performance issues arise here.

Recommendations for Use

  • If the appearance of a widget will not change after it is created and there is no need for status tracking, it may be more appropriate to use “Stateless Widget”.
  • If a widget’s appearance will change depending on the data it contains or will change as a result of user interactions, it makes sense to use “Stateful Widget”.

Ideally, widgets should be as stateless as possible, because stateless widgets are usually simpler, lighter and more performant. Stateful one should only be used when necessary.

Widget Tree

In Flutter, widgets are organized in a tree structure, creating a hierarchy.

- MaterialApp
- Scaffold
- AppBar
- Text
- Center
- Column
- Text
- SizedBox
- ElevatedButton

The widgets of the simple counter application above form a tree structure like this. This hierarchy shows how the widgets are embedded and related to each other. This is important for understanding how widgets are placed and interact with each other.

In conclusion, the Widget tree in Flutter is a fundamental concept used to build the interface of our application. Widgets are organized in a hierarchy and this tree structure determines the look and behavior of our app. I hope I have explained it in a simple way, I hope to be useful.

Thank you.

Selin.

Flutter ve Widget Kavramı

 


Flutter öğrenirken genel mantığını kavramak için yapılacak ilk şey, sanırım, widget’ları ve bunların hiyerarşisini öğrenmek. Ben de bu yazımda Flutter’da widget’lar ve widget ağacından bahsetmek istedim.

Widget Nedir?

Widget’lar, Flutter uygulamalarında kullanıcı arayüzünü oluşturmak için temel yapı taşlarıdır. Her şey bir widget’tir. Bir metin kutusu da, bir buton da, bir resim de, hatta ikonlar bile. Flutter’da her şey bir widget olarak temsil edilir.

Widget Türleri

Flutter’da kullanılan iki tür widget bulunur.

StatelessWidget:

  • Durumsuz (Stateless): İçinde durum (state) barındırmaz. Yani, bir kez oluşturulduktan sonra içerdiği bilgiler değiştirilemez. Widget'ın görünümü, başlangıçtaki özelliklerine bağlıdır ve bu özellikler değişmedikçe widget kendisi değişmez.
  • Sadece Build Metodu: Genellikle sadece “build” metodunu içerir. Bu metod, widget'ın nasıl görüntüleneceğini belirtir.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter ve Widget Kavramı'),
),
body: Center(
child: Text('Stateless Widget'),
),
),
);
}
}

Yukarıdaki örnekte appBar ve body içerisine yerleştirilen metinler değişmez olarak yazıldığından, burada bir durum değişimi yoktur. Uygulama her yenilendiğinde tekrar tekrar “build” edilmesine gerek olmadığından StatelessWidget tercih edilmelidir.

StatefulWidget:

  • Durum İçerir (Stateful): İçerdiği bir “State” nesnesi sayesinde durumu takip edebilir. Yani, widget oluşturulduktan sonra durumu değişebilir ve bu durum değişiklikleri UI'ı güncellemek için kullanılır.
  • State Sınıfı: Stateful Widget bir sınıftır, ancak asıl durum (state) bu sınıftan ayrı bir “State” sınıfında bulunur. “State” sınıfı, widget'ın durumunu içerir ve güncellendiğinde “build” metodu tekrar çağrılır.
class CounterApp extends StatefulWidget {
@override
_CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
int _counter = 0;

void _incrementCounter() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Sayac Uygulaması'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Sayac Değeri: $_counter'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Arttır'),
),
],
),
),
),
);
}
}

Bu örnekte ise CounterApp içerisinde bir State yönetimi gerekir. Burada bir sayaç işlemi mevcut ve bu sayacın değeri başlangıçta ekranda gösterilir ve “Arttır” butonuna tıklandığında sayacın değeri artar. Bu örnekte, _CounterAppState sınıfı durum değişikliklerini takip eder ve sayacın güncel değerini ekranda gösterir. Yani arka planda ve UI’da değişiklik mevcuttur ve uygulama her yenilendiğinde bu kod parçasının yeniden build edilmesi gerekir. Bu sebepten StatefulWidget kullanılması gerekir.

Öğrenim sürecimin başlarında state nedir, build etmek ne demektir gibi sorgulamaları sıkça yaparken şunu düşünmüştüm. Uygulamanın hangi kısmında stateful hangisinde stateless kullanacağımıza karar veremediysek stateful kullanıp geçebiliriz. Çünkü stateless stateful’un işlemlerini yapamıyor ama stateful her işi görür. :) Siz de böyle düşünmüş olabilirsiniz. Ancak burada karşımıza performans sorunları çıkıyor.

Kullanım Tavsiyeleri:

  • Eğer bir widget’ın görünümü, oluşturulduktan sonra değişmeyecekse ve durum takibine ihtiyaç duyulmuyorsa, “Stateless Widget” kullanmak daha uygun olabilir.
  • Eğer bir widget’ın görünümü, içerdiği verilere bağlı olarak değişecekse veya kullanıcı etkileşimleri sonucunda değişiklik gösterecekse, “Stateful Widget” kullanmak mantıklıdır.

İdeal durumda, widget’lar mümkün olduğunca durumsuz (stateless) olmalıdır, çünkü durumsuz widget’lar genellikle daha basit, hafif ve performanslıdır. Stateful, sadece gerekli olduğunda kullanılmalıdır.

Widget Ağacı

Flutter’da, widget’lar bir hiyerarşi oluşturarak bir ağaç yapısında düzenlenir.

- MaterialApp
- Scaffold
- AppBar
- Text
- Center
- Column
- Text
- SizedBox
- ElevatedButton

Yukarıdaki basit sayaç uygulamasının widget’ları şu şekilde bir ağaç yapısı oluşturur. Bu hiyerarşi, widget’ların nasıl gömülü olduğunu ve birbirleriyle ilişkili olduklarını gösterir. Bu, widget’ların nasıl yerleştirildiğini ve birbirleriyle etkileşime girdiğini anlamak için önemlidir.

Sonuç olarak, Flutter’da Widget ağacı, uygulamamızın arayüzünü oluşturmak için kullanılan temel bir kavram. Widget’lar, bir hiyerarşi içinde düzenleniyor ve bu ağaç yapısı, uygulamamızın görünümünü ve davranışını belirliyor. Umarım basitçe anlatabilmişimdir, faydalı olmayı umuyorum.

Sevgiler.

Selin.