Kategori Arşivi: ‘Flutter’

“Gerçekten” nedir bu BLoC?

Merhabalar, uzun bir süredir yazmaya değer bir konu bulamamam sebebiyle yazılara ara vermiş oldum. Genellikle herkes tarafından yeterince değinildiğini düşündüğüm konuları yazmayı tercih etmiyorum. Yaklaşık 2 sene önce tanıştığım BLoC konusu için ise geç kaldığımı çünkü bu süre zarfında yeterince içerik yayınlanmış olabileceğini düşünmüştüm. Ancak son zamanlarda flutter öğrenmeye çalışan arkadaşlarıma en çok zorlandıkları konuyu sorduğumda “bloc” aldığım yanıtlar arasında hatrı sayılır bir yere sahipti. İtiraf etmek gerekirse benim de flutter yolculuğumda anlamakta ve verimli bir kullanım sağlayacak kadar hakim olmakta en çok zorlandığım konu kendisiydi. Tüm bunları göz önünde bulundurduğumda bu yazıyı yazmaya girişmiş bulundum 🙂 Kişisel olarak, bir konu anlatılırken sadece güçlü ve değerli teorik bilgilerin verilmesi mantalitesine sıcak bakamayanlardanım. Bana göre bir şeyi yapıyorsak “neden yapıyoruz” bunu bilmek gerekir ki (ya da ben fazla sorgulayıcıyım) yaptığımız şey hakkında, ilgili şeyi farklı senaryolarda da yorumlayabilecek kadar fikrimiz olsun. Ben de bu yazıda elimden geldiğince konunun mantığını, size puzzle çözer gibi hissettirmeden temiz bir şekilde aktarmak için elimden geleni yapacağım. Bunu yaparken yazılımsal kavramları yığınla kullanmaktan kaçınıp (e tabii kodlama kısmına kadar????) konunun mantığını öz olarak sunabileceğim bir dil kullanmaya çalışacağım 🙂

Neden BLoC kulllanalım ki?

Bu başlık altında BLoC’ın tarihçesine değinmek gibi bir niyetim yok şimdiden söyleyeyim 😀 Bu konuyu öğrenmek istiyoruz, evet ama neden ki? Neden bunu yapalım? Daha önce BLoC olmadan kod yazdıysanız backend kodları ve ui kodlarının iç içe, aynı class içinde olduğu durumlara aşinasınızdır. (Flutterı henüz yeni yeni öğrenmeye çalıştığım dönemde bu durum benim kafamı oldukça karıştırmıştı) Biz de istiyoruz ki bu spaghetti kodlardan kurtulalım, ui işlemleri ve backend işlemleri birbirinden ayrı yerlerde daha derli toplu, yönetilebilir ve test edilebilir olsun. İşte BLoC dediğimiz pattern, bunu gerçekleştirmek için geliştirilmiş bir kütüphane. BLoC bir state management kütüphanesidir. Bundan ne anlamalıyız? State management/durum yönetimi kavramını şöyle yorumlayabiliriz: Uygulamamızda oluşacak bazı aksiyonlar sonucu, uygulamamızın o an bulunacağı “durum”lara hakim olup birtakım değişiklikler gerçekleştirmek. O halde BLoC bizlere birtakım “olay”lar karşısında birtakım “durum”lar üretme olanağı sunar.

Yavaş yavaş konuya girelim…

Birtakım “olay”lar karşısında, birtakım “durum”lar üreteceksek eğer bizlere olaylar, durumlar ve bunları birbiri ile ilişkilendireceğimiz, mantık akışını yaratacağımız bir alan/bağlam gerekir. (İşin özü aslında bu cümleden ibaret :)) Olaylar, durumlar ve aralarındaki ilişki… Hmm o zaman bunları biraz konuya uyarlayalım. İşte biz bu “olay, durum, mantık akışı/ilişki” kavramlarını tam olarak BLoC patterninde yer alan events, states ve bloc sınıfı ile yapıyoruz/yapacağız.

Event, States, BLoC Sınıfları

Event classları bizim olaylarımızı, state classları durumlarımızı temsil ederken BLoC sınıfımız ise işin logic kısmını üstlenip “arayüz ve backend” arasında adeta bir arabulucu görevi görecek. Bildiğimiz üzere kullanıcıların uygulamalar ile etkileşimi arayüz katmanında gerçekleşir. Biz de kullanıcının hareketlerine göre bir ‘şeyler’(!) gerçekleştiririz. O halde arayüzümüzden bloclara (ilgili bloc sınıfları) “bak user x butonuna tıkladı” gibi haberler göndereceğiz. (Tabii ki bazen kullanıcıdan bağımsız, programda farklı sınıf ve blocların haberleşmesi de söz konusu olabilir.) BLoC sınıfımız ise bu haberin geldiğini tespit ettiğinde servisler, databaseler, helperlar vs. ilgili sınıflara gidip gerekli bilgileri, aksiyonları alacak, gerekli işlemleri başlatacak ve sonrasında da bu konuyla ilgilenen kim varsa “ben gerekli işlemleri başlattım ve şu an x aşamasındayım (x durumunda/x stateinde)” diyecek (state bildirimi). Bunu duyan sınıflar da ilgili state’e göre gerekli ise bir işlem başlatacak ya da ui güncelleyecek. Konunun mantığını biraz olsun anladık varsayıyorum. (Kabaca user interaction yada app akışı-> bir event üretir -> BLoC -> state üretir -> ui, listenerlar, diğer sınıflar vs. bu bilgiyi kullanır diyebiliriz.)

E dinlemek diyoruz, haber vermek diyoruz, ui güncellemek diyoruz. Peki nasıl yapacağız bunları? Size dinlemek için listenerlar olduğunu, state/duruma göre ui oluşturmak için builderlar olduğunu söylesem konunun aslında ne kadar İngilizce/Türkçe insan dili olduğunu görebilirsiniz sanırım. BLoC patterninde konuştuğumuz her şeyin karşılığı var. Listener (dinleyici), builder (oluşturucu) vs. bu componentler, bize anlatılanları, yazılım tarafında gerçekleştirmemize yardımcı olacak. Hadi o zaman bunlara bir göz atalım.

BLoC Componentleri

BLoC öğrenirken belki de en çok zorlandığım şey componentlerin mantığını iyi oturmaktı. Neyi ne zaman kullanacağımı birilerinin kodlarını inceleyerek çözmeye çalışmak ve anladığımı sandığım yerde kendi projem için uygun bloc yapısını oluşturamamak… (Fizik hocasının çözümünde mantıklı gelen formülü, başka soruda uygulayamamak gibi bir şey…) BLoC pattern biraz da deneyimledikçe optimal kullanıma ulaştığımız bir konu aslında.

BLoC Provider/Multi Bloc Provider:

