Flutter 3.35: Performans, Erişilebilirlik ve UI’da Dikkat Çeken Atılımlar

 

Yeni başlayanlardan profesyonel geliştiricilere kadar herkesin bilmesi gereken noktaları



Her gün derinleşen Flutter ekosisteminde, bazen gözümüze ufak bir değişiklik göze çarpar ama altında büyük bir dönüşüm gizlidir. Flutter 3.35, işte böyle “küçük ama etkili” güncellemelerle geldi. Bu yazıda, en dikkat çeken yenilikleri keşfederken, her biriyle alakalı neden önemli olduklarını ve pratikte nasıl göze çarptıklarını anlatıyorum. Umarım faydalı olur.

Yazının tamamına buradan ulaşabilirsiniz.

Breaking Changes — Kodunuzu Yeniden Yazmanız Gereken Değişiklikler

Form artık sliver değil

Daha önce CustomScrollView içindeki Form widget’ı doğrudan kullanabiliyorduk, artık bir hata alıyoruz. Yeni dünyada şu şekilde:

CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Form(...),
),
],
);

Kodunuzda Form widget’ının yapı olarak nerede yer aldığına dikkat etmeniz gerekecek — çünkü bu doğrudan dönüşümsüz bir değişiklik.

Semantics elevation & thickness kaldırıldı

Erişilebilirlik API’lerinde yer alan semanticsElevation ve semanticsThicknessözellikleri artık yok. Eğer özel a11y donanımlı widget’lar geliştirdiyseniz, bu alanları yeniden gözden geçirmeniz gerekebilir.

DropdownButtonFormField’de value deprecated, initialValue geldi

Artık DropdownButtonFormField kullanırken:

DropdownButtonFormField<String>(
initialValue: 'A',
items: [...],
onChanged: (v) {},
);

value: alanını kullanıyorsanız, bunu initialValue: ile değiştirmeniz gerekiyor. Bu, form state yönetimini daha tutarlı hale getirmek için yapılmış. Kodlarıızı bu doğrultuda ayarlamalısınız.

Radio Widget Yeniden Tasarlandı

Radio artık görsel ve davranışsal olarak güncellendi. Tema uyumu ve erişilebilirlik açısından iyileştirildi. Ancak özelleştirme yapıyorsanız yeni RadioThemeData alanlarına bakmanız gerekecek. Buna noktada tema ile ilgili ayrı bir parantez açsam iyi olacak.

Tema Normalizasyonu

Birçok component theme API’sinde (AppBarTheme, InputDecorationTheme vb.) isimlendirme ve varsayılan değerler düzenlendi. Tema dosyalarınızda uyarılar alabilirsiniz.

Framework Tarafındaki Önemli Geliştirmeler

Widget Preview’ın ışık-dil desteği

Widget Preview özelliği çok daha esnek hale geldi: tema ve parlaklık (brightness) ayarlarını ve dil yerelleştirmesini artık farklı modalitelerde test edebilirsiniz. Özellikle paket geliştiriciler için faydalı olacağını düşünüyorum.

DrivenScrollActivity.simulation Constructor

Daha karmaşık scroll animasyonlarını manuel olarak yönetmek isteyenler için yeni bir constructor eklendi. Bunun, özel fizik animasyon senaryolarında işinize yarayacağı belirtilmiş. Örneğin:

TreeSliver & SliverEnsureSemantics

Flutter içindeki TreeSliver yapısının kaydırma (scroll) davranışı düzeltildi, artık daha az UI artifaktı yaşanıyor. Aynı zamanda erişilebilirlik açısından da SliverEnsureSemantics hatalı alt-özellikler yeniden canlandırıldı — özellikle ekran okuyucu kullanıcıları için olumlu.

MediaQuery.heightOf / widthOf

MediaQuery.sizeOf(context).height yerine artık direkt MediaQuery.heightOf(context) gibi daha kısa metodlar var.

final screenHeight = MediaQuery.heightOf(context);

Cupertino ve Material Değişiklikleri

Cupertino

  • CupertinoSlider artık titreşim (haptic feedback) destekli. Dokunsal geri bildirim kullanıcının kaydırdığı hissini pekiştiriyor.
  • CupertinoDatePickerCupertinoTimerPickerCupertinoExpansionTileCupertinoCollapsible gibi yeni bileşen veya gelişmiş davranışlar geldi.
  • Düğmeler, navigasyon bar geçişleri daha tutarlı, animasyonlar daha pürüzsüz hale geldi.

Material

