Jonny Borges
Committed by GitHub

Merge pull request #2338 from gizemgizg/master

🇹🇷 Turkish documents of State Management, Route Management and Dependency Management files were create.
... ... @@ -34,6 +34,7 @@
[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)
[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)
[![Japanese](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README.ja-JP.md)
[![Turkish](https://img.shields.io/badge/Language-Turkish-blueviolet?style=for-the-badge)](README.tr-TR.md)
</div>
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)
[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)
<a href="https://github.com/Solido/awesome-flutter">
<img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" />
</a>
<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a>
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)
<div align="center">
**Languages:**
[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)
[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)
[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)
[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)
[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)
[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)
[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)
[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)
[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)
[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)
[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)
[![Japanese](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README.ja-JP.md)
[![Turkish](https://img.shields.io/badge/Language-Turkish-blueviolet?style=for-the-badge)](README.tr-TR.md)
</div>
- [Get Hakkında](#get-hakkında)
- [Kurulum](#kurulum)
- [GetX ile Sayaç Uygulaması](#getx-ile-sayaç-uygulaması)
- [Üç Temel Kavram](#üç-temel-kavram)
- [State Management (Durum Yönetimi)](#state-management-durum-yönetimi)
- [Reactive State Manager (Reaktif Durum Yönetimi)](#reactive-state-manager-reaktif-durum-yönetimi)
- [State Management Hakkında Daha Fazla Bilgi](#state-management-hakkında-daha-fazla-bilgi)
- [Route Management (Rota Yönetimi)](#route-management-rota-yönetimi)
- [Route Management Hakkında Daha Fazla Bilgi](#route-management-hakkında-daha-fazla-bilgi)
- [Dependency Management (Bağımlılık Yönetimi)](#dependency-management-bağımlılık-yönetimi)
- [Dependency Management Hakkında Daha Fazla Bilgi](#dependency-management-hakkında-daha-fazla-bilgi)
- [Utils](#utils)
- [Internationalization (Uluslararasılaştırma)](#internationalization-uluslararasılaştırma)
- [Translations (Çeviriler)](#translations-çeviriler)
- [Translations Kullanımı](#translations-kullanımı)
- [Locales (Yerel Ayarlar)](#locales-yerel-ayarlar)
- [Locale Değiştirme](#locale-değiştirme)
- [System locale (Yerel Sistem Ayarları)](#system-locale-yerel-sistem-ayarları)
- [Tema Değiştirme](#tema-değiştirme)
- [GetConnect](#getconnect)
- [Varsayılan Ayarlar](#varsayılan-ayarlar)
- [Özel Ayarlarlamalar](#özel-ayarlamalar)
- [GetPage Middleware](#getpage-middleware)
- [Priority (Öncelik)](#priority-öncelik)
- [Redirect (Yönlendirme)](#redirect-yönlendirme)
- [onPageCalled](#onpagecalled)
- [OnBindingsStart](#onbindingsstart)
- [OnPageBuildStart](#onpagebuildstart)
- [OnPageBuilt](#onpagebuilt)
- [OnPageDispose](#onpagedispose)
- [Advanced APIs (Gelişmiş API'ler)](#advanced-apis-gelişmiş-apiler)
- [Opsiyonel Genel Ayarlar ve Manuel Ayarlamalar](#opsiyonel-genel-ayarlar-ve-manuel-ayarlamalar)
- [Local State Widgets (Yerel Durum Widgetları)](#local-state-widgets-yerel-durum-widgetları)
- [ValueBuilder](#valuebuilder)
- [ObxValue](#obxvalue)
- [Faydalı İpuçları](#faydalı-ipuçları)
- [GetView](#getview)
- [GetResponsiveView](#getresponsiveview)
- [Nasıl Kullanılır?](#nasıl-kullanılır)
- [GetWidget](#getwidget)
- [GetxService](#getxservice)
- [2.0 İle Gelen Büyük Değişiklikler](#20-ile-gelen-büyük-değişiklikler)
- [Neden Getx?](#neden-getx)
- [Topluluk](#topluluk)
- [Topluluk Kanalları](#topluluk-kanalları)
- [Nasıl katkıda bulunulur?](#nasıl-katkıda-bulunulur)
- [Makaleler ve Videolar](#makaleler-ve-videolar)
# Get Hakkında
- GetX, Flutter için oldukça basit ve güçlü bir çözüm yoludur. Yüksek performanslı state managment (durum yönetimi), yetenekli dependency injection (bağımlılık enjeksiyonu) ve route management'ı (rota yönetimi) hızlı ve pratik şekilde bir araya getirir.
- GetX'in 3 temel ilkesi vardır. Bu ilkeler kütüphanedeki tüm kaynaklar için önemlidir: **ÜRETKENLİK, PERFORMANS VE ORGANİZASYON.**
- **PERFORMANS:** GetX, performansa ve kaynakların minimum düzeyde tüketimine odaklanmıştır. GetX, Streams ya da ChangeNotifier kullanmaz.
- **ÜRETKENLİK:** GetX kolay ve keyifli bir syntax (yazım kuralları) kullanır. Ne yapmak istersen iste GetX'de her zaman kolay bir çözüm yolu vardır. Saatlerce süren geliştirmeden tasarruf etmeyi ve uygulanın size sağladığı performansı maksimum seviyede kullanmayı mümkün kılar.
Normalde geliştirici, controller'ları hafızadan kaldırmakla ilgilenmelidir. GetX ile bunu yapmaya gerek kalmaz çünkü varsayılan olarak kaynaklar kullanılmadığı zaman hafızadan kendiliğinden kaldırılır. Eğer hafızada tutmak istiyorsanız, dependency içinde "permanent: true" olarak tanımlanmanız gerekmektedir. Bu şekilde hem zaman tasarrufu hem de hafızadaki gereksiz dependency'lerin oluşturabileceği riskler azaltmış olur. Dependency yüklemesi varsayılan olarak lazy'dir (tembeldir).
- **ORGANİZASYON:** GetX, presentation logic'i (sunum mantığını, business logic'i (iş mantığını), dependency injection'ı, navigasyonu View'dan tamamen ayırmayı sağlar. Route'lar arasında navigasyon için context'e gerek duyulmaz bu sayede widget tree'ye (widget ağacına) bağımlı kalmazsınız. Controllers ya da blocs'daki inheritedWidget'a erişmek için context'e ihtiyaç duyulmaz böylelikle presentation logic ve business logic, view katmanından tamamen ayrılır. Controllers/Models/Blocs sınıflarını widget tree'ye inject (aktarırken) ederken `MultiProvider`'lar kullanılmasına ihtiyaç yoktur. GetX'in kendine ait dependency injection özelliği sayesinde DI'yi de view'dan tamamen ayrır.
GetX ile varsayılan olarak temiz kod kullanılarak uygulamadaki her bir özelliğin nerede bulunduğuna ulaşabilirsiniz. Bakım kolaylığının yanı sıra Flutter'da düşünüleyemeyen bir şey olan modülleri paylaşmayı tamamen mümkün kılar.
BLoC, Flutter'daki kodları organize etmenin başlangıç noktasıdır. Business logic'i, view'dan ayırır. Bunun gelişmiş hali olarak ortaya çıkan GetX sadece business logic'i ayırmakla kalmayıp aynı zamanda dependency injection'ları, route'ları ve presentation logic'i de view'dan ayırır. Data layer (Veri katmanı) bu sayede bütün katmanların dışında bırakılır. Her şeyin nerde olduğunu bilmek "hello word" oluşturmaktan çok daha kolay bir yoldur.
GetX, Flutter SDK'sı ile çok kolay, pratik ve ölçeklenebilir yüksek performanslı uygulamalar yapmanızı sağlar. Birlikte çalışılabilen büyük bir ekosistem içerir. Yeni başlayanlar için oldukça kolay ve uzmanlar için de doğru olandır. Güvenli, stabil, güncel ve Flutter SDK'da varsayılan olarak olmayan büyük kapsamlı APIs kullanabilmeyi sağlar.
- GetX şişkin değildir. Çoklu davranış içeren özellikleri kullanarak, herhangi bir endişe olmaksızın programlamaya başlamanızı sağlar. Ancak bu özellikler farklı taraflarda olup sadece kullanıldıktan sonra başlatılır. Sadece state management kullanıyorsanız, sadece bu derlenir. Sadece routes kullanırsanız, state management'dan hiçbir şey derlenmez.
- GetX büyük bir ekosistemdir. Geniş bir topluluk, çok sayıda destekçi içerir ve Flutter var olduğu sürece bu korunacaktır. GetX, tek bir kod ile Android, iOS, Web, Mac, Linux, Windows veya kendi server'ınız (sunucunuz) üzerinde çalışmaya elverişlidir.
**[Get Server](https://github.com/jonataslaw/get_server) ile frontend üzerinde yaptığınız kodu backend üzerinde tamamen yeniden kullanmanız mümkün**.
**Ek olarak, tüm geliştirme süreci hem server'da hem de frontend'de [Get CLI](https://github.com/jonataslaw/get_cli) ile tamamen otomatikleştirilebilir**.
**Ayrıca üretkenliğinizi arttırmak için
[VSCode eklentileri](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) ve the [Android Studio/Intellij eklentileri](https://plugins.jetbrains.com/plugin/14975-getx-snippets) vardır.**
# Kurulum
pubspec.yaml dosyasına Get’i ekleyin:
```yaml
dependencies:
get:
```
Get’i kullanılacak sayfaya import ediyoruz:
```dart
import 'package:get/get.dart';
```
# GetX ile Sayaç Uygulaması
“Sayaç” projesi yeni bir Flutter projesi oluştururken varsayılan olarak gelir. Yorum satırları ile birlikte toplam 100 satır içerir. Get’in gücünü göstermek gerekirse, size bir “sayaç” uygulamasının her bir tıklamada durumunu değiştirip, sayfalar arasında hareket edip ve bunu yaparken state'leri (durumları) aktarıp aynı zamanda organize bir yol izleyerek business logic'i view'dan ayıracağız ve bu YORUM SATIRLARI DAHİL SADECE 26 SATIR İÇERECEK.
- 1.Adım:
“Get”’i MaterialApp’den önce GetMaterialApp'e dönüştürerek ekliyoruz.
```dart
void main() => runApp(GetMaterialApp(home: Home()));
```
- Not: Bu kullanım Flutter’ın sağladığı MaterialApp’i modifiye etmez. Sadece child'ı (çocuğu) MaterialApp olan ve bir öncesinde konfigüre edilmiş bir widget’tır. Kendiniz de manuel olarak konfigüre edebilirsiniz fakat buna gerek yoktur. GetMaterialApp, route’ları oluşturacak ve içine bunları, translation’ları ve route navigation için ihtiyacınız olabilecek olan her şeyi inject edecektir. Eğer Get’i sadece state management ya da dependency management olarak kullanmak isterseniz, GetMaterialApp kullanmanıza gerek yoktur. Bu yapı routes, snackbars, internationalization, bottomSheets, dialogs, ve route'lara bağlı high-level apis kullanımlarında ek olarak da context'in yokluğundaki durumlarda kullanılmalıdır.
- Not²: Bu adım sadece route management kullanıldığında gereklidir (`Get.to()`, `Get.back()` ve bunlar gibi). Kullanmayacaksanız 1. adımı yapmanıza gerek yoktur.
- 2.Adım:
İş mantıklarını içeren sınıfı oluşturup içine tüm değişkenleri metodları ve controller'ları ekleyin.İstediğiniz herhangi bir değişkeni ".obs" ile gözlemlenebilir yapabilirsiniz.
```dart
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
```
- 3.Adım:
View'ı oluşturun ve içine StatelessWidget (bu RAM'den tasarruf sağlar) yerleştirin. Get sayesinde StatefulWidget kullanmanıza gerek yoktur.
```dart
class Home extends StatelessWidget {
@override
Widget build(context) {
// Sınıfınızın nesnesini getirmek için Get.put() kullanılır. Bu içindeki tüm "child" route'ları görüntülenebilir yapar.
final Controller c = Get.put(Controller());
return Scaffold(
// Sayaç her değiştiğinde Text() içindeki değerin güncellenmesi için Obx(()=> kullanılır
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// Navigator.push içeren 8 satırı basit bir şekilde Get.to() ile değiştirin. Bunda context'e ihtiyacınız kalmamaktadır.
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
}
}
class Other extends StatelessWidget {
// Önceki sayfada zaten kulllandığımız Controller'ı, Get'de "find" diyerek getirmesinini istiyoruz.
final Controller c = Get.find();
@override
Widget build(context){
// Güncellenen sayaç değişkenine erişiyoruz.
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
```
Sonuç:
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)
Bu basit bir proje ama Get'in ne kadar güçlü olduğunu zaten açıkça ortaya koyuyor. Projeniz büyüdükçe bu gücü daha iyi anlacaksınız.
Get, ekiplerle çalışmak üzere tasarlanmıştır. Ayrıca bireysel geliştiricinin de işini oldukça kolaylaştırır.
Performanstan ödün vermeden her şeyi zamanında teslim etmenize yardımcı olur. Get tam olarak sana layık!
# Üç Temel Kavram
## State management (Durum Yönetimi)
Get iki farklı state manager içerir: simple state manager (GetBuilder da denilir) ve reactive state manager (GetX/Obx)
### Reactive State Manager (Reaktif Durum Yönetimi)
Reaktif programlama, birçok kişi tarafından karmaşık olduğu söylendiği için kafa karışıklığına yol açabilir. Ancak GetX, reaktif programlamayı oldukça basit bir hale dönüştürür:
- StreamController'ları oluşturmanıza ihtiyacınız yoktur.
- Her bir değişken için StreamBuilder oluşturmanıza gerekmez.
- Her state için sınıf oluşturmanıza gerek yoktur.
- Başlangıç değerleri için get metodu oluşturmaya ihtiyaç olmaz.
- Code generators kullanmanız gerekmez.
Get, reaktif programlamayı setState kullanmak kadar kolay yapmaktadır.
Bir isim değişkeniniz olduğunu ve onu her değiştirdiğinizde, onu kullanan tüm widget'ların otomatik olarak güncellendiğini düşünün.
Bu sizin sayaç değişkeniniz:
```dart
var name = 'Jonatas Borges';
```
Gözlemlenebilir yapmak için ".obs" ekliyorsunuz ve bu şekli alıyor:
```dart
var name = 'Jonatas Borges'.obs;
```
UI'da (kullanıcı arayüzünde) bu değeri göstermek ve değerler değiştiğinde ekranı güncellemek istediğinizde, hemen şunu yapın:
```dart
Obx(() => Text("${controller.name}"));
```
Hepsi bu. İşte _bu kadar_ basit.
### State Management Hakkında Daha Fazla Bilgi
**State Management'ın daha ayrıntılı bir açıklamasına [buradan](./documentation/en_US/state_management.md) erişebilirsiniz. Orada daha fazla örnek ile simple state manager ve reactive state manager arasındaki farkı görebilirsiniz**
GetX'in gücü hakkında daha iyi bir fikir edineceksiniz.
## Route Management (Rota Yönetimi)
Eğer routes/snackbars/dialogs/bottomsheets yapılarını context'e ihtiyaç duymadan kullanmak istedğinizde, GetX bunun için biçilmiş kaftan.
MaterialApp'i GetMaterialApp ile değiştiriyoruz.
```dart
GetMaterialApp( // Önceki hal: MaterialApp(
home: MyHome(),
)
```
Yeni ekrana geçmek için:
```dart
Get.to(NextScreen());
```
Name (isim) ile yeni sayfaya geçiş yapılabilir. Named routes (İsimli rotalar) hakkında daha çok bilgiye [buradan](./documentation/tr_TR/route_management.md#navigation-with-named-routes) ulaşabilirsiniz.
```dart
Get.toNamed('/details');
```
Snackbars, dialogs, bottomsheets ve normalde Navigator.pop(context) ile kapatacağınız herhangi bir şeyi kapatmak için;
```dart
Get.back();
```
Önceki ekrana geri dönme seçeneğinin olmadan bir sonraki ekrana gitmek için (örnek olarak SplashScreens, login screens, vs.)
```dart
Get.off(NextScreen());
```
Sonraki ekrana gitmek ve önceki tüm route'ları kapatmak için shopping carts, polls, ve test'lerde kullanılır)
```dart
Get.offAll(NextScreen());
```
Bunlardan herhangi birini yapmak için context kullanmanız gerekmediğini fark ettiniz mi? Get route management'ı kullanmanın en büyük avantajlarından biri de budur. Böylelikle controller sınıfınızda olan tüm metodları endişe olmadan çalıştırabilirsiniz.
### Route Management Hakkında Daha Fazla Bilgi
**Get, named routes ile çalışırken route'lar arası geçişleri kolayca kontrol etmenizi sağlar. Daha ayrıntılı doküman için [buraya](./documentation/tr_TR/route_management.md) tıklayabilirsiniz.**
## Dependency Management (Bağımlılık Yönetimi)
Get basit ve güçlü bir dependency manager içerir. Sadece tek satır kod ile Bloc ya da Controller'ınızın aynı sınıf nesnesini getirmenizi sağlar. Ayrıca Provider context, ya da inheritedWidget kullanmanıza gerek kalmaz:
```dart
Controller controller = Get.put(Controller()); // Controller controller = Controller(); yazmak yerine
```
- Not: Get'in State Manager'ını kullanıyorsanız, API bağlamaya daha çok dikkat edin ki onlar view'ı controller'a kolayca bağlamanızı sağlayacaktır.
Kullanacağınız sınıfın içinde başka bir sınıfın nesnesini oluşturmak yerine, Get instance sayesinde uygulamanızın her yerinde aynı sınıf nesnesini kullanabilir hale getirebilirsiniz.
Böylelikle controller (ya da Bloc sınıfını) normal bir şekilde kullanabilirsiniz.
**İpucu:** Get dependency management, kütüphanenin diğer parçalarından ayrıdır. Örnek olarak eğer uygulamanızda hali hazırda state manager kullanıyorsanız (hangisi olduğu fark etmez), en baştan yazmaya gerek yoktur. Bu dependency injection'ı problem olmadan kullanabilirsiniz.
```dart
controller.fetchApi();
```
Farzedin ki çok fazla sayıda route'larınız ve controller'larınızda erişmeniz gereken data'lar olsun, state manager'ı Provider ya da Get_it gibi kütüphaneler ile bağlamanız gerekmekedir. Get kullanarak bunları bağlamaya ihtiyacınız kalmaz. Get'e sadece "find" diyerek controller'ınızı bulmasını istemeniz yeterlidir. Fazladan dependency'lere ihtiyacınız yoktur:
```dart
Controller controller = Get.find();
// Evet, inanılmaz değil mi? Get, controller'ınızı bulup getirecek. Get, milyonlarca controller tanımlanmış da olsa size her zaman doğrusunu getirecektir.
```
Sonrasında üstte alınan controller'daki verilerinizi kullanabileceksiniz:
```dart
Text(controller.textFromApi);
```
### Dependency Management Hakkında Daha Fazla Bilgi
**Dependency management'a daha derinden bakmak için [buraya](./documentation/tr_TR/dependency_management.md) tıklayabilirsiniz**
# Utils
## Internationalization (Uluslararasılaştırma)
### Translations (Çeviriler)
Translations, map halinde basit key-value değerleri tutar.
Özel translation'larınızı eklemek için bir sınıf oluşturup `Translations`sınıfını extend edebilirsiniz.
```dart
import 'package:get/get.dart';
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {
'hello': 'Hello World',
},
'de_DE': {
'hello': 'Hallo Welt',
}
};
}
```
#### Translations kullanımı
Önecen belirlenmiş key'e sadece `.tr` eklenince `Get.locale` ve `Get.fallbackLocale` şimdiki değerleri kullanarak otomatik çeviriyi yapacaktır.
```dart
Text('title'.tr);
```
#### Tekil ve çoğul çevirisi yapımı
```dart
var products = [];
Text('singularKey'.trPlural('pluralKey', products.length, Args));
```
#### Parametreler ile çeviri yapımı
```dart
import 'package:get/get.dart';
Map<String, Map<String, String>> get keys => {
'en_US': {
'logged_in': 'logged in as @name with email @email',
},
'es_ES': {
'logged_in': 'iniciado sesión como @name con e-mail @email',
}
};
Text('logged_in'.trParams({
'name': 'Jhon',
'email': 'jhon@example.com'
}));
```
### Locales (Yerel Ayarlar)
Locale ve translation'lar`GetMaterialApp`'in parametreleri içinde atanabilir.
```dart
return GetMaterialApp(
translations: Messages(), //Çevirileriniz
locale: Locale('en', 'US'), //Çeviriler bu locale dilinde gösterilecek
fallbackLocale: Locale('en', 'UK'), // Eğer yanlış bir locale olması durumunda gösterilecek fallback locale
);
```
#### Locale değiştirme
`Get.updateLocale(locale)` çağrılarak locale güncellenebilir. Çeviriler otomatik olarak yeni locale dilinde olacaktır.
```dart
var locale = Locale('en', 'US');
Get.updateLocale(locale);
```
#### System locale (Yerel Sistem Ayarları)
Sistem locale'i okumak için `Get.deviceLocale` kullanılır.
```dart
return GetMaterialApp(
locale: Get.deviceLocale,
);
```
## Tema Değiştirme
Güncellemek için`GetMaterialApp`'in üstüne bir widget koymayın. Bu, kopya key'ler oluşmasını tetikler. Birçok kişi tema değiştirmek için tarih öncesi bir yöntem olan "ThemeProvider" widget'ı oluşturmayı tercih eder. **GetX™** ile buna HİÇ gerek duyulmaz.
`Get.changeTheme`ile kendi oluşturduğunuz temanızı hızlı bir şekilde ekleyebilirsiniz:
```dart
Get.changeTheme(ThemeData.light());
```
`onTap`'de Temayı değiştiren bir buton oluşturmak istiyorsanız, bunun için iki **GetX™** API'sini birleştirebilirsiniz:
- API, karanlık `Theme`'in kullanıp kullanılmadığını kontrol eder.
- `Theme` Change API'yi `onPressed`içine koyabilirsiniz:
```dart
Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
```
`.darkmode` aktif hale geldiğinde, tıklandığında _light theme_ 'e döner, _light theme_ aktif olduğunda, _dark theme_'e geçer.
## GetConnect
GetConnect backend ile frontend'in http ya da websockets ile kolayca iletişime geçmesini sağlar.
### Varsayılan Ayarlar
Sadece GetConnect'den extend ederek gelen GET/POST/PUT/DELETE/SOCKET metodlarını kullanarak Rest API ya da websockets ile kolayca iletişim kurabilirsiniz.
```dart
class UserProvider extends GetConnect {
// Get request
Future<Response> getUser(int id) => get('http://youapi/users/$id');
// Post request
Future<Response> postUser(Map data) => post('http://youapi/users', body: data);
// File ile Post request
Future<Response<CasesModel>> postCases(List<int> image) {
final form = FormData({
'file': MultipartFile(image, filename: 'avatar.png'),
'otherFile': MultipartFile(image, filename: 'cover.png'),
});
return post('http://youapi/users/upload', form);
}
GetSocket userMessages() {
return socket('https://yourapi/users/socket');
}
}
```
### Özel Ayarlamalar
GetConnect oldukça düzenlenebilir. Kendi base Url'nizi tanımlayabilir, cevapları ve Request'leri düzenleyebilirsiniz. Authenticator oluşturup kendiliğinden authenticate olmasını sağlayabilirsiniz. Size verilen standart decoder ile tüm request'leri ek bir ayar olmadan modellerinize aktarabilirsiniz.
```dart
class HomeProvider extends GetConnect {
@override
void onInit() {
// Tüm request'ler jsonEncode'a gider: CasesModel.fromJson()
httpClient.defaultDecoder = CasesModel.fromJson;
httpClient.baseUrl = 'https://api.covid19api.com';
// baseUrl = 'https://api.covid19api.com'; //baseUrl'yi bu şekilde tanımlar
// Http ve websockets kullanılmış ise [httpClient] instance'ına ihtiyaç yoktur.
// Gelen tüm request'ler "apikey"'in header özelliğine gier.
httpClient.addRequestModifier((request) {
request.headers['apikey'] = '12345678';
return request;
});
// Eğer sunucu "Brazilya"'dan bir veri gönderse bile
// response'dan veriyi kaldırdığın için kullanıcılar göremez.
// response önceden getirişmiş olsa bile
httpClient.addResponseModifier<CasesModel>((request, response) {
CasesModel model = response.body;
if (model.countries.contains('Brazil')) {
model.countries.remove('Brazilll');
}
});
httpClient.addAuthenticator((request) async {
final response = await get("http://yourapi/token");
final token = response.body['token'];
// header veriliyor
request.headers['Authorization'] = "$token";
return request;
});
// HttpStatus, HttpStatus.unauthorized ise
// Autenticator 3 defa çağırılır.
httpClient.maxAuthRetries = 3;
}
}
@override
Future<Response<CasesModel>> getCases(String path) => get(path);
}
```
## GetPage Middleware
GetPage'in GetMiddleWare listesi oluşturan ve bunları özel bir sırada çalıştıran bir özelliği vardır.
**Not**: GetPage, Middlewares içeriyor ise bu sayfanın tüm çocukları da aynı middlewares'i otomatik olarak içerir.
### Priority (Öncelik)
Middlewares'in sıralı çalışması için GetMiddleware'lerin priority'leri (öncelikleri) düzenlenmelidir.
```dart
final middlewares = [
GetMiddleware(priority: 2),
GetMiddleware(priority: 5),
GetMiddleware(priority: 4),
GetMiddleware(priority: -8),
];
```
Middleware'ler bu sırada çalışacaktır: **-8 => 2 => 4 => 5**
### Redirect (Yönlendirme)
Çağrılan route'un sayfası arandığında, fonsyon çağırılmış olacaktır. Redirect için RouteSettings kullanılır. Name değeri null verilebilir ve bu olduğu zaman herhangi bir redirect olmayacaktır.
```dart
RouteSettings redirect(String route) {
final authService = Get.find<AuthService>();
return authService.authed.value ? null : RouteSettings(name: '/login')
}
```
### onPageCalled
Bu fonsyon, herhangi bir şey oluşmadan önce sayfa çağırılmak istenildiğinde kullanılır. Sayfada bir şey değiştirmek için ya da yeni bir sayfa vermek için kullanabilirsiniz.
```dart
GetPage onPageCalled(GetPage page) {
final authService = Get.find<AuthService>();
return page.copyWith(title: 'Welcome ${authService.UserName}');
}
```
### OnBindingsStart
Bu fonsyon Bindings başlatılmadan hemen önce çalışır.
Bu sayfa için Bindings'i şu şekilde değiştirebilirsiniz.
```dart
List<Bindings> onBindingsStart(List<Bindings> bindings) {
final authService = Get.find<AuthService>();
if (authService.isAdmin) {
bindings.add(AdminBinding());
}
return bindings;
}
```
### OnPageBuildStart
Bu fonsyon Bindings başlatıldıktan hemen sonra çalışır.
Bindings oluşturulduktan hemen sonra ve widget sayfası oluşturulmadan önce kullanabilirsiniz.
```dart
GetPageBuilder onPageBuildStart(GetPageBuilder page) {
print('bindings are ready');
return page;
}
```
### OnPageBuilt
Bu fonskyon GetPage.page fonskyonu çağrıldıktan hemen sonra çalışır ve fonksyonun sonucunu verir. Sonrasında gösterilecek widget'ı alır.
### OnPageDispose
Bu fonsyon sayfadaki ilgili tüm objelerin (Controllers, views, ...) dispose olmasından hemen sonra çalışır.
## Advanced APIs (Gelişmiş API'ler)
```dart
// currentScreen'deki arg'ı verir
Get.arguments
// Önceki route'un name'ini verir.
Get.previousRoute
// Erişmek için raw route'u verir. Örnek olarak: rawRoute.isFirst()
Get.rawRoute
// GetObserver'dan Routing API'ye erişim verir.
Get.routing
// Snackbar açık mı kontrolü yaplır.
Get.isSnackbarOpen
// Dialog açık mı kontrolü yaplır.
Get.isDialogOpen
// Bottomsheet açık mı kontrolü yaplır.
Get.isBottomSheetOpen
// Tek route kaldırılır.
Get.removeRoute()
// predicate, true döndürene kadar terarlanarak geri gelir.
Get.until()
// Yeni route a gider ve eski tüm route'ları, predicate, true döndürene kadar kaldırır.
Get.offUntil()
// named route'a gider ve eski tüm route'ları, predicate, true döndürene kadar kaldırır.
Get.offNamedUntil()
//Hangi platformda çalıştığı kontrol edilir.
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
//Cihaz türü kontrol edilir.
GetPlatform.isMobile
GetPlatform.isDesktop
//Web'de tüm platformlar bağımsız olarak desteklenir!
//Bir tarayıcının içinde çalışıp çalışmadığınızı anlayabilirsiniz
//Windows, iOS, OSX, Android, vs. gibi
GetPlatform.isWeb
// Aşağıdakine eşittir : MediaQuery.of(context).size.height,
// fakat immutable'dır (sabittir).
Get.height
Get.width
// Navigator'e şimdiki context'i verir.
Get.context
// Önde olan snackbar/dialog/bottomsheet'a nerede olursanız olun context'i verir.
Get.contextOverlay
// Not: aşağıdaki metodlar context üzerine olan extension'lardır.
// UI'ın herhangi bir yerinde context'e erişebilirsiniz ve istediğiniz yerde kullanabilirsiniz.
// Eğer değişken bir height/width verileri varsa (örnek olarak Masaüstü ya da tarayıcı gibi ölçeği değişebilen pencereler) context'i kullanmaya ihtiyacınız vardır.
context.width
context.height
// Size ekranın yarısını, üçte birini vb. tanımlamayı sağlar.
// Responsive uygulamalar için kullanışlıdır.
// param dividedBy (double) optional - default: 1
// param reducedBy (double) optional - default: 0
context.heightTransformer()
context.widthTransformer()
/// MediaQuery.of(context).size'a benzer
context.mediaQuerySize()
/// MediaQuery.of(context).padding'e benzer
context.mediaQueryPadding()
/// MediaQuery.of(context).viewPadding'e benzer
context.mediaQueryViewPadding()
/// MediaQuery.of(context).viewInsets;'e benzer
context.mediaQueryViewInsets()
/// MediaQuery.of(context).orientation;'a benzer
context.orientation()
/// Cihazın yatay modda olup olmadığını kontrol eder.
context.isLandscape()
/// Cihazın dikey modda olup olmadığını kontrol eder.
context.isPortrait()
/// MediaQuery.of(context).devicePixelRatio;'ya benzer
context.devicePixelRatio()
/// MediaQuery.of(context).textScaleFactor;'e benzer
context.textScaleFactor()
/// Ekranın en kısa kenarını getirir
context.mediaQueryShortestSide()
/// width 800'den büyük ise true döndürür.
context.showNavbar()
/// Kısa kenar 600p'den küçük ise true döndürür.
context.isPhone()
/// Kısa kenar 600p'den büyük ise true döndürür.
context.isSmallTablet()
/// Kısa kenar 720p'den büyük ise true döndürür.
context.isLargeTablet()
/// Cihaz tablet ise true döndürür.
context.isTablet()
/// Ekran boyutuna göre <T> değerini döndürür
/// için değer verebilir:
/// watch: Kısa kenar 300'den küçük ise
/// mobile: Kısa kenar 600'den küçük ise
/// tablet: Kısa kenar 1200'den küçük ise
/// desktop: width 1200'den büyük ise
context.responsiveValue<T>()
```
### Opsiyonel Genel Ayarlar ve Manuel Ayarlamalar
GetMaterialApp çoğu şeyi sizin için otomatik olarak ayarlar, ayrıca kendiniz de isterseniz Get'i manuel olarak ayarlayabilirsiniz.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()],
);
```
`GetObserver` içinde kendi Middleware'ınızı kullanabilirsiniz ve bu hiçbir şeyi etkilemez.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer) // Burası
],
);
```
`Get` için _Global Settings_ oluşturabilirsiniz. Herhangi bir route'a push yapmadan önce kodunuza `Get.config` eklemeniz yeterli.
Ya da doğrudan `GetMaterialApp` içinde tanımlayabilirsiniz.
```dart
GetMaterialApp(
enableLog: true,
defaultTransition: Transition.fade,
opaqueRoute: Get.isOpaqueRouteDefault,
popGesture: Get.isPopGestureEnable,
transitionDuration: Get.defaultDurationTransition,
defaultGlobalState: Get.defaultGlobalState,
);
Get.config(
enableLog = true,
defaultPopGesture = true,
defaultTransition = Transitions.cupertino
)
```
İsteğe bağlı olarak tüm logging mesajlarını `Get` üzerinden yönlendirebilirsiniz.
Kendi istediğiniz logging paketinizi kullanmak
ve oradaki log'ları yakalamak istiyorsanız:
```dart
GetMaterialApp(
enableLog: true,
logWriterCallback: localLogWriter,
);
void localLogWriter(String text, {bool isError = false}) {
// istediğiniz logging paketine mesajı aktarır
// eğer, enableLog: false ise log mesajları bu callback içine gönderilir
// GetConfig.isLogEnable aracılığıyla isterseniz kontrol edebilirsiniz
}
```
### Local State Widgets (Yerel Durum Widgetları)
Bu widget'lar tek bir değeri kontrol etmenize ve durumu geçici ya da yerel olarak tutmanızı sağlar.
Reactive ve simple olan yapılar içerir.
Örneğin bunları `TextField` içindeki obscureText parametresine bağlayabilirsiniz. İsterseniz kendinizinkini (Expandable Panel vs.) de oluşturabilirsiniz ya da `Scaffold`'daki body'nin içeriği değişirken `BottomNavigationBar` içindeki current index'i değiştirebilirsiniz.
#### ValueBuilder
Veri güncellemenin bir yolu olan `StatefulWidget`'daki `.setState` yapısının basitleştirilmiş halidir.
```dart
ValueBuilder<bool>(
initialValue: false,
builder: (value, updateFn) => Switch(
value: value,
onChanged: updateFn, // tamamen aynısı! ( newValue ) => updateFn( newValue ) yapısını da kullanabilirsiniz
),
// eğer builder metodu dışından bir çağırma işlemi yapılacak ise
onUpdate: (value) => print("Value updated: $value"),
onDispose: () => print("Widget unmounted"),
),
```
#### ObxValue
[`ValueBuilder`](#valuebuilder)'a oldukça benzer olmasının yanında bu Reactive halidir. Rx nesnesine aktarabilir ( .obs yapısını hatıladınız mı?) ve otomatik olarak güncellenmensini sağlayabilirsiniz, resmen muhteşem değil mi ?
```dart
ObxValue((data) => Switch(
value: data.value,
onChanged: data, // Rx, çağrılabilen fonsyon içerir. (flag) => data.value = flag şeklinde kullanılablir.
),
false.obs,
),
```
## Faydalı Ipuçları
`.obs` yapıları olan gözlemlenebilirler ( _Rx_ tipleri olarak da bilinirler) oldukça çeşitli internal metodlara ve operatörlere sahiptirler.
> `.obs` yapısının gerçek değer olduğunu düşünenler oldukça yaygındır fakat bu yanlış bir düşüncedir.
> Değişkenleri, Type declaration yapmaktan kaçınmalıyız. Çünkü Dart'ın derleyicisi zaten bunu anlayacak kadar zekidir.
> Kodunuzu daha temiz gösterir fakat:
```dart
var message = 'Hello world'.obs;
print( 'Message "$message" has Type ${message.runtimeType}');
```
`message`, gerçek String Type değerini yazdırsa bile aslında bu bir **RxString** Type değeridir!
Yani `message.substring( 0, 4 )` şeklinde kullanmazsınız.
_observable_ içindeki gerçek `value`'ya (değere) erişmelisiniz.
En çok "kullanılan yol" `.value` yapısı ile erişmektir fakat şu şekilde kullanabileceğiniz bir yol daha var...
```dart
final name = 'GetX'.obs;
// eğer değer şimdikinden farklı ise, sadece stream'i "günceller"
name.value = 'Hey';
// Tüm Rx özellikleri "çağrılabilir" ve geriye yeni bir değer döndürür.
// Fakat bu yaklaşım `null` değerleri kabul etmez, sonucunda UI rebuild (tekrardan oluşturulmaz) edilmez.
name('Hello');
// getter yapmak gibi, 'Hello'yazdırır.
name() ;
/// numbers:
final count = 0.obs;
// Tüm non mutable (değişken olmayan) işlemleri num primitives üzerinden yapabilirsiniz.
count + 1;
// Dikkat edin! Bu sadece `count` değerinin 'final' olmayıp 'var' olduğu değerlerde mümkündür.
count += 1;
// Ayrıca değerleri kıyaslayabilirsiniz:
count > 2;
/// booleans:
final flag = false.obs;
// değer true/false arasında değişir.
flag.toggle();
/// tüm tipler için:
// "value"'ları null'a çevirir.
flag.nil();
// Tüm toString(), toJson() işlemleri `value`'ya aktarılır.
print( count ); // RxInt içinden `toString()` çağrılır.
final abc = [0,1,2].obs;
// Değeri bir json Array (dizi) yapısına çevirir ve RxList şeklinde yazdırır.
// Json tüm Rx tipleri tarafından desteklenir.
print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');
// RxMap, RxList ve RxSet kendi native tiplerinden extend edilen özel Rx tipleridir.
// Fakat List ile çalışmak normal listelerle çalışmak gibidir. Reaktiv olmasına rağmen.
abc.add(12); // '12' listeye eklenir ve stream GÜNCELLENİR.
abc[3]; // List'deki gibi 3. index okunur.
// Rx ve value ile çalışmak aynıdır fakat hashCode her zaman value'dan alınır.
final number = 12.obs;
print( number == 12 ); // çıktı: true
/// Özel Rx Modelleri:
// toJson(), toString() child'a gönderilir. Böylelikle override'ları onlara implement edebilirsiniz ve doğrudan gözlemlenebiliri print() edebilirsiniz.
class User {
String name, last;
int age;
User({this.name, this.last, this.age});
@override
String toString() => '$name $last, $age years old';
}
final user = User(name: 'John', last: 'Doe', age: 33).obs;
// `user`,"reactive" yapıdadır. Fakat içinde özellikleri DEĞİLDİR.
// Yani eğer içindeki bazı değerleri değiştirirsek
user.value.name = 'Roi';
//widget, rebuild olmayacaktır!,
//`Rx`, user içindeki bir şeyi değiştirdiğinizde, bundan haberi olmayacaktır.
// Özel sınıflar oluşturmak için, manuel olarak değişiklikleri "notify" etmeliyiz.
user.refresh();
// Ya da `update()` metodunu kullanabiliriz
user.update((value){
value.name='Roi';
});
print( user );
```
## StateMixin
`UI` state ile başa çıkmanın başka bir yolu da `StateMixin<T>` kullanmaktır.
Bunu implement yapmak için, controller'ınıza `with` kullanarak yanına `StateMixin<T>` eklemekle olur.
Bu sizin T modelini kullanmanızı sağlar.
``` dart
class Controller extends GetController with StateMixin<User>{}
```
`change()` metodu istediğiniz yerde State'i değiştirmemizi sağlar.
Veri(data) ve durum(status) aktarmak için kullanılan yol:
```dart
change(data, status: RxStatus.success());
```
RxStatus şu durumları kullanmanızı sağlar:
``` dart
RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('message');
```
UI'ın içinde temsil edilmesi için şu şekilde kullanılır:
```dart
class OtherClass extends GetView<Controller> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller.obx(
(state)=>Text(state.name),
// Kendi yüklenme göstergenizi (loading indicator) buraya eklebilirsiniz
// hali hazırda gelen yapı şudur: Center(child:CircularProgressIndicator())
onLoading: CustomLoadingIndicator(),
onEmpty: Text('No data found'),
// Keni hata widget'ınızı buraya yazabilirsiniz
// hali hazırda gelen yapı şudur: Center(child:Text(error))
onError: (error)=>Text(error),
),
);
}
```
#### GetView
Bu widget'ı çok seviyorum, oldukça basit ve çok kullanışlı!
`const Stateless` Widget, `Controller`'ı tanımlamak için `controller` özelliği içerir.
```dart
class AwesomeController extends GetController {
final String title = 'My Awesome View';
}
// controller'ınızı register etmek için bunu kullandığınız `Type`'a geçirmeyi asla unutmayın.
class AwesomeView extends GetView<AwesomeController> {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Text(controller.title), // sadece `controller.something` deyin
);
}
}
```
#### GetResponsiveView
Responsive view oluşturmak için bu widget'tan extend edilir.
Bu widget ekran size ve type hakkında bilgiler içeren
`screen` özelliğini taşır.
##### Nasıl kullanılır?
build yapmanız için 2 yönteminiz vardır.
- build yapmak için `builder` metodu ile widget döndürmek
- `desktop`, `tablet`,`phone`, `watch` metodları ile
bu özel metodlar ekran türü bu metodlarla eşitlendiiği zaman build metodunu tetikler.
Mesela ekran [ScreenType.Tablet] ise `tablet` metodu çalışrıtılacaktır.
**Not:** Eğer bu metodu kullanırsanız, lütfen `alwaysUseBuilder` özelliğini `false` olarak işaretleyin.
`settings` özelliği sayesinde ekranın türüne göre genişlik limiti koyabilirsiniz.
![örnek](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)
Bu ekranın kodları
[burada](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)
#### GetWidget
Çoğu kişinin widget'lar hakkında hiçbir fikri yok ya da kullanırken inanılmaz kafası karışıyor.
Bu kullanım oldukça nadir fakat özel: Controller `caches`'leme işlemi _cache_ yüzünden asla bir `const Stateless` oluşamaz.
> Peki ne zaman Controller'ı "cache"'yemeye ihtiyacınız olacak?
"Çok da yaygın olmayan" bir **GetX** özelliğini kullanıyorsanız: `Get.create()`.
`Get.create(()=>Controller())` yapısı siz her `Get.find<Controller>()` dediğinizde size yeni bir `Controller` oluşturacak.
`GetWidget`'ın ışığı burada parlıyor. Örnek olarak bir listede
Todo ögelerini tutmak istiyorsanız kullanılır. Eğer widget'ın "rebuilt" olursa, yapı yine aynı controller nesnesini tutmaya devam edecektir.
#### GetxService
Bu sınıf `GetxController`' bezer. Uygulamanın lifecycle'larını (hayat döngüsü metodlarını) içerir ( `onInit()`, `onReady()`, `onClose()`).
Fakat içinde hiçbir mantıksal yapı bulunmaz. Sadece **GetX**'in Dependency Injection sistemini bilgilendirir.
Bunun alt sınıfları, memory (bellekten) hiçbir şekilde **kaldırılamaz**.
Bu yöntem "Servislerinizi" tutmak için oldukça kullanışlıdır. Servisleriniz bu şekilde her zaman ulaşılabilir ve aktif olur. `Get.find()` metodu buna yeter. Örnek olarak:`ApiService`, `StorageService`, `CacheService`.
```dart
Future<void> main() async {
await initServices(); /// SERVİSLERİN BAŞLATILMASI BEKLENİR
runApp(SomeApp());
}
/// Servislerinizi Flutter uygulaması çalışmadan önce başlatılması oldukça mantıklı bir harekettir.
/// Uygulama akışını kontrol edebilirsiniz. (belki de birkaç tane Tema düzenlemesi ya da
/// apiKey, kulllanıcıdan gelen dil tanımlaması gibi düzenlemeler yapmanız lazımdır...Bu durumna SettingService'i ApiService'den önce çalışması gerekmektedir.
/// GetMaterialApp() 'in rebuild yapmasına gerek yoktur. Çünkü değerleri doğrudan alır.
void initServices() async {
print('starting services ...');
/// Burası sizin get_storage, hive, shared_pref gibi yükelemeleri yaptığınız yer.
/// ya da daha fazla özellik bağlamak ve ya async yapıları kullanmak için
await Get.putAsync(() => DbService().init());
await Get.putAsync(SettingsService()).init();
print('All services started...');
}
class DbService extends GetxService {
Future<DbService> init() async {
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
}
}
class SettingsService extends GetxService {
void init() async {
print('$runtimeType delays 1 sec');
await 1.delay();
print('$runtimeType ready!');
}
}
```
`GetxService`'lerini silmenin tek bir yolu vardır o da `Get.reset()`.
Bu yöntem uygulamanıza "Hot Reboot" yapmak gibidir. Eğer uygulamanızın hayat süresi boyunca mutlaka kalıcılığı olmasını istediğiniz bir sınıfın nesnesini oluşturmak istediğiniz zaman `GetxService`'i kullanın.
### Testler
Controller'larınızı lifecycle'ları (hayat döngüleri) dahil olmak üzere diğer sınıflar gibi test edebilirsiniz:
```dart
class Controller extends GetxController {
@override
void onInit() {
super.onInit();
//Değeri name2 ile değiştirme
name.value = 'name2';
}
@override
void onClose() {
name.value = '';
super.onClose();
}
final name = 'name1'.obs;
void changeName() => name.value = 'name3';
}
void main() {
test('''
Test the state of the reactive variable "name" across all of its lifecycles''',
() {
/// Controller'ınızı lifecycle dışında test edebilirsiniz.
/// Fakat bunu GetX dependency injection kullanmadığınız taktirde
/// kullanmanız önerilmiyor.
final controller = Controller();
expect(controller.name.value, 'name1');
/// Eğer kullanıyorsanı istediğiniz her şeyi test edebilirsiniz.
/// Her lifecycle sonrası uygulamanızın durumu dahil olmak üzere.
Get.put(controller); // onInit çağrıldıktan sonra
expect(controller.name.value, 'name2');
/// Bu fonksoynu test edin
controller.changeName();
expect(controller.name.value, 'name3');
/// onClose çağrıldıktan sonra
Get.delete<Controller>();
expect(controller.name.value, '');
});
}
```
#### Ipuçları
##### Mockito or mocktail
Eğer GetxController/GetxService'inizi mock yapmaya ihtiyacınız varsa GetxController'dan extend etmeniz ve Mock ile mixin'lemelisiniz.
```dart
class NotificationServiceMock extends GetxService with Mock implements NotificationService {}
```
##### Using Get.reset()
Eğer widget'ları ya da widget grupllarını test etmek istiyorsanız, testinizin sonunda Get.reset'i kullanın ya da önceki testinizden kalma tüm ayarları sıfırlayın.
##### Get.testMode
Eğer controller'larınızın içinden navigation kullanmak istiyorsanız. Main'den önce `Get.testMode = true` şeklinde kullanın.
# 2.0 Ile Gelen Büyük Değişiklikler
1- Rx Types :
| Önce | Sonra |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
| MapX | `RxMap` |
| ListX | `RxList` |
| NumX | `RxNum` |
| DoubleX | `RxDouble` |
RxController ve GetBuilder şimdi birleştiler. Artık hangi controller'ı kullanmak istediğinizi hatırlamak zorunda değilsiniz. SAdece GetxController diyerek halledin. Bu simple state management ve reactive ile düzgün çalışacaktır.
2- NamedRoutes
Önce:
```dart
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
```
Şimdiki:
```dart
GetMaterialApp(
getPages: [
GetPage(name: '/', page: () => Home()),
]
)
```
Neden bu değişiklik?
Genellikle, hangi sayfanın bir parametreden görüntüleneceğine veya bir giriş belirteciden görüntüleneceğine karar vermek gerekebilir, önceki yaklaşım buna izin vermediği için esnek değildi.
Sayfayı bir fonksiyona sokmak, RAM tüketimini önemli ölçüde azaltır, çünkü rotalar uygulama başlatılmasından bu yana belleğe tahsis edilmeyecek ve aynı zamanda bu tür bir yaklaşım yapmasına izin verilmeyecek:
```dart
GetStorage box = GetStorage();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
```
# Neden Getx?
1- Birçok kez Flutter güncellendikten sonra, birçok paket çalışmaz hale gelecek. Genelde derleme hataları gerçekleşir. Bu hataların hala cevabı olmayabilir. Geliştiricinin bu hatanın nerden geldiğini bilmesi gereklidir. Sonrasında bu hatayı izleyip bunun hakkında repository'de issue açması ve sorunun çözülmesini beklemelidir. Get, geliştirme için gereken ana kaynaklarını (State, dependency ve route management) merkezde toplar, pubspec'e tek bir paket eklemeye izin verir ve çalışmaya başlar. Flutter güncellendikten sonra tek yapmanız gereken Get dependency'yi güncellemek ve çalışmaya başlamaktır. Get uyumluluk problemlerini de çözer. Paketler arasında genelde güncellemeler sonrası uyumsuzluklar olabilir. Get'in kendi içinde her şey birbiri ile uyumlu olduğundan bunun için endişelenmenize gerek yoktur.
2- Flutter oldukça kolay kullanımı olan inanılmaz olmasının yanı sıra birçok geliştirici tarafından istenmeyen `Navigator.of(context).push (context, builder [...]` gibi ezber yapılar içerir. Get geliştirmeyi basitleştirir. Route çağırmak için 8 kod yazmak yerine sadece `Get.to(Home())` diyerek bir sonraki sayfaya geçebilirsin. Dynamic web urls ile çalışmak mevcut Flutter ile çalışırken zorlayıcı olabilir. Get ile durum tam tersi hal alır ve işleri çok kolay bir hale getirir. Flutter'da State'leri yönetmek için dependency'leri pub içerindeki yüzlerce kütüphane arasından seçmek birçok tartışmayı da beraberinde getiren bir konudur. Get sayesinde ekranda değişkeni otomatik olarak güncellemesini sağlamak için değişkeninizin sonuna ".obs" eklemek ve widget'ınızı Obx ile sarmalamak yeterlidir.
3- Performansı kafaya takmayın. Flutter'ın performansı zaten çok iyi. Bir de state manager kullanırken ve blocs/stores/controllers gibi sınıflarınızı locator ile yönetirken de aynı performansı aldığınızı düşünün. İhtiyacınız olmadığında dependency'lerinizi dışarıdan çağırmak zorunda kalacaksınız. Hiç düşündünüz mü, basitçe kullandığınız controller'ınızın artık kimse tarafından kullanılmadığında kolayca bellekten silindiğini? İşte GetX bunu yapar. SmartManagement sayesinde kullanılmayan her şey endişelenmenize gerek kalmadan otomatik olarak hafızadan silinir. Bunun için bir logic yaratmaya gerek bile kalmadan, kaynakları minimum ölçüde tükettiğinize emin olabilirsiniz.
4- Gerçek ayrıştırma: "View ile the business logic (iş mantığını) birbirlerinden ayırmak" kavramını duymuş olabilirsiniz. Bu sadece BLoC, MVC, MVVM'ye özgü bir özellik değildir, piyasadaki diğer standart tasarım desenlerinde de mevcuttur. Ancak bu kavram Flutter'da context kullanımına bağlı olarak kolaylaştırılabilir.
Bir InheritedWidget bulabilmek için context'e ihtiyaç duyduğunuzda, bunu view'da yapmalı ya da parametre ile aktarmalıyız. Ben bu yöntemi oldukça çirkin buluyorum. Ayrıca bir ekip ile çalışırken View'daki iş mantığına hep bağımlı olacağız. GetX standart yaklaşımı benimsemez ve StatefulWidgets, InitState, vb. yapılarını tamamen ortadan kaldırmaz. Daha temiz bir yaklaşım sunar. Controller'ların yaşam döngüleri vardır. Mesela APIREST talebi yaptığında view'a bağlı olmak zorunda değilsin. Http çağrısı başlatmak için "onInit" kullanabilirsiniz. Veriler geldiğinde yerleştirilecektir. GEtX tamamen reaktif (cidden,stream'lerin altında çalışır) olduğu için tüm item'lar doldurulduğunda o değişkeni kullanan tüm widget'lar view'da otomatik olarak güncellenecektir. Bu UI uzmanlığına sahip kişilerin sadece widget'larla çalışmasını sağlar ve kullanıcı etkinlikleri dışında iş mantığına hiçbir şey göndermek zorunda değildir (bir düğmeye tıklamak gibi). İş mantığı ile çalışan insanlar, bunu ayrı olarak oluşturmak ve test etmek konusunda serbest olacaktır.
Bu kütüphane her zaman güncellenebilir ve yeni özellikler eklenebilir olacaktır. PR ve contribute yapmakta tamamen özgürsünüz.
# Topluluk
## Topluluk Kanalları
GetX oldukça aktif ve yardımsever bir topluluğa sahiptir. Bu framework kullanımıyla ilgili sorularınız varsa veya herhangi bir yardım istiyorsanız, lütfen topluluk kanallarımıza katılın, sorunuz daha hızlı yanıtlanacak ki bunun için en uygun yer burasıdır. Repository'de issues açabilir ve kaynak talep edebilirsiniz. GetX topluluğunun bir parçası olmaktan çekinmeyin.
| **Slack** | **Discord** | **Telegram** |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) |
## Nasıl katkıda bulunulur?
_Projeye katkıda bulunmak ister misiniz? Sizi destekçilerimizden biri olarak öne çıkarmaktan gurur duyacağız. İşte katkıda bulunabileceğiniz ve Get'i (ve Flutter'ı) daha da iyi hale getirebileceğiniz bazı noktalar._
- Readme dosyasının diğer dillere çevrilmesine yardımcı olmak.
- Readme'ye dokümanlar eklemek (birçok Get fonsyonu henüz belgelenmedi).
- Get'in kullanımını öğretmek için makaleler yazabilir ya da videolar çekebilirsiniz (Bunlar Readme ve gelecekte Wiki'ye eklenecek).
- Kod ve test PR'ları önermek.
- Yeni fonksiyonlar eklemek.
Her türlü yardım için teşekkürler.
## Makaleler ve videolar
- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).
- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).
- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.
- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.
- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.
- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.
- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.
- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman).
- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Dependency Injection by [Aachman Garg](https://github.com/imaachman).
- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation by Thad Carnevalli.
- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli.
- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.
- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)
... ...
# Dependency Management
- [Dependency Management](#dependency-management)
- [Örnek Metodlar](#örnek-metodlar)
- [Get.put()](#getput)
- [Get.lazyPut](#getlazyput)
- [Get.putAsync](#getputasync)
- [Get.create](#getcreate)
- [Metodların/Sınıfların örneklerinin kullanılması](#metodların/sınıfların-örneklerinin-kullanılması)
- [Alternatif bir instance tanımlama](#alternatif-bir-instance-tanımlama)
- [Metodlar arasındaki farklılıklar](#metodlar-arasındaki-farklılıklar)
- [Bindings](#bindings)
- [Bindings class](#bindings-class)
- [BindingsBuilder](#bindingsbuilder)
- [SmartManagement](#smartmanagement)
- [Nasıl değiştirilir?](#nasıl-değiştirilir)
- [SmartManagement.full](#smartmanagementfull)
- [SmartManagement.onlyBuilder](#smartmanagementonlybuilder)
- [SmartManagement.keepFactory](#smartmanagementkeepfactory)
- [Nasıl bindings yapılır?](#nasıl-bindings-yapılır)
- [Notlar](#notlar)
Get, yalnızca 1 satır kodla, Provider context'i olmadan, inheritedWidget olmadan Bloc veya Controller ile aynı sınıfı almanızı sağlayan basit ve güçlü bir dependency manager'a (bağımlılık yöneticisine) sahiptir:
```dart
Controller controller = Get.put(Controller()); // Rather Controller controller = Controller();
```
Sınıfınızı kullandığınız sınıf içinde somutlaştırmak yerine, onu uygulamanız genelinde kullanılabilir hale getirecek olan Get örneğinde somutlaştırıyorsunuz.
Böylece denetleyicinizi (veya Bloc sınıfını) normal şekilde kullanabilirsiniz.
- Not: Get's State Manager kullanıyorsanız, view'e controller'ı bağlamayı kolaylaştıracak olan [Bindings](#bindings) API'sine daha fazla dikkat edin.
- Not²: Get dependency management (bağımlılık yönetimi) paketin diğer bölümlerinden ayrılmıştır, bu nedenle örneğin uygulamanız zaten bir state manager (durum yöneticisi) kullanıyorsa (herhangi biri, önemli değil), bunu değiştirmeniz gerekmez, dependency injection (bağımlılık enjeksiyonunu) kullanabilirsiniz.
## Örnek metodlar
Metodlar ve configurable parameters (yapılandırılabilir parametreleri) şunlardır:
### Get.put()
Dependency (bağımlılık) eklemenin en yaygın yolu. Örneğin;
```dart
Get.put<SomeClass>(SomeClass());
Get.put<LoginController>(LoginController(), permanent: true);
Get.put<ListItemController>(ListItemController, tag: "some unique string");
```
Put kullanırken ayarlayabileceğiniz tüm seçenekler şunlardır:
```dart
Get.put<S>(
// Zorunlu: Controller veya herhangi bir şey gibi kaydetmek istediğiniz sınıf
// not: "S", herhangi bir türde bir sınıf olabileceği anlamına gelir
S dependency
// isteğe bağlı: bu, aynı türden birden çok sınıf içindir
// normalde Get.find<Controller>() kullanarak bir sınıf aldığınız için,
// hangi örneğe ihtiyacınız olduğunu söylemek için "tag" kullanmanız gerekir
// benzersiz dize olmalıdır
String tag,
// isteğe bağlı: varsayılan olarak, get artık kullanılmadıktan sonra örnekleri elden çıkarır (örneğin,
// gizli bir view'in controller'ı), ancak instance'a ihtiyacınız olabilir
// tüm uygulama boyunca orada tutulacak, Shared Preferences örneği veya başka bir şey gibi
// yani bunu kullanıyorsun
// varsayılan olarak false
bool permanent = false,
// isteğe bağlı: bir testte abstract(soyut) bir sınıf kullandıktan sonra, onu başka bir sınıfla değiştirmenize ve testi takip etmenize olanak tanır.
// varsayılan olarak false
bool overrideAbstract = false,
// optional: allows you to create the dependency using function instead of the dependency itself.
//isteğe bağlı: dependency'nin(bağımlılığın) kendisi yerine fonksiyonu kullanarak dependency(bağımlılık) oluşturmanıza olanak tanır.
//bu yaygın olarak kullanılmaz
InstanceBuilderCallback<S> builder,
)
```
### Get.lazyPut
Bir bağımlılığı lazyLoad ile yalnızca kullanıldığında somutlaştırılacak şekilde yüklemek mümkündür. Hesaplamalı expensive sınıflar için veya birkaç sınıfı tek bir yerde başlatmak istiyorsanız (Bindings sınıfında olduğu gibi) çok kullanışlıdır ve o zaman o sınıfı kullanmayacağınızı bilirsiniz.
```dart
/// ApiMock yalnızca Get.find<ApiMock>'u ilk kez kullandığında çağrılacak
Get.lazyPut<ApiMock>(() => ApiMock());
Get.lazyPut<FirebaseAuth>(
() {
// ... gerekirse biraz mantık
return FirebaseAuth();
},
tag: Math.random().toString(),
fenix: true
)
Get.lazyPut<Controller>( () => Controller() )
```
lazyPut'u kullanırken ayarlayabileceğiniz tüm seçenekler şunlardır:
```dart
Get.lazyPut<S>(
// zorunlu: sınıfınız ilk kez çağrıldığında yürütülecek bir yöntem
InstanceBuilderCallback builder,
// isteğe bağlı: Get.put() ile aynı, aynı sınıfın birden çok farklı örneğini istediğinizde kullanılır
// unique olmalı
String tag,
// isteğe bağlı: "Kalıcı" ile benzerdir, aradaki fark, instance şu durumlarda atılmasıdır.
// kullanılmıyor, ancak tekrar kullanılması gerektiğinde Get, instance yeniden oluşturacak
//bindings api'sindeki "SmartManagement.keepFactory" ile aynı
// varsayılan olarak false
bool fenix = false
)
```
### Get.putAsync
Eşzamansız bir instance kaydetmek istiyorsanız, `Get.putAsync` kullanabilirsiniz:
```dart
Get.putAsync<SharedPreferences>(() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('counter', 12345);
return prefs;
});
Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )
```
putAsync kullanırken ayarlayabileceğiniz tüm seçenekler şunlardır:
```dart
Get.putAsync<S>(
// zorunlu: sınıfınızın instance'ını oluşturmak için yürütülecek bir asenkron metod
AsyncInstanceBuilderCallback<S> builder,
//isteğe bağlı: Get.put() ile aynı, aynı sınıfın birden çok farklı örneğini istediğinizde kullanılır
// unique olmalı
String tag,
// isteğe bağlı: Get.put() ile aynı, bu instance tüm uygulamada canlı tutmanız gerektiğinde kullanılır
// varsayılan olarak false
bool permanent = false
)
```
### Get.create
Bu zor. Bunun ne olduğuna ve diğeri arasındaki farklara ilişkin ayrıntılı bir açıklama, [Differences between methods:](#differences-between-methods) bölümünde bulunabilir.
```dart
Get.Create<SomeClass>(() => SomeClass());
Get.Create<LoginController>(() => LoginController());
```
Oluştururken ayarlayabileceğiniz tüm seçenekler şunlardır:
```dart
Get.create<S>(
// gerekli: her seferinde "fabrikasyon" olacak bir sınıf döndüren bir işlev
// `Get.find()` çağrılır
// Örnek: Get.create<YourClass>(() => YourClass())
FcBuilderFunc<S> builder,
// isteğe bağlı: tıpkı Get.put() gibi, ancak birden çok örneğe ihtiyacınız olduğunda kullanılır
// aynı sınıftan bir
// Her öğenin kendi denetleyicisine ihtiyaç duyduğu bir listeniz varsa kullanışlıdır
// benzersiz bir dize olması gerekir.
String name,
// isteğe bağlı: tıpkı int`Get.put()` gibi,
// tüm uygulama boyunca canlı örnek. Fark Get.create'de
// kalıcı, varsayılan olarak doğrudur
bool permanent = true
```
## Metodların/Sınıfların örneklerinin kullanılması
Çok sayıda rotada gezindiğinizi ve kontrol cihazınızda geride bırakılan bir veriye ihtiyacınız olduğunu hayal edin, Sağlayıcı veya Get_it ile birleştirilmiş bir durum yöneticisine ihtiyacınız olacak, değil mi? Get ile değil. Controller için "find" seçeneğini sormanız yeterlidir, herhangi bir ek bağımlılığa ihtiyacınız yoktur:
```dart
final controller = Get.find<Controller>();
// veya
Controller controller = Get.find();
// Evet, sihir gibi görünüyor, Controller'ı(Denetleyicinizi) bulacak ve size teslim edecek.
// Instance edilmiş 1 milyon controller'a sahip olabilirsiniz, Get size her zaman doğru controller'ı verecektir.
```
Ve sonra orada elde edilen controller ile verilerinizi kurtarabileceksiniz:
```dart
Text(controller.textFromApi);
```
Döndürülen değer normal bir sınıf olduğundan, istediğiniz her şeyi yapabilirsiniz:
```dart
int count = Get.find<SharedPreferences>().getInt('counter');
print(count); // out: 12345
```
Get örneğini kaldırmak için:
```dart
Get.delete<Controller>(); //genellikle bunu yapmanız gerekmez çünkü GetX kullanılmayan controller'ları(denetleyicileri) zaten siler
```
## Alternatif bir instance tanımlama
Şu anda eklenen bir örnek, `replace` veya `lazyReplace` yöntemi kullanılarak benzer veya genişletilmiş bir sınıf örneğiyle değiştirilebilir. Bu daha sonra özgün sınıf kullanılarak alınabilir.
```dart
abstract class BaseClass {}
class ParentClass extends BaseClass {}
class ChildClass extends ParentClass {
bool isChild = true;
}
Get.put<BaseClass>(ParentClass());
Get.replace<BaseClass>(ChildClass());
final instance = Get.find<BaseClass>();
print(instance is ChildClass); //true
class OtherClass extends BaseClass {}
Get.lazyReplace<BaseClass>(() => OtherClass());
final instance = Get.find<BaseClass>();
print(instance is ChildClass); // false
print(instance is OtherClass); //true
```
## Metodlar arasındaki farklılıklar
İlk olarak Get.lazyPut'un `fenix`i ve diğer yöntemlerin `permanent`'larından bahsedelim.
`permanent` ve `fenix` arasındaki temel fark, örneklerinizi nasıl depolamak istediğinizdir.
Güçlendirme: Varsayılan olarak GetX, kullanımda değilken örnekleri siler.
Bunun anlamı: Ekran 1'de controller 1 varsa ve ekran 2'de controller 2 varsa ve ilk rotayı stackten kaldırırsanız (`Get.off()` veya `Get.offNamed()` kullanıyorsanız) controller(denetleyici) 1 kaybolur kullanımı silinecektir.
Ancak `permanent:true` kullanmayı tercih etmek istiyorsanız, bu geçişte controller kaybolmaz - bu, tüm uygulama boyunca canlı tutmak istediğiniz hizmetler için çok yararlıdır.
`fenix`ise ekran değişiklikleri arasında kaybetme endişesi duymadığınız ancak o hizmete ihtiyaç duyduğunuzda canlı olmasını beklediğiniz hizmetler içindir. Temel olarak, kullanılmayan controller/service/class elden çıkaracak, ancak ihtiyacınız olduğunda yeni bir örneği "küllerden yeniden yaratacaktır".
Metodlar arasındaki farklarla devam edelim:
- Get.put ve Get.putAsync, ikincisinin eşzamansız bir yöntem kullanması farkıyla aynı oluşturma sırasını takip eder: bu iki yöntem, örneği oluşturur ve başlatır. Bu, `permanent: false` ve `isSingleton: true` parametreleriyle `insert` dahili yöntemi kullanılarak doğrudan belleğe eklenir (bu isSingleton parametresinin tek amacı, "bağımlılık" bağımlılığını kullanıp kullanmayacağını söylemektir. veya `FcBuilderFunc` bağımlılığını kullanacaksa). Bundan sonra, bellekteki örnekleri hemen başlatan `Get.find()` çağrılır.
- Get.create: Adından da anlaşılacağı gibi, dependency'i (bağımlılığı) "create(oluşturacak)"! `Get.put()`a benzer şekilde, örneklemeye `insert` dahili yöntemini de çağırır. Ancak `permanent` doğru oldu ve`isSingleton` yanlış oldu (bağımlılığımızı "creating", bunun tek bir örnek olmasının bir yolu yok, bu yüzden yanlış). Ve `permanent: true` olduğu için, varsayılan olarak ekranlar arasında kaybetmeme avantajına sahibiz! Ayrıca `Get.find()` hemen çağrılmaz, çağrılacak ekranda kullanılmayı bekler. `permanent` parametresini kullanmak için bu şekilde yaratılmıştır, o zamandan beri, fark edilmeye değer `Get.create()`, örneğin bir bu liste için benzersiz bir örnek istiyorsanız - bu nedenle Get.create GetWidget ile birlikte kullanılmalıdır.
- Get.lazyPut: Adından da anlaşılacağı gibi tembel bir işlemdir. Örnek yaratılır, ancak hemen kullanılmak üzere çağrılmaz, çağrılmayı bekler. Diğer yöntemlerin aksine burada `insert` denilmez. Bunun yerine, instance hafızanın başka bir bölümüne, örneğin yeniden oluşturulup oluşturulamayacağını söylemekle sorumlu bir kısma eklenir, buna "factory" diyelim. Daha sonra kullanılmak üzere bir şey yaratmak istersek, şu anda kullanılanlarla karıştırılmayacak. Ve işte burada `fenix` sihirleri devreye giriyor: `fenix: false` bırakmayı seçerseniz ve `smartManagement`ınız `keepFactory` değilse, o zaman `Get.find` kullanılırken örnek bellekteki yeri değiştirecektir. "factory"den ortak örnek bellek alanına. Bundan hemen sonra, varsayılan olarak "factory"den kaldırılır. Şimdi, `fenix: true` seçeneğini seçerseniz, örnek bu özel bölümde var olmaya devam eder, hatta gelecekte tekrar çağrılmak üzere ortak alana gider.
## Bindings
Bu paketin en büyük farklılıklarından biri, belki de route'ların, state manager'in(durum yöneticisinin) ve dependency manager(bağımlılık yöneticisinin) tam entegrasyonu olasılığıdır.
Stackten bir rota kaldırıldığında, onunla ilgili tüm controller'lar, değişkenler ve nesne örnekleri bellekten kaldırılır. Streams(Akışlar) veya timers(zamanlayıcılar) kullanıyorsanız, bunlar otomatik olarak kapatılır ve bunların hiçbiri için endişelenmenize gerek yoktur.
2.10 sürümünde Bindings API'sini tamamen uygulayın.
Artık init metodunu kullanmanıza gerek yok. İstemiyorsanız controller yazmanız bile gerekmez. Bunun için uygun yerde controller ve servislerinizi başlatabilirsiniz.
Binding sınıfı, state manager(durum yöneticisine) ve dependency manager(bağımlılık yöneticisine) giden rotaları "binding" ederken, dependency injection(bağımlılık enjeksiyonunu) ayıracak bir sınıftır.
Bu, belirli bir controller(denetleyici) kullanıldığında hangi ekranın görüntülenmekte olduğunu ve bunun nerede ve nasıl imha edileceğini bilmenizi sağlar.
Ayrıca Binding sınıfı, SmartManager yapılandırma kontrolüne sahip olmanızı sağlar. Stackten bir rota kaldırılırken veya onu kullanan pencere öğesi düzenlendiğinde veya hiçbirini yapmadığında düzenlenecek bağımlılıkları yapılandırabilirsiniz. Sizin için çalışan intelligent dependency management(akıllı bağımlılık yönetimine) sahip olacaksınız, ancak buna rağmen istediğiniz gibi yapılandırabilirsiniz.
### Bindings class
- Bir sınıf oluşturun ve Binding'i uygulayın
```dart
class HomeBinding implements Bindings {}
```
IDE'niz otomatik olarak sizden "dependencies(bağımlılıklar)" metodunu geçersiz kılmanızı isteyecektir ve sadece lambaya tıklamanız, metodu geçersiz kılmanız ve o rotada kullanacağınız tüm sınıfları eklemeniz yeterlidir:
```dart
class HomeBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<HomeController>(() => HomeController());
Get.put<Service>(()=> Api());
}
}
class DetailsBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<DetailsController>(() => DetailsController());
}
}
```
Şimdi sadece rotanızı, route manager(rota yöneticisi), dependencies(bağımlılıklar) ve states(durumlar) arasında bağlantı kurmak için bu binding'i kullanacağınızı bildirmeniz gerekiyor.
- Adlandırılmış yolları kullanma:
```dart
getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: HomeBinding(),
),
GetPage(
name: '/details',
page: () => DetailsView(),
binding: DetailsBinding(),
),
];
```
- Normal yolları kullanma:
```dart
Get.to(Home(), binding: HomeBinding());
Get.to(DetailsView(), binding: DetailsBinding())
```
Orada, artık uygulamanızın bellek yönetimi konusunda endişelenmenize gerek yok, Get bunu sizin için yapacak.
Bir rota çağrıldığında Binding sınıfı çağrılır, oluşturulacak tüm bağımlılıkları eklemek için GetMaterialApp'ınızda bir "initialBinding" oluşturabilirsiniz.
```dart
GetMaterialApp(
initialBinding: SampleBind(),
home: Home(),
);
```
### BindingsBuilder
Binding oluşturmanın varsayılan yolu, Binding'leri uygulayan bir sınıf oluşturmaktır.
Ancak alternatif olarak, istediğiniz her şeyi somutlaştırmak için bir işlevi kullanabilmeniz için `BindingsBuilder` callback kullanabilirsiniz.
Örnek:
```dart
getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: BindingsBuilder(() {
Get.lazyPut<ControllerX>(() => ControllerX());
Get.put<Service>(()=> Api());
}),
),
GetPage(
name: '/details',
page: () => DetailsView(),
binding: BindingsBuilder(() {
Get.lazyPut<DetailsController>(() => DetailsController());
}),
),
];
```
Bu şekilde, her rota için bir Binding sınıfı oluşturmaktan kaçınarak bunu daha da basitleştirebilirsiniz.
Her iki şekilde de gayet iyi çalışıyor ve zevkinize en uygun olanı kullanmanızı istiyoruz.
### SmartManagement
GetX, bir hata oluşsa ve onu kullanan bir pencere öğesi düzgün şekilde atılmamış olsa bile, varsayılan olarak kullanılmayan controller(denetleyicileri) bellekten atar.
Bu, `full` dependency management(bağımlılık yönetimi) modu olarak adlandırılan şeydir.
Ancak GetX'in sınıfların imhasını kontrol etme şeklini değiştirmek istiyorsanız, farklı davranışlar ayarlayabileceğiniz `SmartManagement` sınıfınız var.
#### Nasıl değiştirilir?
Bu yapılandırmayı (genellikle ihtiyacınız olmayan) şekilde değiştirmek istiyorsanız:
```dart
void main () {
runApp(
GetMaterialApp(
smartManagement: SmartManagement.onlyBuilder //burada
home: Home(),
)
)
}
```
#### SmartManagement.full
Varsayılan olanıdır. Kullanılmayan ve kalıcı olarak ayarlanmamış sınıfları dispose edin. Çoğu durumda, bu yapılandırmayı el değmeden tutmak isteyeceksiniz. Eğer Get için yeniyseniz, bunu değiştirmeyin.
#### SmartManagement.onlyBuilder
Bu seçenekle, yalnızca `init:` ile başlatılan veya `Get.lazyPut()` ile bir Binding'e yüklenen controller(denetleyiciler) dispose edilecektir.
`Get.put()` veya `Get.putAsync()` veya başka bir yaklaşım kullanırsanız, SmartManagement bu bağımlılığı dışlamak için izinlere sahip olmayacaktır.
Varsayılan davranışla, SmartManagement.onlyBuilder'ın aksine "Get.put" ile örneklenen widget'lar bile kaldırılacaktır.
#### SmartManagement.keepFactory
SmartManagement.full gibi, artık kullanılmadığında bağımlılıklarını kaldıracaktır. Ancak, factory'leri koruyacak, yani bu örneğe tekrar ihtiyacınız olursa dependency(bağımlılığı) yeniden yaratacaktır.
### Nasıl bindings yapılır?
Bindings, başka bir ekrana gitmek için tıkladığınız anda oluşturulan geçici factory'ler oluşturur ve ekran değişirken animasyon gerçekleşir gerçekleşmez yok edilir.
Bu o kadar hızlı gerçekleşir ki analyzer onu kaydedemez bile.
Bu ekrana tekrar gittiğinizde, yeni bir geçici factory çağrılır, bu nedenle SmartManagement.keepFactory kullanmak yerine bu tercih edilir, ancak Bindings oluşturmak istemiyorsanız veya tüm bağımlılıklarınızı aynı Binding üzerinde tutmak istiyorsanız, mutlaka size yardımcı olacaktır.
Factory'ler çok az bellek kaplarlar, örnekleri tutmazlar, ancak istediğiniz sınıfın "shape" olan bir fonksiyona sahiptirler.
Bunun bellekte maliyeti çok düşüktür, ancak bu kitaplığın amacı, minimum kaynakları kullanarak mümkün olan maksimum performansı elde etmek olduğundan, Get factory bile varsayılan olarak kaldırır.
Hangisi sizin için daha uygunsa onu kullanın.
## Notlar
- Birden çok Bindings kullanıyorsanız SmartManagement.keepFactory KULLANMAYIN. Bindings olmadan veya GetMaterialApp'in initialBinding'inde bağlantılı tek bir Binding ile kullanılmak üzere tasarlanmıştır.
- Bindings kullanmak tamamen isteğe bağlıdır, isterseniz belirli bir controller(denetleyiciyi) kullanan sınıflarda `Get.put()` ve `Get.find()` kullanabilirsiniz.
Ancak, Services veya başka bir abstract class ile çalışıyorsanız, daha iyi bir organizasyon için Bindings'i kullanmanızı öneririm.
... ...
- [Rota Yönetimi (Route Management)](#route-management)
- [Nasıl kullanılır?](#nasıl-kullanılır)
- [Adlandırılmış rotalar olmadan navigasyon](#adlandırılmış-rotalar-olmadan-navigasyon)
- [Adlandırılmış rotalarla navigasyon](#adlandırılmış-rotalarla-navigasyon)
- [Verileri adlandırılmış rotalara gönder](#verileri-adlandırılmış-rotalara-gönder)
- [Dinamik URL bağlantıları](#dinamik-url-bağlantıları)
- [Middleware](#middleware)
- [Context olmadan Navigasyon](#context-olmadan-navigasyon)
- [SnackBars](#snackbars)
- [Dialogs](#dialogs)
- [BottomSheets](#bottomsheets)
- [Nested Navigasyon](#nested-navigasyon)
# Route Management
Konu rota yönetimi olduğunda Getx için gereken her şeyin tam açıklaması budur.
## Nasıl kullanılır?
Bunu pubspec.yaml dosyanıza ekleyin:
```yaml
dependencies:
get:
```
Context olmadan routes/snackbars/dialogs/bottomsheets kullanacaksanız veya üst düzey Get API'lerini kullanacaksanız, `MaterialApp`'ınızdan önce `Get` eklemeniz, `GetMaterialApp`'a dönüştürmeniz ve keyfini çıkarmanız yeterlidir!
```dart
GetMaterialApp( // Öncesi: MaterialApp(
home: MyHome(),
)
```
## Adlandırılmış rotalar olmadan navigasyon
Yeni bir ekrana gitmek için:
```dart
Get.to(NextScreen());
```
Snackbar'ları, Dialog'ları, Bottomsheet'leri veya normalde kapatacağınız herhangi bir şeyi kapatmak için `Navigator.pop(context);`
```dart
Get.back();
```
Bir sonraki ekrana gittikten sonra önceki ekrana geri dönme seçeneğinin olmaması için (SplashScreens, Login ekranlarında vb. kullanım için)
```dart
Get.off(NextScreen());
```
Bir sonraki ekrana gittikten sonra önceki tüm rotaları iptal etmek için (Alışveriş sepetlerinde, Anketlerde ve Testlerde kullanışlıdır)
```dart
Get.offAll(NextScreen());
```
Bir sonraki rotaya gitmek ve geri döner dönmez verileri almak veya güncellemek için:
```dart
var data = await Get.to(Payment());
```
diğer ekrandan önceki rota için bir veri gönderin:
```dart
Get.back(result: 'success');
```
Ve kullanın:
Örn:
```dart
if(data == 'success') madeAnything();
```
Sözdizimimizi öğrenmek istemiyor musun? Navigator'ı (büyük harf) navigator (küçük harf) olarak değiştirin ve bağlam(context) kullanmak zorunda kalmadan standart navigasyonun tüm işlevlerine sahip olacaksınız.
Örnek:
```dart
// Varsayılan Flutter Navigator
Navigator.of(context).push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return HomePage();
},
),
);
// Bağlama(context) ihtiyaç duymadan Flutter sözdizimini(syntax) kullanın
navigator.push(
MaterialPageRoute(
builder: (_) {
return HomePage();
},
),
);
// Get syntax (Bu kullanım çok daha iyidir. Tabiki siz karşı çıkma hakkına sahipsiniz.)
Get.to(HomePage());
```
### Adlandırılmış Rotalarla Navigasyon
- NamedRoutes ile gezinmeyi tercih ederseniz, Get de bunu destekler.
nextScreen'e gitmek için
```dart
Get.toNamed("/NextScreen");
```
Ağaçta ve önceki ekranda gezinmek için.
```dart
Get.offNamed("/NextScreen");
```
Ağaçta gezinmek ve önceki tüm ekranları kaldırmak için
```dart
Get.offAllNamed("/NextScreen");
```
Rotaları tanımlamak için `GetMaterialApp`'i kullanın:
```dart
void main() {
runApp(
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => MyHomePage()),
GetPage(name: '/second', page: () => Second()),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.zoom
),
],
)
);
}
```
Tanımsız rotalara navigasyonu yönetmek için (404 hatası), `GetMaterialApp`'de bir `unknownRoute` sayfası tanımlayabilirsiniz.
```dart
void main() {
runApp(
GetMaterialApp(
unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => MyHomePage()),
GetPage(name: '/second', page: () => Second()),
],
)
);
}
```
### Verileri adlandırılmış Rotalara gönder
Sadece argümanlar için istediğinizi gönderin. Get, burada bir String, Map, List veya hatta bir Class örneği olsun, her şeyi kabul eder.
```dart
Get.toNamed("/NextScreen", arguments: 'Get is the best');
```
sınıfınızda(class) veya denetleyicinizde(controller):
```dart
print(Get.arguments);
//print out: Get is the best
```
### Dinamik URL bağlantıları
Web'deki gibi gelişmiş dinamik url'ler sunun. Web geliştiricileri muhtemelen bu özelliği Flutter'da istemişlerdir ve büyük olasılıkla bir paketin bu özelliği vaat ettiğini ve bir URL'nin web'de bulunacağından tamamen farklı bir sözdizimi sunduğunu görmüşlerdir, ancak Get bunu da çözmektedir.
```dart
Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");
```
controller/bloc/stateful/stateless Sınıfınıza:
```dart
print(Get.parameters['id']);
// out: 354
print(Get.parameters['name']);
// out: Enzo
```
Ayrıca Get ile Adlandırılmış Parametreleri kolayca alabilirsiniz:
```dart
void main() {
runApp(
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(
name: '/',
page: () => MyHomePage(),
),
GetPage(
name: '/profile/',
page: () => MyProfile(),
),
//Argümanlı rotalar için farklı bir sayfa ve argümansız başka bir sayfa tanımlayabilirsiniz, ancak bunun için yukarıdaki gibi argüman almayacak olan rotada '/' eğik çizgisini kullanmanız gerekir.
GetPage(
name: '/profile/:user',
page: () => UserProfile(),
),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.cupertino
),
],
)
);
}
```
Rota adına veri gönder
```dart
Get.toNamed("/profile/34954");
```
İkinci ekranda verileri parametreye göre alın
```dart
print(Get.parameters['user']);
// out: 34954
```
veya bunun gibi birden çok parametre gönderin
```dart
Get.toNamed("/profile/34954?flag=true&country=italy");
```
veya
```dart
var parameters = <String, String>{"flag": "true","country": "italy",};
Get.toNamed("/profile/34954", parameters: parameters);
```
İkinci ekranda, verileri genellikle olduğu gibi parametrelere göre alın
```dart
print(Get.parameters['user']);
print(Get.parameters['flag']);
print(Get.parameters['country']);
// out: 34954 true italy
```
Ve şimdi tek yapmanız gereken, herhangi bir bağlam(context) olmaksızın adlandırılmış rotalarınızda gezinmek için Get.toNamed()'i kullanmaktır (rotalarınızı doğrudan BLoC veya Controller sınıfınızdan çağırabilirsiniz) ve uygulamanız web'de derlendiğinde, rotalar url'de görünecek <3
### Middleware
Eylemleri tetiklemek için olayları almak dinlemek istiyorsanız routingCallback'i kullanabilirsiniz.
```dart
GetMaterialApp(
routingCallback: (routing) {
if(routing.current == '/second'){
openAds();
}
}
)
```
GetMaterialApp kullanmıyorsanız, Middleware gözlemcisini(observer) eklemek için manuel API'yi kullanabilirsiniz.
```dart
void main() {
runApp(
MaterialApp(
onGenerateRoute: Router.generateRoute,
initialRoute: "/",
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer), // Burası !!!
],
),
);
}
```
Bir MiddleWare sınıfı oluşturun
```dart
class MiddleWare {
static observer(Routing routing) {
/// Her ekranda rotalar, snackbarlar, diyaloglar ve bottomsheetleri ek olarak dinleyebilirsiniz.
///Bu 3 olaydan herhangi birini doğrudan buraya girmeniz gerekiyorsa,
///Yapmaya çalıştığınızdan daha fazla olayın olduğunu != kullanarak belirtmelisiniz.
if (routing.current == '/second' && !routing.isSnackbar) {
Get.snackbar("Hi", "You are on second route");
} else if (routing.current =='/third'){
print('last route called');
}
}
}
```
Şimdi, Get on kodunu kullanın:
```dart
class First extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.add),
onPressed: () {
Get.snackbar("hi", "i am a modern snackbar");
},
),
title: Text('First Route'),
),
body: Center(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/second");
},
),
),
);
}
}
class Second extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.add),
onPressed: () {
Get.snackbar("hi", "i am a modern snackbar");
},
),
title: Text('second Route'),
),
body: Center(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/third");
},
),
),
);
}
}
class Third extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Third Route"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Get.back();
},
child: Text('Go back!'),
),
),
);
}
}
```
## Context olmadan Navigasyon
### SnackBars
Flutter ile basit bir SnackBar'a sahip olmak için Scaffold bağlamını(context) almalısınız veya Scaffold'unuza bağlı bir GlobalKey kullanmalısınız.
```dart
final snackBar = SnackBar(
content: Text('Hi!'),
action: SnackBarAction(
label: 'I am a old and ugly snackbar :(',
onPressed: (){}
),
);
// Widget ağacında Scaffold'u bulun ve kullanın
// bir SnackBar göstermek için.
Scaffold.of(context).showSnackBar(snackBar);
```
Get ile:
```dart
Get.snackbar('Hi', 'i am a modern snackbar');
```
Get ile, Yapmanız gereken tek şey kodunuzun herhangi bir yerinden Get.snackbar'ınızı aramak veya onu istediğiniz gibi özelleştirmek!
```dart
Get.snackbar(
"Hey i'm a Get SnackBar!", // title
"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!", // message
icon: Icon(Icons.alarm),
shouldIconPulse: true,
onTap:(){},
barBlur: 20,
isDismissible: true,
duration: Duration(seconds: 3),
);
////////// ALL FEATURES //////////
// Color colorText,
// Duration duration,
// SnackPosition snackPosition,
// Widget titleText,
// Widget messageText,
// bool instantInit,
// Widget icon,
// bool shouldIconPulse,
// double maxWidth,
// EdgeInsets margin,
// EdgeInsets padding,
// double borderRadius,
// Color borderColor,
// double borderWidth,
// Color backgroundColor,
// Color leftBarIndicatorColor,
// List<BoxShadow> boxShadows,
// Gradient backgroundGradient,
// TextButton mainButton,
// OnTap onTap,
// bool isDismissible,
// bool showProgressIndicator,
// AnimationController progressIndicatorController,
// Color progressIndicatorBackgroundColor,
// Animation<Color> progressIndicatorValueColor,
// SnackStyle snackStyle,
// Curve forwardAnimationCurve,
// Curve reverseAnimationCurve,
// Duration animationDuration,
// double barBlur,
// double overlayBlur,
// Color overlayColor,
// Form userInputForm
///////////////////////////////////
```
Geleneksel snackbar'ı tercih ediyorsanız veya yalnızca bir satır eklemek de dahil olmak üzere sıfırdan özelleştirmek istiyorsanız (Get.snackbar zorunlu bir başlık ve mesaj kullanır),
Get.snackbar'ın üzerine inşa edildiği RAW API'sini sağlayan `Get.rawSnackbar();` kullanabilirsiniz.
### Dialogs
Dialog'u açmak için:
```dart
Get.dialog(YourDialogWidget());
```
Varsayılan dialog açmak için:
```dart
Get.defaultDialog(
onConfirm: () => print("Ok"),
middleText: "Dialog made in 3 lines of code"
);
```
showGeneralDialog yerine Get.generalDialog'u da kullanabilirsiniz.
Cupertinos dahil olmak üzere tüm diğer Flutter Dialog widget'ları için bağlam(context) yerine Get.overlayContext'i kullanabilir ve kodunuzun herhangi bir yerinde açabilirsiniz.
Overlay kullanmayan widget'lar için Get.context'i kullanabilirsiniz.
Bu iki bağlam(context), inheritedWidget'ın bir gezinme bağlamı(context) olmadan kullanıldığı durumlar dışında, kullanıcı arayüzünüzün bağlamını(context) değiştirmek için vakaların %99'unda çalışacaktır.
### BottomSheets
Get.bottomSheet, showModalBottomSheet gibidir, ancak bağlama(context) ihtiyaç duymaz.
```dart
Get.bottomSheet(
Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(Icons.music_note),
title: Text('Music'),
onTap: () {}
),
ListTile(
leading: Icon(Icons.videocam),
title: Text('Video'),
onTap: () {},
),
],
),
)
);
```
## Nested Navigasyon
Flutter'ın iç içe gezinmesini daha da kolaylaştırın.
İçeriğe ihtiyacınız yoktur ve navigasyon yığınınızı kimliğe(ID) göre bulacaksınız.
- NOT: Paralel gezinme yığınları oluşturmak tehlikeli olabilir. İdeal olan, NestedNavigators'ı kullanmamak veya idareli kullanmaktır. Projeniz gerektiriyorsa, devam edin, ancak bellekte birden çok gezinme yığınını tutmanın RAM tüketimi için iyi bir fikir olmayabileceğini unutmayın.
Bakın ne kadar basit:
```dart
Navigator(
key: Get.nestedKey(1), // index göre anahtar oluşturma
initialRoute: '/',
onGenerateRoute: (settings) {
if (settings.name == '/') {
return GetPageRoute(
page: () => Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // indexe göre iç içe geçmiş rotanıza göre gezinin
},
child: Text("Go to second"),
),
),
),
);
} else if (settings.name == '/second') {
return GetPageRoute(
page: () => Center(
child: Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child: Text("second")
),
),
),
);
}
}
),
```
... ...
* [State Management](#state-management)
+ [Reactive State Manager](#reactive-state-manager)
- [Avantajlar](#avantajlar)
- [Maksimum Performans:](#maksimum-performans)
- [Reaktif bir değişken bildirmek](#reaktif-bir-değişken-bildirmek)
- [Reaktif bir state'e sahip olmak kolaydır.](#reaktif-bir-state'e-sahip-olmak-kolaydır)
- [Görünümdeki değerleri kullanmak](#görünümdeki-değerleri-kullanmak)
- [Yeniden oluşturulacak koşullar](#yeniden-oluşturulacak-koşullar)
- [Nerede .obs kullanılabilir](#nerede-obs-kullanılabilir)
- [Listeler hakkında not](#listeler-hakkında-not)
- [Neden .value kullanmak zorundayım?](#neden-value-kullanmak-zorundayım?)
- [Obx()](#obx)
- [Çalışanlar](#Çalışanlar)
+ [Simple State Manager](#simple-state-manager)
- [Avantajlar](#avantajlar-1)
- [Kullanımı](#kullanımı)
- [Controller'lar nasıl çalışır](#controller'lar-nasıl-çalışır)
- [Artık StatefulWidget'lara ihtiyacınız olmayacak](#artık-statefulwidget'lara-ihtiyacınız-olmayacak)
- [Neden var](#neden-var)
- [Kullanmanın diğer yolları](#kullanmanın-diğer-yolları)
- [Unique IDs-Benzersiz Kimlikler](#unique-ids-benzersiz-kimlikler)
+ [İki state managers ile Mixing](#İki-state-managers-ile-mixing)
+ [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)
# State Management
GetX, diğer State Management'ler (Durum Yöneticileri) gibi Streams veya ChangeNotifier kullanmaz. Niye? GetX ile android, iOS, web, linux, macos ve linux için uygulamalar oluşturmaya ek olarak, Flutter/GetX ile aynı syntax(sözdizimine) sahip server(sunucu) uygulamaları oluşturabilirsiniz. Yanıt süresini iyileştirmek ve RAM tüketimini azaltmak için düşük işletim maliyetiyle çok fazla performans sunan düşük gecikmeli çözümler olan GetValue ve GetStream'i oluşturduk. State Management (Durum Yönetimi) de dahil olmak üzere tüm kaynaklarımızı oluşturmak için bu temeli kullanıyoruz.
* _Complexity_ (Karmaşıklık): Bazı state management'ler karmaşıktır ve çok fazla ortak özelliği vardır. GetX ile her olay için bir sınıf tanımlamanız gerekmez, kod son derece temiz ve nettir ve daha az yazarak çok daha fazlasını yaparsınız. Pek çok insan bu konu yüzünden Flutter'dan vazgeçti ve şimdi nihayet durumları yönetmek için basit bir çözüme sahipler.
* _No code generators_ (Kod Oluşturucu Yok): Geliştirme zamanınızın yarısını uygulama mantığınızı yazmaya harcarsınız. Bazı state management'ler, minimum düzeyde okunabilir koda sahip olmak için kod oluşturuculara güvenir. Bir değişkeni değiştirmek ve build_runner'ı çalıştırmak verimsiz olabilir ve genellikle flutter clean'den sonraki bekleme süresi uzun olur ve çok fazla kahve içmeniz gerekir.
GetX ile her şey reaktiftir ve hiçbir şey kod oluşturuculara bağlı değildir, bu da geliştirmenizin tüm yönlerinde üretkenliğinizi artırır.
* _It does not depend on context(Context'e bağlı değil)_: Muhtemelen görünümünüzün context'ini (bağlam) bir denetleyiciye göndermeniz gerekiyordu, bu da görünümün iş mantığınızla bağlantısını yüksek hale getirdi. Muhtemelen context'i (bağlamı) olmayan bir yer için bir bağımlılık kullanmak zorunda kaldınız ve context'i(bağlamı) çeşitli sınıflar ve fonksiyonlardan geçirmek zorunda kaldınız.Bu sadece GetX ile mevcut değil. Controller'larınıza (Denetleyicilerinize) , controller'larınızın(denetleyicilerinizin) içinden herhangi bir context (bağlam) olmadan erişebilirsiniz. Kelimenin tam anlamıyla hiçbir şey için context'i(bağlamı) parametreye göre göndermeniz gerekmez.
* _Granular control(Parçacıklı Kontrol)_: Çoğu state management(durum yöneticisi) ChangeNotifier'ı temel alır. ChangeNotifier, notifyListeners çağrıldığında kendisine bağlı olan tüm widget'ları bilgilendirecektir. Bir ekranda ChangeNotifier sınıfınızın bir değişkenine sahip 40 widget'ınız varsa, birini güncellediğinizde hepsi yeniden oluşturulacaktır.
GetX ile iç içe geçmiş widget'lara bile saygı duyulur. Obx listview'inizi izliyorsa ve diğeri ListView içinde bir onay kutusu izliyorsa, CheckBox değerini değiştirirken yalnızca o onay kutusu güncellenir, Liste değerini değiştirirken yalnızca ListView güncellenir.
* _It only reconstructs if its variable REALLY changes (Değişken değişirse GERÇEKTEN yeniden yapılandırır)_: GetX akış kontrolüne sahiptir, yani 'Paola' ile bir text(metin) görüntülerseniz, (observable)gözlemlenebilir değişkeni tekrar 'Paola' olarak değiştirirseniz, widget yeniden yapılandırılmayacaktır. Çünkü GetX, 'Paola'nın' zaten text'de(metinde) görüntülendiğini ve gereksiz rekonstrüksiyonlar yapmayacağını biliyor.
Mevcut state management'lerin(durum yöneticilerin) çoğu (hepsi değilse de) ekranda yeniden oluşturulur.
## Reactive State Manager
Reaktif programlama birçok insanı yabancılaştırabilir çünkü karmaşık olduğu söylenir. GetX reaktif programlamayı oldukça basit bir şeye dönüştürür:
* Stream Controller oluşturmanıza gerek yoktur.
* Her değişken için bir StreamBuilder oluşturmanız gerekmez.
* Her state(durum) için bir sınıf oluşturmanız gerekmeyecektir.
* Bir initial value(başlangıç değeri) için bir get oluşturmanız gerekmeyecektir.
Get ile reaktif programlama, Setstate'i kullanmak kadar kolaydır.
Bir ad değişkeniniz olduğunu ve her değiştirdiğinizde onu kullanan tüm widget'ların otomatik olarak değiştirilmesini istediğinizi düşünelim.
Bu sizin count(sayım) değişkeninizdir:
``` dart
var name = 'Jonatas Borges';
```
Observable hale getirmek için, sonuna ".obs" eklemeniz gerekir:
``` dart
var name = 'Jonatas Borges'.obs;
```
Hepsi bu. *Bu kadar basit* bir şey.
Şu andan itibaren, bu reaktif-".obs"(ervables) değişkenlerine _Rx_ adını verebiliriz.
Başlık altında ne yaptık? `String` lerin bir `Stream` oluşturduk, `"Jonatas Borges"` initial value'sunu(başlangıç değerini) atadık, `"Jonatas Borges"` kullanan tüm widget'lara artık bu değişkene "ait olduklarını" bildirdik ve _Rx_ değeri değiştiğinde de değişmeleri gerekecek.
Bu, Dart'ın yetenekleri sayesinde **GetX'in büyüsüdür**.
Ancak, bildiğimiz gibi, bir `Widget` yalnızca bir işlevin içindeyse değiştirilebilir, çünkü statik sınıflar "otomatik değiştirme" gücüne sahip değildir.
Bir `StreamBuilder` oluşturmanız, değişiklikleri dinlemek için bu değişkene abone olmanız ve aynı kapsamdaki birkaç değişkeni değiştirmek istiyorsanız, iç içe geçmiş `StreamBuilder` bir "kaskad" oluşturmanız gerekir, değil mi?
Hayır, bir `StreamBuilder`a ihtiyacınız yok, ancak statik sınıflar konusunda haklısınız.
Pekala, görünüşe göre, belirli bir Widget'ı değiştirmek istediğimizde genellikle çok fazla ortak bilgimiz olur, bu Flutter yoludur.
**GetX** ile bu ortak kod kodunu da unutabilirsiniz.
`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? Hayır, bu değişkeni bir `Obx()` Widget'ına yerleştirmeniz yeterlidir.
``` dart
Obx (() => Text (controller.name));
```
_Ezberlemek için neye ihtiyacın var?_Sadece `Obx(() =>` .
Bu Widget'ı bir ok işlevinden bir `Obx()` (_Rx_'in "Observable") içine geçiriyorsunuz.
`Obx` oldukça akıllıdır ve yalnızca `controller.name`nin değeri değiştiğinde değişecektir.
`name`, `"John"` ise ve onu `"John"` ( `name.value = "John"` ) olarak değiştirirseniz, öncekiyle aynı `değer` olduğundan, ekranda hiçbir şey değişmeyecektir, ve 'Obx' , kaynakları kurtarmak için yeni değeri yok sayar ve Widget'ı yeniden oluşturmaz. **Harika değil mi?**
> Peki ya bir `Obx` içinde 5 _Rx_ (observable) değişkenim varsa?
Yalnızca **herhangi biri** değiştiğinde güncellenecektir.
> Ve bir sınıfta 30 değişkenim varsa, birini güncellediğimde, o sınıftaki değişkenlerin **tümünü** günceller mi?
Hayır, sadece bu _Rx_ değişkenini kullanan **belirli Widget**.
Bu nedenle, **GetX** yalnızca _Rx_ değişkeni değerini değiştirdiğinde ekranı günceller.
```
final isOpen = false.obs;
// NOTHING will happen... same value.
void onButtonTap() => isOpen.value=false;
```
### Avantajlar
**GetX()**, güncellenen değişkenler üzerinde **ayrıntılı** kontrole ihtiyacınız olduğunda size yardımcı olur.
Bir eylem gerçekleştirdiğinizde tüm değişkenleriniz değiştirileceğinden `unique IDs(benzersiz kimliklere)` ihtiyacınız yoksa, `GetBuilder`ı kullanın,
çünkü Simple State Updater(Basit Durum Güncelleyicisi)'dir (`setState ()` gibi bloklar halinde), sadece birkaç kod satırında yapılır.
En az CPU etkisine sahip olmak ve sadece tek bir amacı (_State_ rebuild) yerine getirmek ve mümkün olan en az kaynağı harcamak için basitleştirildi.
**Güçlü** bir State Management (Durum Yöneticisi)'e ihtiyacınız varsa, **GetX** ile yanlış yapmış olamazsınız.
Değişkenlerle çalışmaz, ancak __flows__, içindeki her şey başlık altındaki `Streams`dır.
_rxDart_ ile birlikte kullanabilirsiniz, çünkü her şey `Streams`,
her "_Rx_variable"ın 'event(olayını)' dinleyebilirsiniz,
çünkü içindeki her şey `Streams`'dir.
Kelimenin tam anlamıyla bir _BLoC_ yaklaşımıdır, _MobX_'den daha kolaydır ve kod oluşturucuları veya süslemeleri yoktur.
**Herhangi bir şeyi** yalnızca bir `.obs` ile _"Observable"_ hale getirebilirsiniz.
### Maksimum Performans:
State Management (Durum Yöneticisinin)'in değiştiğinden emin olmak için akıllı bir algoritmaya sahip olmanın yanı sıra **GetX** comparators kullanır.
Uygulamanızda herhangi bir hatayla karşılaşırsanız ve yinelenen bir State(durum) değişikliği gönderirseniz,
**GetX** çökmemesini sağlayacaktır.
**GetX** ile State(Durum) yalnızca `value(değer)` değişirse değişir.
Bu, **GetX** ile mobx_'den _ `computed` kullanımı arasındaki temel farktır.
İki defa __observable__ 'da bir değişiklik yapıldığında; o _observable_ dinleyicisi de değişecektir.
**GetX** ile, iki değişkeni birleştirirseniz, `GetX()` (`Observer()`a benzer) yalnızca gerçek bir State(Durum) değişikliği gerektiriyorsa yeniden oluşturacaktır.
### Reaktif bir değişken bildirmek
Bir değişkeni "observable" hale getirmenin 3 yolu vardır.
1 - Birincisi **`Rx{Type}`** kullanmak.
``` dart
// initial value önerilir, zorunlu değildir.
final name = RxString('');
final isLogged = RxBool(false);
final count = RxInt(0);
final balance = RxDouble(0.0);
final items = RxList<String>([]);
final myMap = RxMap<String, int>({});
```
2 - İkincisi, **`Rx`** kullanmak ve Darts Generics, `Rx<Type>` kullanmaktır.
``` dart
final name = Rx<String>('');
final isLogged = Rx<Bool>(false);
final count = Rx<Int>(0);
final balance = Rx<Double>(0.0);
final number = Rx<Num>(0);
final items = Rx<List<String>>([]);
final myMap = Rx<Map<String, int>>({});
// Custom classes - herhangi bir sınıf olabilir
final user = Rx<User>();
```
3 - Üçüncü, daha pratik, daha kolay ve tercih edilen yaklaşım,`value`'ya bir **`.obs`** ekleyin:
``` dart
final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;
// Custom classes - herhangi bir sınıf olabilir
final user = User().obs;
```
##### Reaktif bir state'e sahip olmak kolaydır.
Bildiğimiz gibi, _Dart_ şimdi _null safety_ doğru gidiyor.
Şu andan itibaren hazırlıklı olmak için, _Rx_ değişkenlerinizi her zaman bir **initial value** ile başlatmalısınız.
> Bir değişkeni **GetX** ile _observable_ + _initial value_ değerine dönüştürmek en basit ve pratik yaklaşımdır.
Kelimenin tam anlamıyla bir değişkeninizin sonuna bir " `.obs` " ekleyeceksiniz, ve **bu kadar**. Şimdi onu gözlemlenebilir hale getirdiniz,
ve onun `.value(değer)`'i, _initial value_ olacaktır.
### Görünümdeki değerleri kullanmak
``` dart
// controller dosyası
final count1 = 0.obs;
final count2 = 0.obs;
int get sum => count1.value + count2.value;
```
``` dart
// view dosyası
GetX<Controller>(
builder: (controller) {
print("count 1 rebuild");
return Text('${controller.count1.value}');
},
),
GetX<Controller>(
builder: (controller) {
print("count 2 rebuild");
return Text('${controller.count2.value}');
},
),
GetX<Controller>(
builder: (controller) {
print("count 3 rebuild");
return Text('${controller.sum}');
},
),
```
`count1.value++` değerini artırırsak, şunu yazdırır:
* `count 1 rebuild`
* `count 3 rebuild`
`count1`, `1` değerine sahip olduğundan ve `1 + 0 = 1` olduğundan, `toplam` değeri değiştirilir.
`count2.value++` değerini değiştirirsek, şunu yazdırır:
* `count 2 rebuild`
* `count 3 rebuild`
çünkü `count2.value` değişti ve `sum`un sonucu şimdi `2` oldu.
* NOT: Varsayılan olarak, ilk etkinlik aynı `value` olsa bile widget'ı yeniden oluşturacaktır.
Bu durum boolean değişkenlerinde de mevcuttur.
Bunu yaptığınızı hayal edin:
``` dart
var isLogged = false.obs;
```
Ardından, bir kullanıcının `ever` içinde bir olayı tetiklemek için `isLogged` olup olmadığını kontrol ettiniz.
``` dart
@override
onInit() async {
ever(isLogged, fireRoute);
isLogged.value = await Preferences.hasToken();
}
fireRoute(logged) {
if (logged) {
Get.off(Home());
} else {
Get.off(Login());
}
}
```
`hasToken` `false` olsaydı, `isLogged`da herhangi bir değişiklik olmazdı, bu nedenle `ever()` asla çağrılmazdı.
Bu tür davranışlardan kaçınmak için, bir _observable_ öğesindeki ilk değişiklik her zaman bir olayı tetikleyecektir,
aynı `.value` değerini içerse bile.
İsterseniz bu davranışı kullanarak kaldırabilirsiniz:
`isLogged.firstRebuild = false;`
### Yeniden oluşturulacak koşullar
Ek olarak, Get gelişmiş durum kontrolü sağlar. Bir olayı (listeye nesne ekleme gibi) belirli bir koşulda koşullandırabilirsiniz.
``` dart
// İlk parametre: koşul, true veya false döndürmelidir.
// İkinci parametre: koşul doğruysa yeni değer uygulanacaktır.
list.addIf(item < limit, item);
```
Süslemesiz, kod oluşturucusuz, komplikasyonsuz :smile:
Flutter'ın sayaç uygulamasını biliyor musunuz? Controller sınıfınız şöyle görünebilir:
``` dart
class CountController extends GetxController {
final count = 0.obs;
}
```
Basit bir şekilde:
``` dart
controller.count.value++
```
Kullanıcı arabiriminizdeki sayaç değişkenini nerede depolandığına bakılmaksızın güncelleştirebilirsiniz.
### Nerede .obs kullanılabilir
Obs üzerindeki her şeyi dönüştürebilirsiniz. İşte bunu yapmanın iki yolu:
* Sınıf değerlerinizi obs'ye dönüştürebilirsiniz
``` dart
class RxUser {
final name = "Camila".obs;
final age = 18.obs;
}
```
* veya tüm sınıfı observable hale getirebilirsiniz.
``` dart
class User {
User({String name, int age});
var name;
var age;
}
// örnek:
final user = User(name: "Camila", age: 18).obs;
```
### Listeler hakkında not
Listeler, içindeki nesneler gibi tamamen gözlemlenebilir. Bu şekilde, bir listeye bir değer eklerseniz, onu kullanan widget'ları otomatik olarak yeniden oluşturur.
Ayrıca listelerde ".value" kullanmanıza gerek yok, harika dart api'ları bunu kaldırmamıza izin verdi.
Ne yazık ki, String ve int gibi ilkel türler genişletilemez, bu da kullanımını sağlar. Değer zorunludur, ancak bunlar için get ve setter'larla çalışıyorsanız bu bir sorun olmayacaktır.
``` dart
// On the controller
final String title = 'User Info:'.obs
final list = List<User>().obs;
// on the view
Text(controller.title.value), // .value olması gerekir
ListView.builder (
itemCount: controller.list.length // listelerin buna ihtiyacı yok
)
```
Kendi sınıflarınızı observable hale getirirken, bunları güncellemenin farklı bir yolu vardır:
``` dart
// model dosyasında
// her bir öznitelik yerine tüm sınıfı observable hale getireceğiz
class User() {
User({this.name = '', this.age = 0});
String name;
int age;
}
// Controller dosyası
final user = User().obs;
// User değişkenini güncellemeniz gerektiğinde:
user.update( (user) { // bu parametre, güncellemek istediğiniz sınıfın kendisidir.
user.name = 'Jonny';
user.age = 18;
});
// user değişkenini güncellemenin alternatif bir yolu:
user(User(name: 'João', age: 35));
// on view:
Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}"))
// model değerlerine .value olmadan da erişebilirsiniz:
user().name;
```
İstemiyorsanız setlerle çalışmak zorunda değilsiniz. "assign" ve "assignAll" api'sini kullanabilirsiniz.
"assign" api'si listenizi temizler ve oradan başlatmak istediğiniz tek bir nesneyi ekler.
"assignAll" api, mevcut listeyi temizleyecek ve ona enjekte ettiğiniz yinelenebilir nesneleri ekleyecektir.
### Neden .value kullanmak zorundayım?
Basit bir decoration ve code generator ile `String` ve `int` için 'value' kullanma zorunluluğunu kaldırabiliriz, ancak bu kütüphanenin amacı kesinlikle dış bağımlılıklardan kaçınmaktır. Temelleri (route, dependencies ve state management) içeren, harici bir pakete ihtiyaç duymadan basit, hafif ve performanslı bir şekilde programlamaya hazır bir ortam sunmak istiyoruz.
Pubspec'inize (get) tam anlamıyla 3 harf ve iki nokta üst üste ekleyebilir ve programlamaya başlayabilirsiniz. Rota yönetiminden durum yönetimine kadar varsayılan olarak dahil edilen tüm çözümler kolaylık, üretkenlik ve performansı hedefler.
Bu kitaplığın toplam ağırlığı, eksiksiz bir çözüm olmasına rağmen tek bir state manager'den daha azdır.
Eğer `.value` dan rahatsızsanız MobX harika bir alternatiftir ve Get ile birlikte kullanabilirsiniz.
MobX code generator ile bir sorununuz yoksa veya BLoC ilgili bir sorununuz yoksa Get ile route'u kullanabilirsiniz. Get SEM ve RSM ile doğdu, şirketimin 90'dan fazla controller'a sahip bir projesi var.Büyük bir projeniz varsa, oldukça iyi bir makinede bir Flutter Clean'den sonra görevlerini tamamlaması 30 dakikadan fazla sürdü. 5, 10, 15 controller, herhangi bir state manager size yardımcı olacaktır. Büyük bir projeniz varsa ve code generator sizin için bir sorunsa, bu çözüm size verildi.
Açıkçası, birisi projeye katkıda bulunmak ve bir code generator veya benzeri bir şey oluşturmak istiyorsa, bunu readme'de alternatif olarak bağlantı ekleyeceğim, şimdilik diyorum ki, bunu zaten yapan iyi çözümler var, MobX gibi.
### Obx()
Bindings kullanarak Get yazmak gereksizdir. Yalnızca bir pencere öğesi oluşturan anonim işlevi alan GetX yerine Obx pencere aracını kullanabilirsiniz.
Açıkçası, bir tür kullanmıyorsanız, değişkenleri kullanmak için denetleyicinizin bir örneğine sahip olmanız veya değeri almak için `Get.find<Controller>()` .value veya Controller.to.value öğesini kullanmanız gerekir. .
### Çalışanlar
Bir olay meydana geldiğinde belirli geri aramaları tetikleyerek size yardımcı olacaktır.
``` dart
/// 'Count1' her değiştiğinde çağrılır.
ever(count1, (_) => print("$_ has been changed"));
/// $_ değişkeni yalnızca ilk kez değiştirildiğinde çağrılır.
once(count1, (_) => print("$_ was changed once"));
/// Anti DDoS - Örneğin, kullanıcı 1 saniye boyunca yazmayı her durdurduğunda çağrılır.
debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1));
/// 1 saniye içinde tüm değişiklikleri yok sayın.
interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1));
```
Tüm çalışanlar (`debounce` dışında), "bool" veya "bool" döndüren bir callback olabilen bir "Koşul" adlı parametreye sahiptir.
Bu "koşul", "callback" işlevinin ne zaman yürütüleceğini tanımlar.
Tüm çalışanlar, çalışanı iptal etmek için ( `dispose()` aracılığıyla) kullanabileceğiniz bir 'Worker' örneği döndürür.
* **`ever`**
_Rx_ değişkeni her yeni bir değer yaydığında çağrılır.
* **`everAll`**
`ever` gibi, ancak değişkeni her değiştirildiğinde çağrılan _Rx_ değerlerinin bir `List`'ini alır. Bu kadar.
* **`once`**
'once', yalnızca değişken ilk değiştirildiğinde çağrılır.
* **`debounce`**
'debounce', yalnızca kullanıcı yazmayı bitirdiğinde API'nin çağrılmasını istediğiniz arama işlevlerinde çok kullanışlıdır. Kullanıcı "Jonny" yazarsa, apı'lerde J, o, n, n ve y harfleriyle 5 aramanız olur. Get ile bu olmaz, çünkü yalnızca yazmanın sonunda tetiklenecek bir "debounce" çalışanınız olur.
* **`interval`**
'interval' debouce'dan farklıdır. debouce kullanıcı 1 saniye içinde bir değişkene 1000 değişiklik yaparsa, öngörülen zamanlayıcıdan sonra yalnızca sonuncusunu gönderir (varsayılan değer 800 milisaniyedir). Interval bunun yerine, öngörülen süre boyunca tüm kullanıcı eylemlerini yoksayar. Olayları saniyede 1000 olmak üzere 1 dakika boyunca gönderirseniz, debounce yalnızca kullanıcı olayları engellemeyi bıraktığında size sonuncusunu gönderir. aralık, her saniye olayları teslim eder ve 3 saniyeye ayarlanırsa, o dakika 20 olay teslim eder. Bu, kullanıcının bir şeye hızlı bir şekilde tıklayabileceği ve bir avantaj elde edebileceği işlevlerde kötüye kullanımı önlemek için önerilir (kullanıcının bir şeye tıklayarak para kazanabileceğini düşünün, aynı dakikada 300 kez tıklarsa, 300 jetona sahip olur, aralığı kullanarak, bir zaman dilimi ayarlayabilirsiniz 3 saniye boyunca ve hatta 300 veya bin kez tıklandığında, 1 dakika içinde alacağı maksimum 20 jeton, 300 veya 1 milyon kez tıklanır). Debounce, anti-DDoS için, Onchange'deki her değişikliğin apı'nizde bir sorguya neden olacağı arama gibi işlevler için uygundur. Debounce, kullanıcının isteği yapmak için adı yazmayı bırakmasını bekleyecektir. Yukarıda belirtilen jeton senaryosunda kullanılmış olsaydı, kullanıcı yalnızca belirlenen süre boyunca "durakladığında" çalıştırıldığı için kullanıcı yalnızca 1 jeton kazanırdı.
* NOT: Çalışanlar her zaman bir Controller veya Class başlatırken kullanılmalıdır, bu nedenle her zaman onInit (önerilen), Class oluşturucu veya statefulwidget'in initState üzerinde olmalıdır (bu uygulama çoğu durumda önerilmez, ancak herhangi bir yan etkisi olmamalıdır).
## Simple State Manager(Basit Durum Yöneticisi)
Get'in son derece hafif ve kolay, ChangeNotifier kullanmayan, özellikle Flutter'a yeni başlayanların ihtiyacını karşılayacak ve büyük uygulamalar için sorun yaratmayacak bir state manager'i var.
GetBuilder tam olarak çoklu state controller'a yöneliktir. Bir sepete 30 ürün eklediğinizi, birini sil'i tıklattığınızı, aynı zamanda listenin güncellendiğini, fiyatın güncellendiğini ve alışveriş sepetindeki rozetin daha küçük bir sayıya güncellendiğini düşünün. Bunu GetBuilder yapar, çünkü durumları gruplandırır ve bunun için herhangi bir "hesaplama mantığı" olmadan hepsini bir kerede değiştirir. GetBuilder, bu tür bir durum göz önünde bulundurularak oluşturuldu, çünkü geçici durum değişikliği için Setstate'i kullanabilirsiniz ve bunun için bir state manager'e ihtiyacınız olmaz.
Bu şekilde, tek bir controller'a ihtiyacınız varsa, bunun için ID'ler atayabilir veya getx'i kullanabilirsiniz. Bu size kalmış, sahip olduğunuz daha fazla "individual" widget'ın, getx'in performansının o kadar fazla öne çıkacağını, Getbuilder'ın performansının ise birden fazla durum değişikliği olduğunda üstün olması gerektiğini unutmayın.
### Avantajlar
1. Yalnızca gerekli widget'ları günceller.
2. ChangeNotifier kullanmaz, daha az bellek kullanan (0mb'ye yakın) durum yöneticisidir.
3. StatefulWidget'ı unutun! Get ile buna asla ihtiyacınız olmayacak. Diğer state manager'lar ile (BLoC, MobX Controller vb.) muhtemelen bir StatefulWidget kullanmanız gerekecek. Stateless Widget mı? Öyleyse, yalnızca state bilgisi olan Widget'ın durumunu kaydedebiliyorsanız, neden tüm sınıfın durumunu kurtarın? Get bunu da çözer. Stateless bir sınıf oluşturun, her şeyi Stateless yapın. Tek bir bileşeni güncellemeniz gerekiyorsa, onu GetBuilder ile sarın.
4. Projenizi gerçek anlamda düzenleyin! Denetleyiciler UI'nizde bulunmamalı, TextEditController'ınızı veya kullandığınız herhangi bir denetleyiciyi Controller sınıfınıza yerleştirmemelidir.
5.Bir widget'ı oluşturulduğu anda güncellemek için bir olayı tetiklemeniz mi gerekiyor? GetBuilder, StatefulWidget gibi "initState" özelliğine sahiptir ve initState'inize daha fazla event yerleştirilmeden, doğrudan denetleyicinizden event'leri çağırabilirsiniz.
6. Stream, timer vb. kapatmak gibi bir eylemi tetiklemeniz gerekiyor mu? Get Builder ayrıca, widget yok edilir edilmez olayları çağırabileceğiniz dispose özelliğine de sahiptir.
7. Stream'leri yalnızca gerektiğinde kullanın. Stream Controller controller içinde normal olarak kullanabilir ve Streambuilder'ı da normal olarak kullanabilirsiniz, ancak unutmayın, bir stream makul bir şekilde bellek tüketir, reaktif programlama güzeldir, ancak kötüye kullanmamalısınız. aynı anda açılan 30 stream, Changenotifier'den daha kötü olabilir (ve changeNotifier çok kötüdür).
8. Ram harcamadan widget'ları güncelleyin. Get yalnızca Get Builderlder içerik oluşturucu kimliğini ve gerektiğinde GetBuilder güncelleştirmelerini depolar. Bellekte get ID depolama bellek tüketimi bile GetBuilders binlerce çok düşüktür. Yeni bir GetBuilder oluşturduğunuzda, aslında bir içerik oluşturucu kimliği olan GetBuilder durumunu paylaşıyorsunuz demektir. Her GetBuilder için büyük uygulamalar için çok fazla ram tasarrufu sağlayan yeni bir durum oluşturulmaz. Temel olarak uygulamanız tamamen Stateless olacak ve State Bilgisi olan birkaç Widget (GetBuilder içinde) tek bir duruma sahip olacak ve bu nedenle birini güncellemek hepsini güncelleyecektir. State sadece bir tanesidir.
9. Get her şeyi bilir ve çoğu durumda bir denetleyiciyi bellekten çıkarma zamanını tam olarak bilir. Bir denetleyiciyi ne zaman elden çıkaracağınız konusunda endişelenmemelisiniz, Bunu yapmak için en iyi zamanı öğrenin.
### Kullanımı
``` dart
// Controller sınıfı oluşturun ve GetxController'ı extends edin
class Controller extends GetxController {
int counter = 0;
void increment() {
counter++;
update(); // artış çağrıldığında kullanıcı arayüzünde sayaç değişkenini güncellemek için update() işlevini kullanın
}
}
// Stateless/Stateful sınıfınızda, artış çağrıldığında Metni güncellemek için Get Builder'ı kullanın
GetBuilder<Controller>(
init: Controller(), // INIT IT ONLY THE FIRST TIME
builder: (_) => Text(
'${_.counter}',
),
)
//Initialize yalnızca ilk kez başlatın. Aynı controller için ReBuilder'ı ikinci kez kullanıyorsanız, tekrar kullanmayın. Controller'ınız, onu 'init' olarak işaretleyen pencere öğesi yerleştirildiği anda bellekten otomatik olarak kaldırılacaktır. Bunun için endişelenmenize gerek yok, Get bunu otomatik olarak yapacak, sadece aynı contrroller'ın iki kez başlatmadığınızdan emin olun.
```
**Tamamlandı!**
* Get ile durumları nasıl yöneteceğinizi öğrendiniz.
* Not: Daha büyük bir organizasyon isteyebilirsiniz ve init özelliğini kullanmayabilirsiniz. Bunun için bir sınıf oluşturup Bindings sınıfını extends edebilir ve bunun içinde o rotada oluşturulacak controller'dan bahsedebilirsiniz. Controller'lar o anda oluşturulmaz, tam tersine, bu sadece bir ifadedir, böylece bir Controller'ı ilk kullandığınızda, nereye bakacağınızı bilecek. Get lazyLoad olarak kalacak ve artık ihtiyaç duyulmadığında Controller'ları elden çıkarmaya devam edecek. Nasıl çalıştığını görmek için pub.dev örneğine bakın.
Birçok rotada gezinirseniz ve daha önce kullandığınız controller'ınızda bulunan verilere ihtiyacınız varsa, GetBuilder tekrar (init olmadan) kullanmanız yeterlidir:
``` dart
class OtherClass extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GetBuilder<Controller>(
builder: (s) => Text('${s.counter}'),
),
),
);
}
```
Controller'ınızı GetBuilder dışında birçok başka yerde kullanmanız gerekiyorsa, controller'ınıza bir get oluşturun ve kolayca elde edin. (veya `Get.find<Controller>()` kullanın)
``` dart
class Controller extends GetxController {
/// Buna ihtiyacın yok. Sadece syntax kolaylığı için kullanmanızı öneririm.
/// statik yöntemle: Controller.to.increment();
/// statik yöntem olmadan: Get.find<Controller>().increment();
/// Her iki syntax kullanmanın herhangi bir yan etkisi veya performans farkı yoktur. Yalnızca birinin türe ihtiyacı yoktur ve diğeri IDE tarafından otomatik olarak tamamlanır.
static Controller get to => Get.find(); // bu satırı ekleyin
int counter = 0;
void increment() {
counter++;
update();
}
}
```
Ve sonra controller'a doğrudan bu şekilde erişebilirsiniz:
``` dart
FloatingActionButton(
onPressed: () {
Controller.to.increment(),
} // Bu inanılmaz derecede basit!
child: Text("${Controller.to.counter}"),
),
```
FloatingActionButton tuşuna bastığınızda, 'counter' değişkenini dinleyen tüm widget'lar otomatik olarak güncellenir.
### Controller'lar nasıl çalışır
Diyelim ki elimizde bu var:
`Class a => Class B (has controller X) => Class C (has controller X)`
A sınıfında controller henüz bellekte değil çünkü henüz kullanmadınız (Get is lazyLoad). B sınıfında controller kullandınız ve belleğe girdi. C sınıfında, B sınıfındakiyle aynı controller'ı kullandınız, Get, controller B'nin durumunu C controller'ı ile paylaşacak ve aynı controller hala bellekte kalacaktır. C ekranını ve B ekranını kapatırsanız, Get, A Sınıfı controller'ı kullanmadığından otomatik olarak X controller'ını bellekten alır ve kaynakları boşaltır. Tekrar B'ye giderseniz, X controller'ı tekrar belleğe girer, C sınıfına gitmek yerine tekrar A sınıfına dönerseniz Get, controller aynı şekilde bellekten çıkarır. C sınıfı controller'ı kullanmadıysa ve B sınıfını bellekten çıkardıysanız, hiçbir sınıf controller'ı X kullanmayacak ve aynı şekilde imha edilecektir. Get ile bulaşabilecek tek istisna, B'yi rotadan beklenmedik bir şekilde kaldırırsanız ve controller'ı C'de kullanmaya çalışırsanız. Bu durumda, controller'ın B'deki ID silindi ve Get şu şekilde programlandı: ID olmayan her controller'ı bellekten kaldırın. Bunu yapmayı düşünüyorsanız, "autoRemove: false" işaretini B sınıfının GetBuilder'ına ekleyin ve adoptID = true; yapın C sınıfında GetBuilder kullanın.
### Artık StatefulWidget'lara ihtiyacınız olmayacak
Stateful Widget kullanmak, tüm ekranların durumunu gereksiz yere depolamak anlamına gelir, çünkü bir widget'ı minimum düzeyde yeniden oluşturmanız gerekse bile, onu başka bir Stateful Widget olacak olan bir Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx içine gömeceksiniz. StatefulWidget sınıfı, daha fazla RAM tahsis edecek olan StatelessWidget'ten daha büyük bir sınıftır ve bu, bir veya iki sınıf arasında önemli bir fark yaratmayabilir, ancak 100 tanesine sahip olduğunuzda kesinlikle yapacaktır! TickerProviderStateMixin gibi bir mixin kullanmanız gerekmiyorsa, Get ile bir StatefulWidget kullanmak tamamen gereksiz olacaktır.
StatefulWidget'ın tüm yöntemlerini doğrudan bir GetBuilder'dan çağırabilirsiniz.
Örneğin, initState() veya Dispose() yöntemini çağırmanız gerekiyorsa, bunları doğrudan çağırabilirsiniz;
``` dart
GetBuilder<Controller>(
initState: (_) => Controller.to.fetchApi(),
dispose: (_) => Controller.to.closeStreams(),
builder: (s) => Text('${s.username}'),
),
```
Bundan çok daha iyi bir yaklaşım, doğrudan controller'dan onInit() ve onClose() yöntemini kullanmaktır.
``` dart
@override
void onInit() {
fetchApi();
super.onInit();
}
```
* NOT: Controller ilk kez çağrıldığı anda bir metot başlatmak istiyorsanız, bunun için constructors kullanmanıza GEREK YOKTUR, aslında Get gibi performans odaklı bir paket kullanarak bu sorunu çözebilirsiniz. Controller'ların oluşturulduğu veya tahsis edildiği mantıktan saptığı için (bu controller'ın bir örneğini oluşturursanız, constructor hemen çağrılır, bir controller kullanılmadan önce bellek ayırırsınız ve belleği doldurursunuz. Bu kesinlikle bu kütüphanenin ilkelerine zarar verir. onInit() yöntemleri; ve onClose(); için oluşturulduysa, Get.lazyPut kullanıp kullanmadığınıza bağlı olarak Controller oluşturulduğunda veya ilk kez kullanıldığında çağrılırlar. Örneğin, verileri doldurmak için API'nize bir çağrı yapmak istiyorsanız, eski moda initState/dispose yöntemini unutabilirsiniz, sadece onInit'te api'ye çağrınızı başlatın ve herhangi bir komutu çalıştırmanız gerekirse akışları kapatmak gibi, bunun için onClose()'u kullanın.
### Neden var
Bu paketin amacı, mümkün olan en az bağımlılıkları kullanarak, yüksek derecede ayrıştırma ile rotaların gezinmesi, bağımlılıkların ve durumların yönetimi için eksiksiz bir çözüm sunmaktır. Get, mümkün olan en az bağlantıyla çalıştığınızdan emin olmak için tüm yüksek ve düşük seviyeli Flutter API'lerini kendi içinde çalıştırır. Projenizde herhangi bir bağlantı olmadığından emin olmak için her şeyi tek bir pakette merkezileştiriyoruz. Bu şekilde, görünümünüze yalnızca widget'lar koyabilir ve ekibinizin iş mantığıyla çalışan bölümünü, Görünümün herhangi bir öğesine bağlı kalmadan iş mantığıyla çalışmak üzere serbest bırakabilirsiniz. Bu, çok daha temiz bir çalışma ortamı sağlar, böylece ekibinizin bir kısmı controller'a veri göndermekten endişe etmeden yalnızca widget'larla çalışır ve ekibinizin bir kısmı, görünümün hiçbir öğesine bağlı kalmadan yalnızca genişliğindeki iş mantığıyla çalışır.
Yani bunu basitleştirirsek:
Initstate'deki yöntemleri çağırmanız ve bunları controller'ınıza parametre ile göndermeniz veya bunun için controller içerisinde constructor kullanmanız gerekmez, doğru zamanda çağrılan onInit () yöntemine sahip olursunuz.
Cihaz aramak zorunda değilsiniz, gerektiğinde tam zamanında close() yöntemi ile hafızasından silinecektir. Bu şekilde, yalnızca widget'lar için görünümler bırakın, her türlü iş mantığından kaçının.
GetxController içinde bir dispose yöntemi çağırmayın, hiçbir şey yapmaz, controller'ın bir Widget olmadığını, "dispose" gerektiğini ve Get tarafından bellekten otomatik ve akıllıca kaldırılacağını unutmayın. Üzerinde herhangi bir akış kullandıysanız ve kapatmak istiyorsanız, onu close yöntemine eklemeniz yeterlidir. Örnek:
``` dart
class Controller extends GetxController {
StreamController<User> user = StreamController<User>();
StreamController<String> name = StreamController<String>();
/// close stream = onClose yöntemi, dispose değil.
@override
void onClose() {
user.close();
name.close();
super.onClose();
}
}
```
Controller life cycle(yaşam döngüsü):
* onInit() oluşturulduğu yer.
* onClose() close yöntemine hazırlanırken herhangi bir değişiklik yapmak için kapatıldığı yer.
* deleted: Controller bellekten tam anlamıyla kaldırdığı için bu API'ye erişiminiz olmaz. Herhangi bir iz bırakmadan kelimenin tam anlamıyla silinir.
### Kullanmanın diğer yolları
Controller'ı doğrudan GetBuilder ile kullanabilirsiniz:
``` dart
GetBuilder<Controller>(
init: Controller(),
builder: (value) => Text(
'${value.counter}', //here
),
),
```
Controller'ınızı GetBuilder dışında bir örneğine de ihtiyacınız olabilir ve bunu başarmak için bu yaklaşımları kullanabilirsiniz:
``` dart
class Controller extends GetxController {
static Controller get to => Get.find();
[...]
}
// görünümde:
GetBuilder<Controller>(
init: Controller(), // Her controller'ı bir kez kullanın
builder: (_) => Text(
'${Controller.to.counter}', //burada
)
),
```
or
``` dart
class Controller extends GetxController {
// static Controller get to => Get.find(); // static olmadan
[...]
}
// on stateful/stateless class
GetBuilder<Controller>(
init: Controller(), // Her controller'ı bir kez kullanın
builder: (_) => Text(
'${Get.find<Controller>().counter}', //burada
),
),
```
* Bunu yapmak için "non-canonical" yaklaşımları kullanabilirsiniz. Get_it, modular vb. Gibi başka bir dependency manager kullanıyorsanız ve sadece controller instance etmek istiyorsanız, bunu yapabilirsiniz:
``` dart
Controller controller = Controller();
[...]
GetBuilder<Controller>(
init: controller, //burada
builder: (_) => Text(
'${controller.counter}', // burada
),
),
```
### Unique IDs-Benzersiz Kimlikler
Bir widget'ın controller'ını güncellemek istiyorsanız GetBuilder onlara benzersiz kimlikler atayabilirsiniz:
``` dart
GetBuilder<Controller>(
id: 'text'
init: Controller(), // Her controller'ı bir kez kullanın
builder: (_) => Text(
'${Get.find<Controller>().counter}', //burada
),
),
```
Ve bu formu güncelleyin:
``` dart
update(['text']);
```
Güncelleme için koşullar da uygulayabilirsiniz:
``` dart
update(['text'], counter < 10);
```
GetX bunu otomatik olarak yapar ve yalnızca değiştirilen değişkeni tam olarak kullanan widget'ı yeniden yapılandırır, bir değişkeni öncekiyle aynı olacak şekilde değiştirirseniz ve bu state değişikliği anlamına gelmezse GetX widget'ı bellek ve CPU döngülerinden tasarruf etmek için yeniden oluşturmaz (ekranda 3 görüntüleniyor ve değişkeni tekrar 3 olarak değiştirirsiniz. Çoğu state manager, bu yeni bir yeniden yapılanmaya neden olur, ancak Get ile widget yalnızca state değiştiyse yeniden oluşturulur).
## İki state managers ile Mixing
Bazı insanlar, yalnızca bir tür reaktif değişken ve diğer mekanikleri kullanmak istediklerinden ve bunun için bir GetBuilder'a bir Obx eklemeleri gerektiğinden bir özellik request'i açtı. Bunu düşünerek MixinBuilder oluşturuldu. Hem ".obs" değişkenlerini değiştirerek reaktif değişikliklere hem de update() aracılığıyla mekanik güncellemelere izin verildi. Bununla birlikte, 4 widget'tan en çok kaynak tüketendir, çünkü children'larda değişiklik olaylarını anlaması için sahip olmasının yanı sıra, controller'ın güncelleme yöntemine sahip olur.
GetxController'ı extends etmek önemlidir, çünkü yaşam döngüleri vardır ve olayları onInit() ve onClose() yöntemlerinde "başlatabilir" ve "bitebilir". Bunun için herhangi bir sınıfı kullanabilirsiniz, ancak değişkenlerinizi observable olsun ya da olmasın yerleştirmek için GetxController sınıfını kullanmanızı şiddetle tavsiye ederim.
## StateMixin
`UI` state'ini ele almanın başka bir yolu da `StateMixin<T>` kullanmaktır.
Bunu uygulamak için, `StateMixin<T>` ile `with`i kullanın.
bir controller'a T modelinizi ekleyin.
``` dart
class Controller extends GetController with StateMixin<User>{}
```
`change()` yöntemi istediğimiz zaman State'i değiştirir.
Sadece verileri ve state'i bu şekilde iletin:
```dart
change(data, status: RxStatus.success());
```
RxStatus şu duruma izin verir:
``` dart
RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('message');
```
UI'da bu şekilde kullanın:
```dart
class OtherClass extends GetView<Controller> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller.obx(
(state)=>Text(state.name),
// burada özel yükleme göstergenizi koyabilirsiniz, ancak
// varsayılan olarak Center(child:CircularProgressIndicator()) olacaktır.
onLoading: CustomLoadingIndicator(),
onEmpty: Text('No data found'),
// burada ayrıca kendi hata widget'ınızı ayarlayabilirsiniz, ancak
// default birCenter(child:Text(error)) olacaktır.
onError: (error)=>Text(error),
),
);
}
```
## GetBuilder vs GetX vs Obx vs MixinBuilder
Programlamayla geçen on yılda bazı değerli dersler öğrenebildim.
Reaktif programlama ile ilk temasım çok "vay be, bu inanılmaz" oldu ve aslında reaktif programlama inanılmaz.
Ancak, tüm durumlar için uygun değildir. Çoğu zaman tek ihtiyacınız olan, aynı anda 2 veya 3 parçacığın durumunu değiştirmek veya geçici bir durum değişikliğidir, bu durumda reaktif programlama kötü değildir, ancak uygun değildir.
Reaktif programlama, bireysel iş akışıyla telafi edilebilecek daha yüksek bir RAM tüketimine sahiptir; bu, yalnızca bir widget'ın yeniden oluşturulmasını ve gerektiğinde yapılmasını sağlar, ancak her biri birkaç akışa sahip 80 nesneden oluşan bir liste oluşturmak iyi bir fikir değildir. Dartı açın ve bir StreamBuilder'ın ne kadar tükettiğini kontrol edin ve size ne söylemeye çalıştığımı anlayacaksınız.
Bunu akılda tutarak, basit bir state manager yarattım. Bu basittir ve ondan tam olarak talep etmeniz gereken şey budur: State'i bloklar halinde basit bir şekilde ve en ekonomik şekilde güncellemek.
GetBuilder RAM'de çok ekonomiktir ve ondan daha ekonomik bir yaklaşım yoktur (en azından ben bir tane hayal edemiyorum, varsa lütfen bize bildirin).
Ancak GetBuilder hala mekanik bir state manager'dir, tıpkı Provider'ın notifyListeners() işlevini çağırmanız gerektiği gibi update() öğesini çağırmanız gerekir.
Reaktif programlamanın gerçekten ilginç olduğu başka durumlar da vardır ve onunla çalışmamak, tekerleği yeniden icat etmekle aynı şeydir. Bunu akılda tutarak GetX, bir State Manager'de en modern ve gelişmiş olan her şeyi sağlamak için oluşturuldu. Sadece gerekli olanı günceller ve gerektiğinde, bir hatanız varsa ve aynı anda 300 durum değişikliği gönderirseniz GetX, yalnızca durum gerçekten değiştiğinde ekranı filtreler ve günceller.
GetX, diğer herhangi bir reaktif durum yöneticisinden hala daha ekonomiktir, ancak GetBuilder'dan biraz daha fazla RAM tüketir. Bunu düşünerek ve Obx'in yarattığı kaynakların tüketimini en üst düzeye çıkarmayı hedefleyerek. GetX ve GetBuilder'dan farklı olarak, bir Obx içinde bir controller başlatamayacaksınız, bu sadece children'larda değişiklik olaylarını alan bir StreamSubscription'a sahip bir Widget'tır, hepsi bu. GetX'ten daha ekonomiktir, ancak reaktif olduğu için beklendiği gibi GetBuilder'a kaydeder ve GetBuilder, bir parçacığın hashcode'unu ve StateSetter'ını depolamak için var olan en basit yaklaşıma sahiptir. Obx ile controller türünüzü yazmanız gerekmez ve değişikliği birden çok farklı controller'dan ulaşabilir ve dinleyebilirsiniz, ancak bu readme dosyasının başındaki örnek yaklaşım kullanılarak veya Bindings classı kullanılarak daha önce başlatılması gerekir.
... ...
... ... @@ -3,14 +3,18 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
import 'package:get_demo/pages/home/domain/adapters/repository_adapter.dart';
import 'package:get_demo/pages/home/domain/entity/cases_model.dart';
import 'package:get_demo/pages/home/presentation/controllers/home_controller.dart';
// import 'package:get_demo/routes/app_pages.dart';
// import 'package:get_test/get_test.dart';
import 'package:matcher/matcher.dart' as m;
import '../lib/pages/home/domain/adapters/repository_adapter.dart';
import '../lib/pages/home/domain/entity/cases_model.dart';
import '../lib/pages/home/presentation/controllers/home_controller.dart';
class MockRepositorySuccess implements IHomeRepository {
@override
Future<CasesModel> getCases() async {
return CasesModel(
... ...