BlocProvider adı üzerinde bir sağlayıcıdır. Bloc providerlar bize ilgili blocımızı context içerisinde kullanmayı sağlarlar. Bunu bir nevi ilgili blocımızı, uygulamamızın contextine kayıtlandırıyormuşuz gibi düşünebiliriz. Sonuçta kayıtlanmamış şeylerin varlığından haberimiz olmaz ve kullanamayız. BlocProvider.of<T>(context) bize context üzerinden ilgili bloc nesnemize erişim verir. Blocımıza ait bir provider tanımlamadan o blocı ilgili context içinde kullanamayız. Burada BlocProviderın bloca, oluşturduğumuz contextin sub-treelerinde/alt ağaçlarında erişim verdiğini unutmayalım. Yeni başlayanlar bu konsepti anlamadığı için güzel hatalar alabilir 😀 (kod bölümünde örneklendirdim)

MultiBloc provider ise birden fazla bloc providerı kullanmaya olanak sağlayan bir widgettır. Birden fazla bloc providerın kullanılması gereken senaryolarda iç içe bloc providerlar oluşturmaktan kurtulup daha düzgün kodlar elde edebiliriz. Eğer uygulamamızda birden fazla bloc varsa birbiri içine providerlar yazmak yerine hepsini liste içinde parametre olarak alan tek bir multi bloc provider yazmamız çok daha düzgün bir kod elde etmemizi sağlayacaktır. Aynı zamanda yönetimlerinin kolaylaşması da söz konusu olur. (Ekleme, çıkarma vs.)

BLoC Listener:

Her kavramın isimlendirmesi adeta bir özet gibi. Bloc listenerlar bizim blocımızdaki “değişimleri dinlememizi” sağlayan componentlerdir. Bloc listenerlar genellikle durumlardaki değişimlerin takibi için kullanılır. Listenerların tetiklenmesi için “değişim” gerekir. Bu davranış biçimini, yazdığımız kodlarda loglama yaparak gözlemleyebiliriz. Ne gibi?

Bu şekilde listenerlarımızın içine eklediğimiz custom loglar, başlarda nasıl davrandığını anlamak için yardımcı olabilir.

BlocListener, örneğin bir hata durumunda uyarı ekranına ya da hata ekranına yönlendirme gibi işlem yapılacaksa kullanılır. Burada işin Türkçesi şudur:

BlocA blocını sürekli dinleyen bir dinleyicimiz BlocA’nın durum değişimlerinden haberdardır. Örneğin BlocA bir başlangıç durumunda iken bir hata durumuna dönüşmüşse bu hata durumunun Bloc tarafında emit edildiği anda bunu yakalar.

Yine bu listener, dinlenen durumlar içerisinde yakalamak istediği bir x durumu olduğunda yapmak istediği bir işlem varsa bunu gerçekleştirir.

Kabaca bir örnek verelim ve açıklayalım.

BlocListenerlar her blocı dinleyemez değil mi? Hangisini dinleyeceğini belirtmemiz gerekir. (generic type bildirimi) Burada şunu diyoruz: sen BlocA’yı dinliyorsun evet ve eğer bir fail durumu yakalarsan ben uygulamamın error sayfasına yönlenmesini isterim, bu sebeple bu condition/şartım gerçekleştiğinde ilgili fonksiyonumu çağır.

Şununla karıştırmayalım: Bloclarımızın hangi eventta hangi duruma geçtiğini loglamak istersek bunun için bloc observer kullanırız. Buna kod bölümünde değineceğim.

BLoC Builder:

Bloc konseptinin en çok kullanılan bileşenlerinden biri bloc builderdır. Bloc builder, içinde builder fonksiyonunu bulunduran (ki bu fonksiyon mutlaka bir widget döndürmelidir.) bir bileşendir. Bloc builder, bize state’e göre bir widget gösterme olanağı verir. Bu bileşenlerin nasıl kullanılacağı ile ilgili örnekleri vereceğimiz için şimdilik ne amaçla kullandığımızı bilmekle yetinebiliriz.

Multibloc Listener:

Eğer aynı contextte farklı birkaç bloc listenera ihtiyaç duyuyorsak, bunları multibloclistener çatısı altında tutabiliriz. (MultiBlocProvider da bu konsepte sahip) Multibloc listener, birden fazla bloc listenerı liste olarak parametre alan bir componenttir. Multibloc listenerı kullanarak iç içe bulunan bloc listener widgetlarından kurtulup daha okunulabilir bir kod parçası yazabiliriz.

BLoC Consumer:

Bloc Consumer, eğer bir bloc için hem listener hem de buildera ihtiyaç duyuyorsak ikisini bir arada kullanmamızı sağlar. “E zaten hem listener hem buildera ihtiyacım varsa ikisini de iç içe oluştururum, consumera ne gerek var?” derseniz bu da bir tercih olabilir tabii. Zaten bloc consumer da koddaki gereksiz iç içe kullanımlardan kurtarmak amacıyla kullanılan bir widgettır. Yani iç içe listener ve builder da yazabiliriz, direkt bloc consumer da kullanabiliriz. Tabii burada tercih bloc consumer olsa daha doğru bir kullanım olur ????.

Kodlara Dökelim 🙂

Hadi şimdi tüm anlattıklarımızı darta dönüştürerek biraz pekiştirme yapalım… Öncelikle boş bir flutter projesi oluşturalım. Ve bloc paketimizi yaml dosyamıza ekleyelim.

Hem bloc builder kullanmanın mantıklı olacağı use caseleri barındıracak hem de birden fazla state/duruma ihtiyaç duyacak bir proje konusu ne olabilir diye düşündüğümde aklıma hava durumu uygulaması geldi. Burada api isteklerini beklerken farklı sonuç geldiğinde farklı bir ui gösterebiliriz.

En basit haliyle bir hava durumu uygulaması yaratmak için öncelikle bize bir hava durumu blocı gerekir. Aynı zamanda isteklerimizi atmak için bir servisimiz olsun. (Burada amaç blocın özünü anlatmak olduğu için konseptten kopmamak adına uygulamaya çok işlevsellik katmayacağım.) Bir de api’ye istek atıp response’u parse edebileceğimiz bir modelimiz olacak. Bloc sınıfları dışındaki sınıfların üzerine çok düşmeyeceğiz. Şunu biliyoruz: Bir bloc pattern için events, states ve bloc sınıfı olmak üzere 3 ana sınıf gerekir. O halde şimdi gerekli dosyalarımızı oluşturalım.

Bloc Yapısı için Sınıfları Oluşturmak:

Öncelikle ön hazırlık olarak apiye istek atmak için birer request, response ve apiden dönen bilgileri parse edeceğim info modeli oluşturdum. Sonrasında bu apiye istek atacağımız bir servis sınıfımız var. Şimdi bloc tarafını düşünelim. Neler gereklidir? Bizi zorlamayacak bir mimari oluşturmak için önceden potansiyel senaryoları düşünmek oldukça önemlidir.