CarouselView Geliştirmeleri

CarouselView artık temalandırılabilir ve hatalar giderildi. Mouse scroll desteği ve crash fix’leri önemli.

InputDecorationTheme Genişletildi

  • visualDensity desteği geldi.
  • hintMaxLines eklenerek uzun placeholder metinlerinin kontrolü kolaylaştı.
  • hintLocales ile placeholder için çoklu dil desteği mümkün oldu.

Switch ve CheckboxListTile Geliştirmeleri

  • Switch için activeThumbColor eklendi.
  • CheckboxListTile ve SwitchListTile için isThreeLine tema üzerinden ayarlanabilir.

DropdownMenuFormField Yenilikleri

  • restorationId desteği.
  • trailingIcon gizlenebilir.
  • value parametresi yerine initialValue. (yukarıda bunu açıklamıştım)

Platforma Özel İyileştirmeler

iOS & macOS

  • Minimum iOS sürümü 13’ten 14’e şeklinde güncellenmedi ama bazı API’lerde modern Swift uyumu sağlandı.
  • Swift ile embedder desteği genişledi.
  • Hot restart ardından klavye kapanması gibi küçük ama önemli iyileştirmeler yapıldı.
  • Live Text destekleri eklendi.

Android

  • Min SDK yükseltildi: artık API 24 (Lollipop) altı desteklenmiyor.
  • Android target SDK hedefi 36’ye çıktı.
  • Impeller Vulkan başlatma süresi iyileşti, grafik odaklı uygulamalar bunu doğrudan hissedecek.
  • Deprecation: setStatusBarColor vb. metotlar kaldırılacak.

Web

  • Safari/Firefox’taki bazı input focus sorunları giderildi.
  • VoiceOver gibi erişilebilirlik araçlarında tab sıralaması düzenlendi.
  • Paint dithering sayesinde grafiksel pürüzsüzlük arttı.

Windows

  • Multi-window desteği eklendi.
  • Platform ve UI thread’leri “birleşik yapı”ya kavuşturuldu. Windows uygulamalarında performans ve sabitlik artışı hedefleniyor.

Engine ve Performans İyileştirmeleri

  • Impeller: kesme (stroke) hesaplamaları daha verimli, Vulkan modunda daha hızlı açılış.
  • Leak tracker’ın web için deneysel modu geldi, developer memory leak kontrolü kolaylaşıyor.
  • Pub workspace ile çalışma altyapısı Modern Flutter projesine evrildi.
  • Test süreçlerinde birçok pub package temizlendi, build süreci hızlandı.
  • Frame rendering daha kararlı: Özellikle düşük donanımlı cihazlarda FPS dalgalanmaları %30 oranında azaldı.
  • Shader compilation cache geliştirmeleri sayesinde ilk açılışta yaşanan “jank” sorunu büyük ölçüde azaldı.
  • Skia güncellemesi ile daha keskin vektör çizimleri ve düşük bellek tüketimi.

Küçük bir not: Eğer oyun benzeri animasyonlar kullanıyorsanız, bu sürümde Impeller ile test yapmayı deneyin. Daha akıcı bir deneyim fark edeceğinizi söylüyorlar.

Özetle;

Flutter 3.25, sadece bir sürüm güncellemesi değil; daha akıcı, daha uyumlu ve geliştirici dostu bir deneyim sunuyor. Ayrıca performans optimizasyonuaçısından da önemli bir adım.

Küçük projeler için bile faydalı olan, büyük projelerde ise doğrudan kodunuzu etkileyecek değişiklikler içeriyor. Elimden geldiğince release notlarından özetlemeye çalıştım umarım faydalı olur.

Eğer projenizde henüz güncelleme yapmadıysanız, Flutter’ı şu komutla hemen güncelleyebilirsiniz:

flutter upgrade

Buraya kadar okuduğunuz için teşekkür ederim.

Yazımı beğendiyseniz clap butonuna tıklamayı ve diğer içeriklerimden haberdar olmak için abone olmayı unutmayın.

Yeni yazılarda görüşmek üzere.

Selin.

The 10 Most Common Mistakes in Flutter State Management and How to Fix Them

 

Hello, everyone. Today, I’m here to talk about StateManagement, a topic that many of us find complicated. Let’s get started.

You can read the full article here.

At first glance, your Flutter project may seem as innocent as a small “hello world” application. But as things grow and screens, API calls, user interactions, and data management come into play, state management can suddenly turn into a horror movie.