Kendi deneyimlerimden çıkardığım bir sonucu sizlerler paylaşmak istiyorum, eğer bir işlemi bloc ile gerçekleştirirken karmaşık geliyorsa ya da süreci yönetmekte zorlanıyorsanız muhtemelen olayları, durumları kısacası mimariyi uygun şekilde oluşturmamışsınız demektir. Bu yüzden bloc pattern ile çalışırken öncelikle gerçekleşecek/gerçekleşebilecek olayları ve durumların taslağını çıkarmak önemlidir. Tabii ki sonrasında projenin ihtiyacına göre değişiklikler gerekir fakat ilk oluşturma için bu durum önem arz eder.

Events Sınıfı

Öncelikle events sınıfımızı göz önünde bulunduralım. Bunun için ilk olarak soyut bir olaylar sınıfı oluşturacağız sonrasında bundan extend edilen asıl olay sınıflarımızı ekleyeceğiz. Şu an için olayımız usera göstermek adına hava durumu bilgilerini getirmek olabilir. O halde blocımız için event sınıfımızın adı EventWeatherGetInfo olabilir. Biz bu sınıfı bloca bildirip ‘bize şehrin hava durumu bilgilerini getir’ diyeceğiz. O zaman bizim bu eventı bloca bildirirken hangi şehirden bahsettiğimizi de söylememiz gerekir değil mi?

Bu durumda bu sınıfımıza bir şehir bilgisi alanı girmeliyiz ki bu bilgiyi bloc tarafa taşıyabilelim.

İşte şimdi events sınıfımız tamamlandı. Peki neden abstract class oluşturduk ya ezbere mi yapıyorsun bunu? Yoo, hemen söyleyelim. Biz işin logic kısmını yapmak için Bloc sınıfımızı oluştururken aslında bloc paketimizde bulunan Bloc sınıfımızdan miras alacağız. Bu miras alma esnasında generic typeımızda event ve state bildirimi yapmamız gerekmekte. NEDENNN? Çünkü eğer bu generic type bildirimini yapmazsak oluşturacağımız bloc sınıfımız <dynamic, dynamic> tipe sahip bir bloc olur. Bu da bizim belirlediğimiz state ve event classlarının tipiyle uyuşmazlık yaratır ve birçok componenti kullanırken bu konuyla ilgili hata alırız.

Bir event sınıfını generic type olarak vermemiz gerekiyor ama bizim bir çok eventımız var (şu an için bir tane olsa da başka projelerde birden fazla olacak) e hangi birini vereceğiz? İşte bunun için tüm olaylarımızı temsil edecek soyut bir sınıf oluşturup bunu blocımıza bildiriyoruz. Sonrasında örnekte de gördüğümüz gibi yeni bir olay sınıfı yaratmak isterken de bu abstract classımızdan miras alıyoruz ki bu generic typeımız ile bir uyuşmamazlık yaşamayalım. Aynı durum stateler için de bu şekildedir. Sanırım şimdi oldu 🙂 Hadi devam edelim.

Stateler…

Gelelim state sınıflarımıza. Stateler, appimiz için o bloc bünyesinde yaptığımız eylemler sonucunda oluşabilecek durumları temsil eden sınıflardır. Şimdi kendi use caseimizi düşünelim. Ne yapıyoruz? Bir apiye istek atıp bazı hava durumu bilgilerini alıyoruz. Bu durumda ne olabilir ki? Birincisi başarı ile bu isteği atıp, sonucu alıp kullanıcıya bunu gösterebiliriz. İkincisi, bu isteği atarken bir hata alabiliriz ve kullanıcıya bir hata meydana geldiğine dair bilgilendirme yapabiliriz. O halde bunları göz önünde bulundurarak 2 adet durum oluşur diyebiliriz. Bir de apiden istek dönene kadar bir bekleme durumu oluşabilir. Böylece 3 adet durumumuz var diyebiliriz. Peki ya herhangi bir olayı henüz tetiklememişken bloc sınıfımızdan bir bloc nesnesi üretip kullanıma hazır hale getirirken o esnada durum ne olur? Bu durum için de bloc sınıfımıza bir başlangıç durumu atayabiliriz. Böylece artık 4 durum sınıfı oluşturmamız gerektiğini anladık. Şimdi bir de şunu düşünelim bloc sınıfımıza eventımız vasıtasıyla “kullanıcı x şehri için hava durumlarını istiyor, bunları getir” dedik. Bloc sınıfımız ise bir arabirim, haberci gibi davranarak ilgili api servisine bu isteği iletip sonucu alacak ve app bazında “artık sonuçlar hazır” ya da “apiden sonuçları getirirken hata çıktı” gibi durumlara dönüştürecek. Bu durumda, bunları bildirirken eğer istek başarılıysa bu başarılı sonucun değerlerine erişebilmeli ve bir WeatherInfo (api responseunu parse etmek için oluşturduğumuz model sınıfı) sınıfı nesnesi aracılığıyla ilgili bilgilere sahip olmalıyız. Burada yazdığımız apinin responseunu incelemekte fayda var. Örneğin bizim kullanacağımız api 7 günlük bir hava durumu bildirimi sunar. Dolayısıyla burada kullanıcıya bir List<WeatherInfo> değişkeni üzerinden bilgileri göstermemiz gerekir. Aynı şekilde bir hata durumunda kullanıcıya hata mesajımızı göstermek istiyorsak, bunun için de failed durumuna bu mesajı atayabileceğimiz bir alan vermemiz şarttır.

Bu bilgiler ışığında statelerimizin son hali:

şeklinde olur diyebiliriz.

NŞA’da kodlama yaparken naming convention benim için oldukça önemlidir. State sınıfı için ise naming conventionda isimlerin kullanılması önerilir çünkü bahsi geçen durum bir nevi o “an”ın temsilidir. Örneğin bir işlem tamamlanmışsa ProcessCompleted değil ProcessComplete olmalıdır. Ancak ben state sınıflarımı kişisel insiyatifimle bu şekilde anlandırıyorum. Lütfen siz naming conventionları buradan inceleyin. Sonrasında kendi kararınızı verin 🙂

Bloc Sınıfı

Gelelim işin logic kısmının döndüğü asıl sınıfımız olan Bloc sınıfımıza. Projenin akışını, eventları, stateleri vs. önceden düşünüp iskeletimizi oluşturduktan sonra bloc sınıfımızı yazmak oldukça kolay olacaktır. (en azından bu ölçütte bir proje için :D) Önceden bloc sınıfı mapEventToState adında eventları state’e dönüştüren ve stateleri yield eden streame sahipti. Burada developerlar için, stream, yield, yield*, async* gibi kavramların öğrenme yükünü azaltmak, iç içe async işlemlerde hangi durumun olacağının bazen öngörülememesi gibi sebeplerle stream yerine “event handler”ların kullanılmasına karar verildi.

Event handlerlar (on<YakalanmasınıİstediğimizEvent>) hangi olayda ne işlem yapacağımızı bildirmemize olanak sağlar. Böylece olay karşısında alınacak aksiyonun öngörülebilir olması için bir olay ile ((Event event, Emitter<State>) {} şeklinde) bir callbacki eşleştirebiliriz. Bu callbackler asenkron olabilir. Aynı zamanda callback üzerinden tetiklenen event/olaya erişebildiğimiz için o eventın field değerlerine de erişebiliriz. Ne demek istiyorum?

Bloc sınıfımız yukarıdaki gibi. Özetlemek gerekirse bloc için bir constructor tanımladık ve default olarak initialize durumu ile ilgili bloc nesnemizi başlatmaya olanak sağladık.

Satırı ile bir event handler tanımladık. Aslında burada, eğer EventWeatherGetInfo eventını yakalarsan _getWeatherInfo callbackini tetikle şeklinde bir tanımlama gerçekleştirdik. Şimdi bu callback değerimizi inceleyecek olursak…

Buradaki kodun oldukça okunabilir olduğunu düşünüyorum ancak özetlemek gerekirse: Öncelikle asenkron bir işlem başlatacağımız ve bunun ne kadar süreceğini bilemediğimiz için hızlıca bir bekleme durumuna geçtiğimizi belirten statei emit ediyoruz. (Aslında bloc builderı anlatmak için biraz bahane :)) Sonrasında apiye istek atıyoruz. Sonucumuz başarılı ise başarılı olma durumuna geçip bu ilgili statein de fieldına responsedan dönen bilgimizi (hava durumları listesi) veriyoruz. Eğer başarılı değil ise de fail stateine geçip yine errorMessage olarak constructorına eklediğimiz değeri giriyoruz.

Burada eventın fieldına nasıl eriştiysek (event.city kullanımı) state sınıflarına field olarak verdiğimiz bu değerlere de ui tarafında aynı kullanım ile erişeceğiz (state.errorMessage gibi).

Artık bloc sınıfımız hazır. Umarım neyi neden yaptığımızı ve nasıl yapacağımızı anlamışsınızdır 🙂 (Anlamadıysanız da sorun değil, buyrun iletişime geçelim). Artık anlatımımıza UI kısmıyla devam edebiliriz.

UI, BLoC Componentleri

Bloc mimarimizi oluşturduk, şimdi ise bunu projenin presentation katmanında nasıl kullanabiliriz sorusuna bakalım.

Şimdi böyle baya ince düşünülmüş bir UI’ımız olsun 😀 (Kodların ss olmasına takılmayalım repoyu paylaşacağım. )

Burada, butonumuza tıkladığımızda tetiklenecek bir fonksiyonumuz var, gördüğümüz üzere adı da _getWeatherInfo(). Biz bu fonksiyon içerisinden ilgili blocımıza bir event göndereceğiz. Bunu gönderirken textfieldımız içerisindeki şehir bilgisini de ileteceğiz.

Bloc tarafta bir eventı nasıl yakaladığımızı (event handlerlar ile) anlatmıştım. Peki bloc’a eventı nasıl iletiriz? Bunun için Bloc nesnesi üzerinden .add(EventSınıfımız(field: fieldDeğerimiz)) şeklinde bir kullanım yapabiliriz. Bir başka deyişle add ile bloclarımızda olay tetikleme gerçekleştiririz. O halde bizim bunu yapmak için bu bloc değerine erişimimiz gereklidir. Alt ağaçlardan bloc nesnesine erişmek için bloc provider üzerinden bir bloc sağlayıcı oluşturmamız gerekir ki biz bu blocı kullanabilelim. Ben bu providerımı, üzerinde çalıştığım PageMain’imi kapsayan main widgetta ekledim ki alt ağaçlardaki contextler üzerinden erişimimim olabilsin.

Şimdi peki bu provider üzerinden PageMainimde nasıl bir erişim gerçekleştirebilirim? Bunu şöyle yapabiliriz. Main sınıfımızın init state’i içerisinde contextten okunup alınmak üzere bir BlocWeather tipinde nesne oluşturabiliriz. Şöyle ki:

late ile sonradan değerinin atanacağını bildirip, initStateimizde bu atamayı gerçekleştirdik.

İlgili butonumuzun fonksiyonu içerisinde de yukarıdaki gibi bir kullanımla olayımızı tetikleriz. Ne yapıyoruz? add ile bir nevi “sana şu olayı gönderiyorum“ mesajını blocımıza iletiyoruz. Buradaki _textController.text ifadesi ise daha önce EventWeatherGetInfo sınıfımız için oluşturduğumuz city değeridir, bunu constructorda set ediyoruz. İşte bu kadar basit.

Şu ana kadar söz konusu iletişimi nasıl yapacağımızı düşündük. Bir de şöyle bir şey gerçekleştirelim: Butonumuzun hemen altında, bize bilgi gelirken bir yükleniyor ibaresi görünsün, sonuç geldiğinde ise bu bilgileri görelim. O halde aslında burada ne oluyor? Önceden belirlediğimiz bloc statelerine göre farklı widgetlar gösterme gereksinimi duyuyoruz. Dikkat ederseniz bu use case tam olarak BlocBuilderın tanımındaki senaryoya örnektir. Bu sebeple butonumuzun hemen altına bir bloc builder eklememiz gerektiği sonucunu çıkarabiliriz.

Uygulamamızın ilgili bölümünde, builderımız içerisinde kendi koyduğumuz state conditionlarına göre istediğimiz widgetları döndürmeliyiz. O halde yukarıda önceden tasarladığımız akışa göre return edeceğimiz widgetlarımızı ekleyelim:

Artık uygulamamızı tümüyle tamamladık.

Eğer main.dartta providerımızı tanımlamasaydık: BlocProvider.of() called with a context that does not contain a BlocWeather. şeklinde bir hata alacaktık.

Tüm yaptıklarımız sonucunda uygulamamızın son hali:

Yazı burada bitiyormuş gibi görünüyor (ben de bitti sanmıştım ????) ama son olarak bloc kullanırken hangi olayın tetiklendiğini, hangi duruma geçildiğini kısacası blocımız içerisinde neler olup bittiğini anlamımızı sağlayacak bloc observerdan da bahsedelim.

Bloc Observer

Bloc observer sınıfı bloc paketinde bulunan ve içerisinde bloclarda gerçekleşen error, change gibi durumları alarak bazı işlemler gerçekleştirmemizi sağlayan, kısacası bloc/larımızı gözlemlemiz için kullanılan bir soyut sınıftır. Uygulamalarımız için bu sınıfın metotlarını override ederek kendi custom observer sınıfımızı yazabiliriz.