Incorrect state management:

  1. Slows down your application.
  2. Ruins the readability of your code.
  3. Makes teamwork difficult.
  4. And worst of all, makes debugging impossible in the future.

In this article, we will examine the 10 most common mistakes made when managing state in Flutter, with real code examples and solutions.

We will also discuss how you can spot these mistakes in advance and write more performant, sustainable code.

1. Putting All State in One Place

Mistake: Putting all of the application’s state into a single Provider, Bloc, or State class.

class AppState with ChangeNotifier {
String userName = '';
int cartItemCount = 0;
bool isDarkMode = false;
List<String> notifications = [];

void updateUserName(String name) {
userName = name;
notifyListeners();
}

void addNotification(String message) {
notifications.add(message);
notifyListeners();
}
}

This structure seems innocent in small projects. However, as the project grows:

  • Unnecessary rebuilds occur (even if only one field changes, all listeners are triggered).
  • The code becomes more complex.
  • Testing becomes more difficult.

Solution:
Modular state management → Separate state classes or Blocs for each feature.

class UserState with ChangeNotifier {
String userName = '';
void updateUserName(String name) {
userName = name;
notifyListeners();
}
}

class CartState with ChangeNotifier {
int itemCount = 0;
void addItem() {
itemCount++;
notifyListeners();
}
}

2. Unnecessary Rebuilds

Error: Wrapping the entire screen with Consumer or BlocBuilder.

Consumer<CartState>(
builder: (context, cart, child) {
return Scaffold(
appBar: AppBar(title: Text('Cart (${cart.itemCount})')),
body: ProductList(),
);
},
);

When itemCount changes, the entire screen is redrawn.

Solution:
Use Selectors or small widgets to rebuild only the necessary parts.

AppBar(
title: Selector<CartState, int>(
selector: (context, cart) => cart.itemCount,
builder: (context, count, child) => Text('Cart ($count)'),
),
)

3. Mixing Local and Global State

Mistake: Keeping UI-specific data in global state.

Example: Modal open/closed state is kept globally.

class AppState with ChangeNotifier {
bool isModalOpen = false;
}

Solution:
Keep screen-specific states in StatefulWidget or local provider.

class MyScreen extends StatefulWidget {
@override
State<MyScreen> createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
bool isModalOpen = false;
}

4. Mixing Business Logic with UI

Error: API calls or data processing code directly within widgets.

ElevatedButton(
onPressed: () async {
final data = await fetchData();
setState(() {
result = data;
});
},
child: Text("Load"),
)

Solution:
Move the business logic to the state management layer.

class DataState with ChangeNotifier {
String result = '';
Future<void> loadData() async {
result = await fetchData();
notifyListeners();
}
}

5. Use of Non-Immutable State

Error: Directly modifying the state object.

state.user.name = 'John'; // False

Solution:
Keep State immutable, use copyWith.

class User {
final String name;
User({required this.name});

User copyWith({String? name}) {
return User(name: name ?? this.name);
}
}

6. dispose() and Memory Management Neglect

Error: Failure to dispose of Streams, Controllers, or Timers.

class MyNotifier with ChangeNotifier {
final controller = StreamController();
}

Solution:
Add the dispose() method.

@override
void dispose() {
controller.close();
super.dispose();
}

7. Overuse of notifyListeners() in Provider

Error: Triggering all listeners for a single change.

void updateCart() {
itemCount++;
notifyListeners();
}

Solution:
Split the data into pieces or rebuild the target with context.select().

8. Managing Everything with a Single Event in Bloc

Mistake: Consolidating all operations into a single event.

class AppEvent {}

Solution:
Define a separate event for each transaction.

class LoadUser extends AppEvent {}
class UpdateCart extends AppEvent {}

9. Defining Unnecessary Reactive Variables in GetX

Error: Making even unchanging data .obs.

final appName = 'MyApp'.obs; // Not useful

Solution:
Make only the values that change and affect the UI reactive.

10. Wrong Library Selection

Error: Selecting a library because it is popular without analyzing the project requirements.

Solution:

  • Small projects → Provider / Riverpod
  • Medium projects → Riverpod / Bloc
  • Large team projects → Bloc / Clean Architecture

Conclusions and Recommendations

  1. Plan state management correctly at the beginning of the project.
  2. Use a modular approach.
  3. Reduce unnecessary rebuilds.
  4. Prefer immutable data structures.
  5. Don’t ignore testability.

Resources

Thank you for reading this far.

If you liked this article, don’t forget to click the clap button. You can subscribe to stay updated on my other content.

Thank you.

Selin.