Bunun için:

şeklinde BlocObserverdan miras alan CustomBlocObserver sınıfı oluşturabiliriz. Burada her metodu override etmek zorunda değiliz, ihtiyaç duyduklarımız bizim için yeterli olacaktır. Ben 3 önemli metodu override ederek sınıfımızı tamamlıyorum.

Sınıfımızı oluşturduk bir de sınıfımız ile Bloclar arasında bir bağlantı gerekir. Bunu da main metodumuz içerisinde gerçekleştirebiliriz. Böylece:

olan sınıfımıza

ilgili satırı ekleyerek bu bağlantıyı tamamlamış oluruz.

Tüm sürecin sonunda artık loglarımızda ‘bloc observer output’ görselinde de görüldüğü gibi blocımızın state geçişlerini vs. daha rahat gözlemleme şansı elde etmiş olduk.

Yazımızı burada noktalayabiliriz. Umarım işin temelinin nasıl bir mantıkla işlediğini aktarabilmişimdir, teşekkürler 🙂

Herhangi bir soru için LinkedIn üzerinden iletişime geçebilirsiniz.

Proje repoya buradan erişebilirsiniz. Ya da direkt tıklayarak indirebilirsiniz.

Daha fazlası için: resmi dokümandan yardım alın.

Kaynak : “Gerçekten” nedir bu BLoC?. Merhabalar, uzun bir süredir yazmaya… | by Burcu S | Medium

Kategori Featured, Flutter
12.05.2023
72 Okunma

Flutter’da Sayfalar Arası Geçişler

Flutter’da tek sayfa tasarımını yapmak kadar, oluşturulan çoklu sayfalar arasındaki geçişi sağlamak da önemlidir. Bazen bir sayfadan diğerine geçerken, önceki sayfaya geri dönülmesini istemeyebiliriz ya da bir sayfada kullanıcıdan edindiğimiz bir bilgiyi, başka bir sayfada kullanmak isteyebiliriz.

Bu makalede sizlere Flutter’da sayfalar arası geçişlerin nasıl yapıldığıyla ilgili ayrıntıları aktaracağım. Basit olanından, ayrıntılı olanına doğru bir yolculuğa çıkacağız.

1) Navigator.push & MaterialPageRoute & Navigator.pop

İlk olarak sayfalar arası geçişler için Navigator sınıfını kullanacağız. Bu amaçla üç sayfalı bir örneği incelemekle başlayacağız. Şimdi bu konuya özel Flutter’da yeni bir proje başlatın ve aşağıdaki gibi; Sayfa 1Sayfa 2 ve Sayfa 3 şeklinde üç sınıf oluşturun. Bu üç sayfayı sadece geçişler için kullanacağımızdan herhangi bir içerik girmemize şimdilik gerek yok.

Kodu çalıştırdığımızda Sayfa 1 sınıfı inşa edilecektir ve ekranda aşağıdaki sayfa gözükecektir.

Ekranda bulunan Sayfa 2’ye Git düğmesine basıldığında Navigator.push(…) constructor’ı (yapıcı metodu) tetiklenmiş olacaktır.

Navigator.push iki parametre almaktadır. Biri context, diğeri de yeni sayfayı inşa etmeye yarayan MaterialPageRoute sınıfıdır.

MaterialPageRoute ile anlık olarak bir sayfa tasarımı sunulup, önceki sayfadan gelen kullanıcı, yeni oluşturulan sayfaya yönlendirilmiş olur. Yeni sayfanın özellikleri, MaterialPageRoute içerisindeki builder: parametresi ile verilir.

Sayfa2 sınıfı daha önceden hazır olduğu için builder parametresindeki fonksiyon, direkt olarak Sayfa2‘ye döndürülür.

MaterialPageRoute(builder: (context) => Sayfa2())

Böylece birinci sayfadan, ikinci sayfaya geçiş yapmış olduk.

İkinci sayfada iki buton bulunmaktadır. Bunlardan biri Geri dön! diğeri de, Sayfa 3’e Git! butonudur. Üçüncü sayfaya geçiş yapmamızı sağlayan butonda, bir önceki sınıfta olduğu gibi, Navigator.push komutu bulunmaktadır. Birinci sayfadan, ikinci sayfaya nasıl geçtiysek, ikinci sayfadan üçüncü sayfaya da aynı mantıkla geçebiliriz.

Fakat yeniden birinci sayfaya geri dönmek istersek, Navigator.pop(…) komutunu kullanmamız gerekir.

Geri dön! butonuna basıldığında, onPressed parametresinde görebileceğiniz gibi,

onPressed: () => Navigator.pop(context)

ifadesi yer alır. (Sayfa2 sınıfı, 37. satır) Bu sayede istersek ilk sayfaya geri dönebiliriz. Geri dönme işlemini bu butonla yapabildiğimiz gibi, cihazımızda bulunan Geri düğmesi ile de aynı işlemi yapabiliriz. Ayrıca tasarımımızda bir AppBar kullandığımız için, otomatik olarak AppBar üzerinde de bir geri dönme butonu aktif olacaktır. Üstteki resimde geri dönme işlemini yapabileceğimiz üç bölge kırmızı yuvarlakla gösterilmiştir.

Böylece üçüncü sayfaya gelmiş olduk. Sayfa 3 sınıfında da görebileceğiniz gibi, üçüncü sayfada sadece bir Geri dön! butonu bulunur ve bizi ikinci sayfaya taşır.

Bu şekilde hazırladığımız bu üç sayfa arasında kolaylıkla geçiş yapabildik. Şimdi biraz daha ayrıntıya girelim.

Kaynak : Flutter’da Sayfalar Arası Geçişler | by Zeki ÇIPLAK | Flutter Türkiye | Medium

Kategori Featured, Flutter
08.04.2023
140 Okunma

Flutter Timer Sınıfı

Flutter Timer, bir uygulamada zamanlama işlemlerini gerçekleştirmek için kullanılan bir sınıftır. Flutter Timer, belirli bir süre sonunda işlemlerin gerçekleştirilmesini sağlar. Bu makalede, Flutter Timer ile ilgili tüm fonksiyonları ele alacağız.

Flutter Timer’ın Temel Kullanımı

Flutter Timer, dart:async kütüphanesi altında yer alan Timer sınıfından türetilmiştir. Timer sınıfı, bir işlemi belirli bir süre sonra yürütmek için kullanılır. Flutter Timer, Timer sınıfına ek olarak, süreye bağlı olarak tekrarlayan işlemler gerçekleştirmek için tasarlanmıştır.

Flutter Timer’ın temel kullanımı aşağıdaki gibi olacaktır:

Bu kod, 5 saniye sonra konsola “Flutter Timer” yazdıracaktır.

Flutter Timer’ın Çalışma Prensibi

Flutter Timer, bir işlemi belirli bir süre sonra yürütmek için kullanılır. Timer sınıfından türetilmiş olan Flutter Timer, süreye bağlı olarak tekrarlanan işlemler gerçekleştirmek için tasarlanmıştır. Flutter Timer, zamanlayıcı işlemi gerçekleştirmek için bir işlev alır. Bu işlev, zamanlayıcı süresi dolduğunda çalıştırılacaktır.

Flutter Timer, başlat () yöntemi çağrıldığında zamanlayıcıyı başlatır. Başlat () yöntemi, iki parametre alır: süre ve işlev. Süre, zamanlayıcının çalışma süresini belirlerken, işlev, zamanlayıcının süresi dolduğunda gerçekleştireceği işlemi belirler.

Flutter Timer’ın Özellikleri

Flutter Timer, birçok özellik içerir. Bu özellikler, zamanlayıcının işlevselliğini artırmak için tasarlanmıştır. Aşağıdaki özellikler, Flutter Timer ile ilgili en önemli özelliklerdir:

  • Süre: Süre, zamanlayıcının çalışma süresini belirler. Süre, Duration sınıfından türetilir. Duration sınıfı, zaman aralıklarını ve süreleri temsil etmek için kullanılır.
  • İşlev: İşlev, zamanlayıcının süresi dolduğunda gerçekleştireceği işlemi belirler. İşlev, Function
  • Tekrarlayan İşlemler: Flutter Timer, tekrarlayan işlemler gerçekleştirmek için tasarlanmıştır. Bu özellik, zamanlayıcının süresi dolduğunda işlevi tekrarlayarak, belirli bir süre boyunca işlemleri gerçekleştirmesini sağlar.
  • İş Parçacığı: Flutter Timer, varsayılan olarak ana iş parçacığında çalışır. Bu nedenle, zamanlayıcı işlemleri ana iş parçacığında gerçekleştirilecektir. Ancak, zamanlayıcı işlemleri farklı bir iş parçacığında gerçekleştirmek için de yapılandırılabilir.

Flutter Timer’ın Fonksiyonları

Flutter Timer, birçok fonksiyona sahiptir. Bu fonksiyonlar, zamanlayıcının işlevselliğini artırmak için tasarlanmıştır. Aşağıdaki fonksiyonlar, Flutter Timer ile ilgili en önemli fonksiyonlardır:

  • start(): Zamanlayıcıyı başlatmak için kullanılır. Bu yöntem, zamanlayıcının süresi dolduğunda gerçekleştirilecek işlemi belirler.

  • cancel(): Zamanlayıcıyı iptal etmek için kullanılır. Bu yöntem, zamanlayıcının süresi dolduğunda gerçekleştirilecek işlemi iptal eder.

  • isActive: Zamanlayıcının aktif olup olmadığını belirlemek için kullanılır. Bu yöntem, zamanlayıcının aktif olup olmadığını kontrol eder ve true veya false değerleri döndürür.

  • periodic(): Sürekli olarak tekrar eden işlemler için kullanılır. Bu yöntem, zamanlayıcının süresi dolduğunda gerçekleştirilecek işlemi tekrarlayarak, belirli bir süre boyunca işlemleri gerçekleştirir.

Flutter Timer, mobil uygulama geliştiricilerinin zamanlama işlemlerini gerçekleştirmek için kullanabilecekleri çok yönlü bir araçtır. Flutter Timer, belirli bir süre sonunda işlemlerin gerçekleştirilmesini sağlar ve tekrarlayan işlemler için özellikler içerir. Bu makalede, Flutter Timer ile ilgili tüm fonksiyonları ele aldık ve kullanımı hakkında bilgi verdik.

Aşağıdaki örnekte, kullanıcının belirlediği bir süre boyunca geri sayım sayacı çalışacak ve her saniye güncellenecektir:

Yukarıdaki örnekte, _startTimer fonksiyonu, kullanıcının belirlediği süreye göre geri sayım süresini ayarlar ve _timer değişkenine bir Timer.periodic nesnesi atar. Timer.periodic fonksiyonu, belirli bir aralıkta geri sayım yapmak için kullanılır. Her saniye, geri sayım değeri bir azaltılarak, _secondsRemaining değişkeni güncellenir ve ekranda gösterilir. Geri sayım sıfıra ulaştığında, _timer iptal edilir.

Scaffold içinde, geri sayım değeri ekranda gösterilir ve ElevatedButton üzerinde tıklanarak geri sayım başlatılır. Yukarıdaki örnek, Flutter Timer kullanarak basit bir geri sayım sayacı oluşturmanın temelini göstermektedir. Bu örneği istediğiniz gibi değiştirebilir ve özelleştirebilirsiniz.

Aşağıda saat,dakika ve saniye cinsinden saatin son hali görünmektedir.

Kategori Featured, Flutter
29.03.2023
111 Okunma

Flutter Card Uygulaması

 

Kategori Featured, Flutter
25.03.2023
92 Okunma

Flutter TextStyle Kullanımı

TextStyle, Flutter’da metin öğelerine stil uygulamanın temel yoludur. Metin stilleri, örneğin font boyutu, renk, vurgulama ve ayrıştırma ayarları gibi metin öğelerindeki çeşitli özellikleri belirleyen bir nesnedir.

Öncelikle, bir TextStyle nesnesi oluşturmak için TextStyle sınıfını kullanarak başlayabiliriz. Aşağıdaki örnek gibi bir TextStyle nesnesi oluşturalım:

Bu kod bloğu, 20 piksel boyutunda kalın siyah bir metin stilini tanımlar. fontWeight özelliği, metnin kalınlığını belirler. Burada, FontWeight.bold ile metnin kalınlığı en yüksek ayara getirilmiştir. Ayrıca, metin rengi de belirtilmiştir.

Şimdi bu metin stilini kullanarak bir metin öğesi oluşturalım:

Bu kod bloğu, “Flutter yazılımı harikadır!” ifadesini myTextStyle nesnesiyle stilize eder. TextStyle nesnesi, metnin stil özelliklerini belirttiğimiz yerdir.

Biraz daha karmaşık bir örnek yapalım ve metin stilini daha ayrıntılı hale getirelim. Aşağıdaki kod bloğu, farklı renklerdeki ve boyutlardaki metinleri içeren bir sütun oluşturur:

Bu kod bloğu, üç farklı metin öğesi oluşturur, her biri farklı bir stil özelliğiyle donatılmıştır. İlk metin normal kalınlıkta ve mavi renklidir, ikinci metin kalın ve kırmızı renklidir, üçüncü metin ise eğik yazı stili ve yeşil renkli olarak belirlenmiştir.

Sonuç olarak, TextStyle, Flutter’da metin stillerinin uygulanması için çok kullanışlı bir araçtır. Bu örneklerin yardımıyla, farklı metin stillerini uygulama konusunda daha fazla fikir edinmiş olabilirsin.

Aşağıdaki örnek, kullanıcı tarafından belirtilen parametrelere göre farklı metin stilleri oluşturur:

Bu kod bloğu, CustomText adlı bir özel widget sınıfı oluşturur. Bu widget, text, fontSize, color, fontWeight ve fontStyle gibi parametreler alır. Bu parametreler, metin stilinin farklı özelliklerinin belirlenmesini sağlar.

Bu özel widget’ı kullanarak farklı metin stilleri oluşturabiliriz:

Bu kod bloğu, CustomText sınıfını kullanarak üç farklı metin öğesi oluşturur. Her biri, farklı bir parametre değeri ile farklı bir metin stilinde gösterilir. Bu, kullanıcıların metin stillerini kolayca özelleştirebileceği ve uygulamamızdaki metinlerin daha çeşitli ve özelleştirilmiş görünmesini sağlar.

Sonuç olarak, TextStyle, Flutter’da metin stilleri oluşturmak için kullanışlı bir araçtır. Parametreler eklemek, metin stillerinin özelleştirilmesini ve uygulamalarda daha çeşitli metin stillerinin kullanılmasını sağlar.

Flutter’da TextStyle kullanarak oluşturabileceğimiz 10 farklı örnek şunlar olabilir:

Başlık metni stilini oluşturma:

Alt başlık metni stilini oluşturma:

Normal metin stilini oluşturma:

İtalik yazı stili oluşturma:

Metin gölgesi ekleyerek yazıyı vurgulama:

Altı çizgili metin stilini oluşturma:

Üstü çizgili metin stilini oluşturma:

Gölgeli metin stilini oluşturma:

Harf büyüklüğünü küçültme:

Çok satırlı metinler için satır yüksekliğini ayarlama:

 

Kategori Featured, Flutter
21.03.2023
85 Okunma

Flutter Custom Font Ekleme

Flutter’da özel font eklemek için aşağıdaki adımları takip edebilirsiniz:

İlk olarak, kullanacağınız özel font dosyasını projenize eklemeniz gerekiyor. Bu dosyayı, “assets/fonts” dizinine kopyalayabilirsiniz.

Daha sonra, “pubspec.yaml” dosyanızı açın ve “fonts” sekmesine gidin. Burada, yeni bir öğe eklemek için aşağıdaki kodu kullanabilirsiniz:

Burada, [font-family-name] özel fontun adını, [font-file-name] ise dosyanın adını belirtir.

Bu adımdan sonra, özel fontu kullanmak için MaterialApp veya TextStyle gibi bir widget kullanabilirsiniz. Örneğin, aşağıdaki gibi TextStyle kullanabilirsiniz:

Bu şekilde, özel fontunuzu Flutter uygulamanıza başarıyla ekleyebilirsiniz.

Kategori Featured, Flutter
16.03.2023
84 Okunma

Flutter Stack Kullanımı

Stack widget’i, diğer widget’ların üstüne konumlandırılmasına olanak tanıyan bir widget’dır. Genellikle Overlay, GridView, ListView veya Row/Column gibi widget’ların içinde kullanılır.

İşte basit bir örnek:

Bu örnekte, Stack widget’i, dört farklı Container widget’ını içerir. Her bir Container widget’ı, farklı bir renk ve farklı bir konumda yer alır. Positioned widget’ı, her bir Container widget’ını belirli bir konuma yerleştirir.

Stack widget’ı, diğer widget’ların üstüne konumlandırılabilmesi nedeniyle çok yönlü bir widget’dır. Örneğin, bir resim veya video oynatıcı widget’ı, Stack widget’ı içinde konumlandırılabilir ve üstüne farklı widget’lar eklenebilir.

Flutter’da Stack widget’ının birçok farklı kullanımı ve özelliği vardır. Umarım bu örnekler size başlangıçta yardımcı olmuştur.

Bir resim widget’ı ve bir metin widget’ını Stack widget’ı içinde konumlandırma:

Bir video oynatıcı widget’ı ve üstünde bir düğme widget’ı Stack widget’ı içinde konumlandırma:

Bir resim widget’ı, bir ikon ve bir metin widget’ını Stack widget’ı içinde konumlandırma:

Bu örnekler, Stack widget’ının nasıl kullanılabileceği konusunda farklı fikirler vermektedir. İhtiyaçlarınıza göre Stack widget’ını kullanarak, farklı widget’ların üst üste konumlandırılmasıyla, çok çeşitli tasarımlar yapabilirsiniz.

Kategori Featured, Flutter
16.03.2023
82 Okunma

Flutter FloatingActionButton Kullanımı

Öncelikle FloatingActionButton’ın kullanımı için, önceden oluşturulmuş bir Scaffold bileşeni içinde yer alması gerektiğini unutmayın.

İşte basit bir örnek:

Bu örnekte, Scaffold bileşeni içinde, floatingActionButton özelliği kullanılarak bir FloatingActionButton oluşturulmuştur. onPressed özelliği, FloatingActionButton tıklandığında çalışacak kodu içerir. child özelliği, FloatingActionButton içinde görünecek ikonu belirler.

FloatingActionButton’ı farklı şekillerde özelleştirebilirsiniz. Örneğin, FloatingActionButton’ın arkasındaki materyal rengini değiştirmek için backgroundColor özelliğini kullanabilirsiniz:

Ayrıca, shape özelliğini kullanarak FloatingActionButton’ın şeklini de değiştirebilirsiniz:

Bu örnekte, shape özelliği, FloatingActionButton’ın şeklini yuvarlatılmış köşeli bir dikdörtgen olarak belirler. borderRadius özelliği, köşelerin yuvarlaklığını ayarlar.

Flutter’da FloatingActionButton’un birçok farklı özelliği ve kullanımı vardır. Umarım bu örnekler size başlangıçta yardımcı olmuştur.

Kategori Featured, Flutter
16.03.2023
80 Okunma

Flutter FutureBuilder Kullanımı #137

Flutter’da verilerin asenkron olarak getirilmesi için kullanılan birçok yöntem vardır. Bunlardan biri de FutureBuilder widget’ıdır. FutureBuilder, asenkron bir işlemdeki verileri anlık olarak görüntülemek için kullanılır.

FutureBuilder, gelecekte tamamlanması beklenen bir işlemi başlatır ve işlem tamamlandığında sonucu ekrana yansıtır. FutureBuilder widget’ı, bir Future nesnesi alır ve Future nesnesi tamamlandığında çağrılan bir builder fonksiyonunu içerir. Builder fonksiyonu, Future nesnesi tamamlandığında yeniden çağrılır ve builder fonksiyonu tarafından döndürülen Widget ağacı görüntülenir.

Şimdi, FutureBuilder widget’ını üç örnekle inceleyelim:

Örnek 1: Bir JSON veri kaynağından veri çekme

Bu örnekte, FutureBuilder widget’ını kullanarak bir JSON veri kaynağından veri çekeceğiz ve ListView widget’ı ile birlikte verileri listeleyeceğiz.

Öncelikle, http paketini projemize ekleyelim:

Şimdi, main.dart dosyasına aşağıdaki kodları ekleyelim:

Örnek 2: Veri kaynağından veri almak ve FutureBuilder kullanarak göstermek

Bu örnekte, bir veri kaynağından (API, veritabanı vb.) veri alacağız ve FutureBuilder widget’ını kullanarak alınan veriyi göstereceğiz. Bu örnekte, jsonplaceholder API’sini kullanacağız.

İlk olarak, HTTP isteği yapmak için http paketini ekleyelim. pubspec.yaml dosyasına aşağıdaki satırı ekleyin:

Daha sonra, main.dart dosyasına aşağıdaki kodu ekleyin:

Bu örnekte, fetchPosts adlı bir fonksiyon oluşturduk. Bu fonksiyon, API’dan veri alır ve JSON formatında döndürür. Daha sonra, HomePage sınıfımızda, FutureBuilder kullanarak bu fonksiyondan verileri gösteriyoruz.

FutureBuilder widget’ı, asenkron olarak veri alınması gereken durumlarda kullanılır. Widget’ın future parametresine, verilerin alınacağı Future nesnesi atanır. builder parametresi, Future nesnesinin durumuna göre farklı widget’lar döndürür. Bu örnekte, AsyncSnapshot sınıfı, hasData özelliği ile alınan verilerin var olup olmadığını kontrol eder. Veriler varsa, ListView.builder kullanarak verileri liste şeklinde gösteririz. Veriler yoksa, CircularProgressIndicator kullanarak yükleniyor işlemini gösteririz.

Örnek 3: Firebase Verilerini FutureBuilder ile Getirme

Firebase, popüler bir Backend-as-a-Service (BaaS) hizmetidir ve Flutter uygulamalarında kullanılabilecek birçok araç sunar. Firebase Firestore, gerçek zamanlı veritabanı hizmeti sunar ve bu örnekte Firestore kullanarak FutureBuilder ile veri getireceğiz.

Öncelikle, pubspec.yaml dosyanızda Firebase ve Firestore bağımlılıklarını ekleyin:

Firebase Firestore’a erişmek için, projenizde bir Firebase projesi oluşturmanız ve projenizin Firebase SDK’sını yapılandırmanız gerekir. Daha fazla bilgi için Firebase Dokümantasyonuna bakabilirsiniz.

Firestore’dan veri almak için önce bir FirebaseFirestore örneği oluşturmalıyız:

Daha sonra, bir Future döndüren bir fonksiyon yazacağız. Bu fonksiyon, Firestore’dan verileri getirecek ve bunları bir List olarak döndürecek.

Bu fonksiyon, ‘myCollection’ adlı bir Firestore koleksiyonundan ‘myField’ adlı bir alanın değerlerini getiriyor. Sonra bu değerleri bir Liste ekleyip return ediyor.

Son olarak, bu Future‘ı bir FutureBuilder içinde kullanabiliriz:

FutureBuilder widget’ı, _getFirestoreData() fonksiyonunu çağırarak bir Future döndürür. Bu Future henüz tamamlanmamışsa, CircularProgressIndicator gösterilir. Future tamamlandığında, ListView‘de veriler görüntülenir. Future bir hata verirse, bir hata mesajı gösterilir.

Sonuç

Bu makalede, FutureBuilder widget’ının ne olduğunu ve nasıl kullanılabileceğini öğrendik. FutureBuilder, bir Future döndüren işlemleri asenkron olarak yönetmek için kullanılır.

Kategori Featured, Flutter
16.03.2023
85 Okunma

Flutter Opacity Kullanımı #138

Flutter’da Opacity widgeti, bir widgetin saydamlığını ayarlamaya olanak tanıyan bir widgetdir. Bu widget, içinde bulunduğu widgetin opaklığını değiştirmek için kullanılır. Bu makalede, Flutter’daki Opacity widgeti hakkında ayrıntılı bilgi edinecek ve örneklerle nasıl kullanıldığını öğreneceksiniz.

Opacity Widget’inin Kullanımı

Flutter’da Opacity widgeti, kullanımı oldukça basit bir widgetdir. Yalnızca bir child widgeti ve bir opacity değeri gerektirir. Opacity değeri, widgetin saydamlığını belirler ve 0,0 ile 1,0 arasında bir değer alır. Değer arttıkça, widgetin opaklığı artar. Değer azaldıkça, widgetin opaklığı azalır.

Yukarıdaki örnekte, bir Container widgeti içeren bir Opacity widgeti kullanılmıştır. Opacity değeri 0.5 olarak ayarlandığı için, Container widgeti yarı saydamdır.

Opacity Widget’inin Özellikleri

Opacity widgeti, child widgetine etki eden birkaç özellik sunar. Bu özellikler şunlardır:

opacity

Bu özellik, widgetin saydamlığını belirler. Değer 0,0 ile 1,0 arasında olmalıdır.

alwaysIncludeSemantics

Bu özellik, Opacity widgetinin, child widgetinin semantiğinin daima görünür olmasını sağlar. Varsayılan değeri false’dur.

child

Bu özellik, Opacity widgetinin içinde bulunan child widgetini belirler.

Opacity Widget’inin Örnekleri

Şimdi, Opacity widgetini kullanarak birkaç örnek görelim.

Örnek 1: Butonun Opaklığını Değiştirme

Bu örnekte, bir butonun opaklığını değiştirmek için Opacity widgeti kullanılır. Butona tıkladığınızda, opaklık değeri değişir.

Örnek 2: Animasyonlu Opacity

Bu örnekte, Opacity widget’ını kullanarak bir resmin opaklığını bir animasyon yardımıyla değiştireceğiz.

Bu örnekte, _visible adlı bir boolean değişken tanımlıyoruz ve varsayılan olarak true değerini atıyoruz. AnimatedOpacity widget’ı içindeki opacity özelliği, _visible değişkeninin değerine göre ayarlanıyor. duration özelliği, animasyonun süresini belirliyor.

Ayrıca, uygulamamızda bir düğme kullanarak _visible değişkeninin değerini tersine çeviriyoruz. Bu düğme, setState yöntemi kullanılarak MyHomePage sınıfının durumunu güncelliyor ve böylece resmin opaklığı da güncelleniyor.

Umarım bu örnekler, Opacity widget’ının ne işe yaradığını ve nasıl kullanıldığını anlamana yardımcı olmuştur.

Kategori Featured, Flutter
16.03.2023
91 Okunma