e
sv

Flutter ile bir haber uygulaması oluşturma

avatar

Yazılım Method

  • e 0

    Mutlu

  • e 0

    Eğlenmiş

  • e 0

    Şaşırmış

  • e 0

    Kızgın

  • e 0

    Üzgün

Kahvaltı masanızda oturup çayınızı veya kahvenizi yudumlarken sabah gazetesini okumayı sevenlerden misiniz? Pekala, ben güncel kalmak için sabahları ilk iş olarak haberleri okumayı seven insanlardan biriyim.

Neden kendimiz için derlenen en son haberlerle güncel kalmak için bir uygulama geliştirmiyorsunuz? Kendi haber uygulamamızı oluşturmak için Flutter bilgimizi uygulayalım. Uygulamayı oluşturmak ve Flutter becerilerimizi geliştirmek için atacağımız adımlar şunlardır:

Nihai ürünümüzün nasıl görüneceğini görmek için okumaya devam edin.

Demo uygulamasına giriş

Ekranın üst kısmında arama çubuğu bulunan tek ekranlı bir uygulama geliştiriyoruz; dünyanın dört bir yanından en iyi manşetleri görüntülemek için bir Döngü widget’ı; ve kullanıcı yan çekmeceden seçim yaptığında Ülke , Kategori veya Kanal bazında haberlerin listesi.

Uygulamayı çalıştırdığınızda, en çok okunan başlıklar için varsayılan Ülke Hindistan olarak, varsayılan Kategori ise İşletme olarak ayarlanır.

Bitmiş Haber Uygulaması

NewsAPI.org’dan API anahtarını kullanacağız. Geliştirici modunda sınırlı sayıda haber makalesini sorgulayabildiğimizden, API’yi MediaStack ve NewsData’dan da kullanabilirsiniz. News API, günde yaklaşık 100 sorguya izin verir. Tersine, MediaStack ayda 500 sorguya izin verir ve NewsData günde 200 sorguya izin verir. Başvurunuzu test etmek için her zaman farklı hesaplarla kaydolabilirsiniz. Benzersiz API anahtarı dışında her şey aynı kalacaktır.

Bunu akılda tutarak, inşa etmeye başlayalım.

Bağımlılıkları ayarlama

pubspec.yaml dosyanıza lütfen aşağıdaki bağımlılıkları ekleyin:

  • http: ^0.13.4 — HTTP istekleri yapmak için şekillendirilebilir, Geleceğe dayalı bir kitaplık. Bu paketi kullanarak NewsApi.org’dan haber makalelerini sorgulayacağız.
  • webview_flutter: ^3.0.4 — Android ve iOS’ta bir WebView widget’ı sağlayan bir Flutter eklentisi. Bu paket ile bir kullanıcı haber makalesinin tamamını okuyabilir
  • carousel_slider: ^4.1.1 — sonsuz kaydırmayı ve özel bir alt pencere öğesini destekleyen bir atlıkarınca kaydırıcı pencere öğesi. Bu paketi, otomatik olarak yatay olarak kaydırılacak en son başlıkları göstermek için kullanıyoruz.
  • get: ^4.6,5 — durum yönetimi çözümümüz. Flutter için durum yönetimi çözümü olarak GetX kullanmanın avantajlarından bahsetmiştim; özellikle bir geliştirici prototip oluştururken uygulanması hızlı ve kolaydır

Android ve iOS için WebView’ı Yapılandırma

Haberin tamamını görüntülemek için WebView paketini kullandığımızdan, Runner klasörü içindeki Android app/ build.gradle dosyasında ve iOS info.plist dosyasında birkaç değişiklik yapmamız gerekiyor.

Android için

minSdkVersion en az 19 olarak değiştirmelisiniz. Ayrıca, Android bağımlılıklarına multiDex desteği ekleyin. Referans için lütfen aşağıdaki resme bakın:

MinSDK sürümü

iOS için

Runner klasörünün içine, iOS aygıtlarında çalışırken Flutter için gömülü görünümleri desteklemek için bu satırı eklemeniz gerekir:

 <key>io.flutter.embedded_views_preview</key>
   <string>EVET</string>

Referans için lütfen aşağıdaki resme bakın:

Gömülü Görünümler

Bağımlılıklarımız haber uygulaması için ayarlandı. Şimdi NewsApi.org’a üye olalım ve benzersiz API anahtarımızı alalım.

News API anahtarını edinme

NewsAPI.org’a gidin ve e-posta kimliğiniz ve şifrenizle kaydolun. Kaydolduğunuz anda, haber makaleleri istemek için kullanacağımız benzersiz bir API anahtarı oluşturacaktır. Bu anahtarı Flutter projesinde sabit olarak kaydedin.

uç noktalar

Bu API’yi kullanmak için uç noktanın ne olduğunu anlamamız gerekir. Uç nokta, bir API’nin yazılım veya programların birbirleriyle iletişim kurmasına izin verdiği ayrı bir noktadır.

Uç noktaların ve API’lerin aynı şeyler olmadığını unutmamak önemlidir. Bir uç nokta, bir API’nin bir bileşenidir, API ise iki yazılım parçasının birbirleriyle iletişim kurmak için bir kaynağı paylaşmasına izin veren bir kurallar dizisidir. Uç noktalar, bu kaynakların konumlarıdır ve bir API, istenen yanıtları almak için URL’leri kullanır.

News API’nin ana uç noktaları

  1. https://newsapi.org/v2/her şey ? (bu, 80.000’den fazla farklı kaynak tarafından yayınlanan her makaleyi arar)
  2. https://newsapi.org/v2/top-headlines ? (bu, ülke ve kategoriye göre son dakika haberlerini döndürür)
  3. Ayrıca belirli yayıncılardan (örneğin: BBC, ABC) haberleri döndüren küçük bir uç nokta da vardır. https://newsapi.org/v2/top-headlines/sources ?

Yukarıdaki uç noktalarla, kimlik doğrulamanın işlendiği API anahtarını sağlamamız gerekir. API anahtarı URL’nin sonuna eklenmezse, 401 - Unauthorized HTTP error almamız gerekir.

Böylece URL şöyle görünecek:

Yukarıdaki URL, şunun gibi görünecek bir JSON yanıtı döndürecektir:

Yukarıdakileri anladıktan sonra, şimdi model sınıflarından ve ardından GetX Controller sınıfımızdan başlayarak uygulamamızı programlamaya başlayacağız.

Model sınıflarının yazılması

3 model sınıfımız var.

  1. ArticleModel
     sınıf MakaleModel {
     ArticleModel(this.source, this.writer, this.title, this.description, this.url,
         this.urlToImage, this.publishedAt, this.content);
    
     Sicim? yazar, açıklama, urlToImage, içerik;
     Dize başlığı, url, yayınlananAt;
     KaynakModel kaynağı;
    
     Harita<Dize, dinamik> toJson() {
       dönüş {
         'yazar': yazar,
         'açıklama': açıklama,
         'urlToImage': urlToImage,
         'içerik': içerik,
         'başlık': başlık,
         'url': url,
         'yayınlananAt': yayınlananAt,
         'kaynak': kaynak,
       };
     }
    
     fabrika ArticleModel.fromJson(Map<String, dynamic> json) => ArticleModel(
           SourceModel.fromJson(json['source'] as Map<String, dynamic>),
           json['yazar'],
           json['başlık'],
           json['açıklama'],
           json['url'],
           json['urlToImage'],
           json['PublishedAt'],
           json['içerik'],
         );
    }
  2. NewsModel
     sınıf Haber Modeli {
     NewsModel(this.status, this.totalResults, this.makaleler);
    
     Dize durumu;
     int toplamSonuçlar;
     <ArticleModel> makalelerini listele;
    
     Harita<Dize, dinamik> toJson() {
       dönüş {
         'durum': durum,
         'totalResults': totalResults,
         'makaleler': makaleler,
       };
     }
    
     fabrika NewsModel.fromJson(Harita<Dize, dinamik> json) => NewsModel(
           json['durum'],
           json['toplamSonuçlar'],
           (json['makaleler'] olarak Liste<dinamik>)
               .map((e) => ArticleModel.fromJson(e as Map<String, dynamic>))
               .Listeye(),
         );
    }
  3. SourceModel
     class SourceModel {
     SourceModel({this.id = '', gerekli this.name});
    
     Sicim? kimlik, isim;
    
     Harita<Dize, dinamik> toJson() {
       dönüş {
         'yaptım,
         'isim': isim,
       };
     }
    
     fabrika SourceModel.fromJson(Harita<Dize, dinamik> json) {
       SourceModel'i döndür(
         kimlik: json['id'],
         isim: json['isim'],
       );
     }
    }

Yukarıdaki örnek JSON yanıtına bakarsanız, model sınıfları buna dayanmaktadır. Model sınıflarındaki değişken adları, JSON yanıtındaki alanlarla eşleşmelidir.

GetX Controller sınıfıyla veri alma

Burada, üç tür haber makalesi almak için tüm değişkenlerimizi, yöntemlerimizi ve işlevlerimizi tanımlayacağız:

  1. En iyi manşetler
  2. Ülkeye, kategoriye ve kanala göre haberler
  3. Aranan haberler

Değişkenleri tanımlayıp başlatarak başlayın:

Sonraki adım, News API’den tüm haber makaleleri için bir JSON nesnesi almaya yönelik bir API işlevidir. HTTP yanıt yöntemini kullanarak, URL’den veri alıyoruz ve JSON nesnesinin kodunu okunabilir bir biçimde çözüyoruz. Ardından yanıt durumunu kontrol ediyoruz.

Yanıt kodu 200 ise, durumun iyi olduğu anlamına gelir. Yanıtta bazı veriler varsa, sonunda kullanıcı arayüzünde gösterilecek olan listeye yüklenecektir. Bu, tüm haberleri alma işlevidir:

 // newsApi.org'dan tüm haberler için bir JSON yanıtı alma işlevi
getAllNewsFromApi(url) zaman uyumsuz {
 //Bir URI dizesini ayrıştırarak yeni bir Uri nesnesi oluşturur.
 http.Response res = bekle http.get(Uri.parse(url));

 if (res.statusCode == 200) {
   //Dizeyi ayrıştırır ve elde edilen Json nesnesini döndürür.
   NewsModel newsData = NewsModel.fromJson(jsonDecode(res.body));

   if (newsData.articles.isEmpty && newsData.totalResults == 0) {
     makaleNotFound.value = isLoading.value == doğru mu? yanlış doğru;
     isLoading.value = yanlış;
     Güncelleme();
   } başka {
     if (isLoading.value == true) {
       // iki liste örneğini spread operatörüyle birleştirmek
       allNews = [...allNews, ...newsData.makaleler];
       Güncelleme();
     } başka {
       if (newsData.articles.isNotEmpty) {
         allNews = newsData.articles;
         // liste ekranın başına geri döner
         if (scrollController.hasClients) scrollController.jumpTo(0.0);
         Güncelleme();
       }
     }
     makaleNotFound.value = yanlış;
     isLoading.value = yanlış;
     Güncelleme();
   }
 } başka {
   makaleNotFound.value = doğru;
   Güncelleme();
 }
}

Ve işte son dakika haberlerini almak için bir fonksiyon:

 // newsApi.org'dan son dakika haberleri için bir JSON yanıtı alma işlevi
getBreakingNewsFromApi(url) zaman uyumsuz {
 http.Response res = bekle http.get(Uri.parse(url));

 if (res.statusCode == 200) {
   NewsModel newsData = NewsModel.fromJson(jsonDecode(res.body));

   if (newsData.articles.isEmpty && newsData.totalResults == 0) {
     makaleNotFound.value = isLoading.value == doğru mu? yanlış doğru;
     isLoading.value = yanlış;
     Güncelleme();
   } başka {
     if (isLoading.value == true) {
       // iki liste örneğini spread operatörüyle birleştirmek
       BreakingNews = [...breakingNews, ...newsData.makaleler];
       Güncelleme();
     } başka {
       if (newsData.articles.isNotEmpty) {
         breakNews = newsData.articles;
         if (scrollController.hasClients) scrollController.jumpTo(0.0);
         Güncelleme();
       }
     }
     makaleNotFound.value = yanlış;
     isLoading.value = yanlış;
     Güncelleme();
   }
 } başka {
   makaleNotFound.value = doğru;
   Güncelleme();
 }
}

Ardından, daha önce tartıştığımız uç noktalarla iletişim kurmak ve API’den özelleştirilmiş yanıtlar almak için işlevler ekliyoruz. Aşağıdaki fonksiyonlarda onu çağırdığımızda yapacağımız yukarıdaki fonksiyonlara bir URL string geçirmemiz gerekiyor.

Bir arama anahtar kelimesine göre tüm haber ve haberleri almak için:

 // tüm haberleri ve aranan haberleri kullanıcı arayüzüne yükleme ve görüntüleme işlevi
getAllNews({channel = '', searchKey = '', yeniden yükle = yanlış}) zaman uyumsuz {
 makaleNotFound.value = yanlış;

 if (!reload && isLoading.value == false) {
 } başka {
   ülke.değer = '';
   kategori.değer = '';
 }
 if (isLoading.value == true) {
   sayfaNum++;
 } başka {
   allNews = [];

   pageNum.value = 2;
 }
 // SON NOKTA
 baseUrl = "https://newsapi.org/v2/top-headlines?pageSize=10&page=$pageNum&";
 // varsayılan ülke Hindistan olarak ayarlandı
 baseUrl += country.isEmpty ? 'ülke=in&' : 'ülke=$ülke&';
 // varsayılan kategori İş olarak ayarlandı
 baseUrl += kategori.isBoş ? 'kategori=işletme&' : 'kategori=$kategori&';
 baseUrl += 'apiKey=${NewsApiConstants.newsApiKey}';
 // kullanıcı bir kanal seçtiğinde ülke ve kategori null olur 
 if (kanal != '') {
   ülke.değer = '';
   kategori.değer = '';
   baseUrl =
       "https://newsapi.org/v2/top-headlines?sources=$channel&apiKey=${NewsApiConstants.newsApiKey}";
 }
 // a herhangi bir anahtar kelime girdiğinde ülke ve kategori null olur
 if (aramaAnahtarı != '') {
   ülke.değer = '';
   kategori.değer = '';
   baseUrl =
       "https://newsapi.org/v2/everything?q=$searchKey&from=2022-07-01&sortBy=popularity&pageSize=10&apiKey=${NewsApiConstants.newsApiKey}";
 }
 print(baseUrl);
 // API işlevini çağırıp URL'yi buraya iletiyoruz
 getAllNewsFromApi(baseUrl);
}

Kullanıcının seçtiği ülkeye göre son dakika haberlerini almak için:

 // son dakika haberlerini kullanıcı arayüzüne yükleme ve görüntüleme işlevi
getBreakingNews({yeniden yükle = yanlış}) zaman uyumsuz {
 makaleNotFound.value = yanlış;

 if (!reload && isLoading.value == false) {
 } başka {
   ülke.değer = '';
 }
 if (isLoading.value == true) {
   sayfaNum++;
 } başka {
   BreakNews = [];

   pageNum.value = 2;
 }
 // varsayılan dil İngilizce olarak ayarlandı
 /// SON NOKTA
 baseUrl =
     "https://newsapi.org/v2/top-headlines?pageSize=10&page=$pageNum&languages=tr&";
 // varsayılan ülke ABD olarak ayarlandı
 baseUrl += country.isEmpty ? 'ülke=biz&' : 'ülke=$ülke&';
 //baseApi += kategori.isBoş ? '' : 'kategori=$kategori&';
 baseUrl += 'apiKey=${NewsApiConstants.newsApiKey}';
 print([baseUrl]);
 // API işlevini çağırıp URL'yi buraya iletiyoruz
 getBreakingNewsFromApi(baseUrl);
}

Son olarak, onInit yöntemini geçersiz kılın ve yukarıdaki iki işlevi çağırın:

 @geçersiz kıl
geçersiz onInit() {
 scrollController = ScrollController()..addListener(_scrollListener);
 getAllNews();
 getBreakingNews();
 super.onInit();
}

Özel bir NewsCard widget’ı oluşturma

Ardından, API’den alacağımız haber makalesinin resmini, başlığını, açıklamasını ve URL’sini görüntülemek için kullanılacak özel bir widget oluşturuyoruz. Bu widget, ana ekranda ListView oluşturucusunda çağrılır:

 class NewsCard, StatelessWidget'ı genişletir {
final String imgUrl, başlık, açıklama, içerik, postUrl;

 const Haber Kartı(
     {Anahtar? anahtar,
     this.imgUrl gerekli,
     gerekli this.desc,
     gerekli this.title,
     gerekli this.content,
     gerekli this.postUrl});

 @geçersiz kıl
 Widget derlemesi(BuildContext bağlamı) {
   iade Kartı(
     yükseklik: Sizes.dimen_4,
     şekil: const RoundedRectangleBorder(
         borderRadius: BorderRadius.all(Radius.circular(Sizes.dimen_10))),
     kenar boşluğu: const EdgeInsets.fromLTRB(
         Sizes.dimen_16, 0, Sizes.dimen_16, Sizes.dimen_16),
     çocuk: Sütun(
       crossAxisAlignment: CrossAxisAlignment.start,
       mainAxisSize: MainAxisSize.min,
       çocuklar: <Widget>[
         KlipDoğru(
             borderRadius: const BorderRadius.only(
                 üstSol: Yarıçap.dairesel(Sizes.dimen_10),
                 üstSağ: Radius.circular(Sizes.dimen_10)),
             çocuk: Image.network(
               imgUrl,
               yükseklik: 200,
               genişlik: MediaQuery.of(bağlam).size.width,
               uygun: BoxFit.fill,
              // resim boş ise
               errorBuilder: (BuildContext bağlamı, Nesne istisnası,
                   Yığın izleme? yığın izleme) {
                 iade Kartı(
                   yükseklik: 0,
                   şekil: YuvarlakDikdörtgenBorder(
                       borderRadius: BorderRadius.circular(Sizes.dimen_10)),
                   çocuk: const SizedBox(
                     yükseklik: 200,
                     genişlik: çift.sonsuz,
                     alt: Simge(Icons.broken_image_outlined),
                   ),
                 );
               },
             )),
         dikey15,
         Dolgu malzemesi(
           dolgu: const EdgeInsets.all(Sizes.dimen_6),
           çocuk: Metin(
             Başlık,
             maxLines: 2,
             stil: const TextStyle(
                 renk: Colors.black87,
                 fontSize: Sizes.dimen_20,
                 fontWeight: FontWeight.w500),
           ),
         ),
         Dolgu malzemesi(
           dolgu: const EdgeInsets.all(Sizes.dimen_6),
           çocuk: Metin(
             açıklama,
             maxLines: 2,
             stil: const TextStyle(renk: Colors.black54, fontSize: Sizes.dimen_14),
           ),
         )
       ],
     ),
   );
 }
}

newsCard görünecek.

Haber kartı

Kodda sabit değerler fark edebilirsiniz. Tüm Flutter projelerimde renk, boyut, metin alanı süslemeleri vb. tanımlamak için sabit dosyalar oluşturma alışkanlığım var. Bu dosyaları buradaki makaleye eklemiyorum, ancak bunları GitHub deposunda bulacaksınız.

Arama çubuğu widget’ı ekleme

Şimdi ana ekranımızı oluşturmaya başlıyoruz. Ekranın üst kısmında arama metin alanımız var. Bir kullanıcı herhangi bir anahtar kelime girdiğinde, API farklı kaynaklardan binlerce makaleyi arayacak ve NewsCard widget’ının yardımıyla bunu ekranda gösterecektir:

 Esnek(
 çocuk: Konteyner(
   dolgu: const EdgeInsets.simetrik(yatay: Sizes.dimen_8),
   kenar boşluğu: const EdgeInsets.simetrik(
       yatay: Sizes.dimen_18, dikey: Sizes.dimen_16),
   dekorasyon: KutuDekorasyon(
       renk: Renkler.beyaz,
       borderRadius: BorderRadius.circular(Sizes.dimen_8)),
   çocuk: Satır(
     mainAxisSize: MainAxisSize.max,
     mainAxisAlignment: MainAxisAlignment.spaceBetween,
     çocuklar: [
       Esnek(
         uygun: FlexFit.tight,
         esnek: 4,
         çocuk: Dolgu(
           dolgu: const EdgeInsets.only(sol: Sizes.dimen_16),
           çocuk: TextField(
             denetleyici: searchController,
             textInputAction: TextInputAction.search,
             dekorasyon: const InputDecoration(
                 sınır: InputBorder.none,
                 hintText: "Haber Arama"),
             onChanged: (val) {
               newsController.searchNews.value = val;
               newsController.update();
             },
             onSubmitted: (değer) zaman uyumsuz {
               newsController.searchNews.value = değer;
               newsController.getAllNews(
                   searchKey: newsController.searchNews.value);
               searchController.clear();
             },
           ),
         ),
       ),
       Esnek(
         esnek: 1,
         uygun: FlexFit.tight,
         çocuk: IconButton(
             dolgu: EdgeInsets.zero,
             renk: AppColors.bordo,
             onPressed: () zaman uyumsuz {
               newsController.getAllNews(
                   searchKey: newsController.searchNews.value);
               searchController.clear();
             },
             simge: const Simge(Icons.search_sharp)),
       ),
     ],
   ),
 ),
),

Arama çubuğumuz bu şekilde görünecektir.

Arama Çubuğu Haberleri

Dönen pencere aracı, bir kullanıcı yan çekmeceden bir ülke seçtiğinde, farklı ülkelerden en iyi manşetleri veya son dakika haberlerini görüntüler. Bu widget, her yeni ülke seçildiğinde ve son dakika haberlerinin güncellenmesi gerektiğinde yeniden oluşturulabilmesi için GetBuilder ile paketlenmiştir.

Kaydırıcıyı otomatik oynatmak için atlıkarınca seçeneğini ayarladım. Kullanıcının kaydırmasına gerek kalmadan otomatik olarak yatay olarak kayar. Yığın pencere öğesi, haberin görüntüsünü ve bunun üzerinde haberin başlığını görüntüler.

Ayrıca sağ üst köşeye, hata ayıklama başlığına benzer bir şey olan Top Headlines yazan bir başlık ekledim. Yığın widget’ı yeniden InkWell ile sarılır ve içinde bir onTap işlevi bulunur. Bir kullanıcı herhangi bir habere tıkladığında, kullanıcıyı tüm haber makalesinin okuyucuya görüntüleneceği WebView ekranına götürecektir:

 GetBuilder<NewsController>(
   başlangıç: NewsController(),
   oluşturucu: (kontrolör) {
     CarouselSlider'ı döndür(
       seçenekler: CarouselOptions(
           yükseklik: 200, otomatik Oynat: doğru, büyütCenterPage: doğru),
       öğeler: controller.breakingNews.map((örnek) {
         controller.articleNotFound.value değerini döndür
             ? sabit Merkez(
                 çocuk: Metin ("Bulunamadı",
                     stil: TextStyle(fontSize: 30)))
             : controller.breakingNews.isBoş
                 ? const Center(alt: CircularProgressIndicator())
                 : Oluşturucu(oluşturucu: (BuildContext bağlamı) {
                     denemek {
                       dönüş afişi(
                         konum: BannerLocation.topStart,
                         mesaj: 'En İyi Başlıklar',
                         çocuk: InkWell(
                           onTap: () => Get.to(() =>
                               WebViewNews(newsUrl: instance.url)),
                           çocuk: Yığın(çocuklar: [
                             KlipDoğru(
                               sınır Yarıçapı:
                                   BorderRadius.circular(10),
                               çocuk: Image.network(
                                 örnek.urlToImage ?? " ",
                                 uygun: BoxFit.fill,
                                 yükseklik: çift.sonsuz,
                                 genişlik: çift.sonsuz,
                                // resim boş ise
                                 hata Oluşturucu:
                                     (BuildContext bağlamı,
                                         Nesne istisnası,
                                         Yığın izleme? yığın izleme) {
                                   iade Kartı(
                                     şekil: YuvarlakDikdörtgenBorder(
                                         sınır Yarıçapı:
                                             BorderRadius.circular(
                                                 10)),
                                     çocuk: const SizedBox(
                                       yükseklik: 200,
                                       genişlik: çift.sonsuz,
                                       çocuk: Simge(Simgeler
                                           .broken_image_outlined),
                                     ),
                                   );
                                 },
                               ),
                             ),
                             Konumlandırılmış(
                                 sol: 0,
                                 sağ: 0,
                                 alt: 0,
                                 çocuk: Konteyner(
                                   dekorasyon: KutuDekorasyon(
                                       sınır Yarıçapı:
                                           BorderRadius.circular(
                                               10),
                                       gradyan: LinearGradient(
                                           renkler: [
                                             renkler.siyah12
                                                 .Opacity(0) ile,
                                             renkler.siyah
                                           ],
                                           başlamak:
                                               Alignment.topCenter,
                                           bitiş: Hizalama
                                               .alt merkez)),
                                   çocuk: Konteyner(
                                       dolgu: const EdgeInsets
                                               .simetrik(
                                           yatay: 5,
                                           dikey: 10),
                                       çocuk: Konteyner(
                                           kenar boşluğu: const EdgeInsets
                                                   .simetrik(
                                               yatay: 10),
                                           çocuk: Metin(
                                             örnek.başlık,
                                             stil: const TextStyle(
                                                 fontSize: Boyutlar
                                                     .dimen_16,
                                                 renk:
                                                     renkler.beyaz,
                                                 yazı tipiAğırlığı:
                                                     Yazı Tipi Ağırlığı
                                                         .gözü pek),
                                           ))),
                                 )),
                           ]),
                         ),
                       );
                     } yakalama (e) {
                       if (kDebugMode) {
                         yazdır(e);
                       }
                       geri dön Container();
                     }
                   });
       }).Listeye(),
     );
   }),

Karuselimiz böyle görünecek.

Haber Döngüsü

Yan çekmece widget’ı ekleme

Çekmece widget’ında Ülke , Kategori veya Kanal seçimi için üç açılır menü bulunur. Bütün bunlar esas olarak daha önce tartıştığımız kaynaklara dönüşüyor. Makalelerin alınmasını özelleştirmek için New API tarafından sağlanan küçük bir uç noktadır.

Açılır menülerden yukarıdakilerden herhangi birini seçtiğinizde, kullanıcının seçimi yan çekmecede görüntülenecek ve ülke adı NewsCard liste öğelerinin üzerinde görüntülenecektir. Bu özellik, prototip oluşturma için özel olarak eklenmiştir, böylece geliştiriciler olarak API’nin koda göre bir yanıt döndürdüğünü biliyoruz:

 Çekmece tarafıDrawer(NewsController newsController) {
 dönüş Çekmecesi(
   arkaplanRenk: AppColors.lightGrey,
   çocuk: ListView(
     çocuklar: <Widget>[
       GetBuilder<NewsController>(
         oluşturucu: (kontrolör) {
           dönüş Konteyneri(
             dekorasyon: const KutuDekorasyon(
                 renk: AppColors.bordo,
                 borderRadius: BorderRadius.only(
                   altSol: Radius.circular(Sizes.dimen_10),
                   altSağ: Radius.circular(Sizes.dimen_10),
                 )),
             dolgu: const EdgeInsets.simetrik(
                 yatay: Sizes.dimen_18, dikey: Sizes.dimen_18),
             çocuk: Sütun(
               crossAxisAlignment: CrossAxisAlignment.start,
               çocuklar: [
                 controller.cName.isNotEmpty
                     ? Metin(
                         "Ülke: ${controller.cName.value.capitalizeFirst}",
                         stil: const TextStyle(
                             renk: AppColors.white, fontSize: Sizes.dimen_18),
                       )
                     : const SizedBox.shrink(),
                 dikey15,
                 controller.category.isNotEmpty
                     ? Metin(
                         "Kategori: ${controller.category.value.capitalizeFirst}",
                         stil: const TextStyle(
                             renk: AppColors.white, fontSize: Sizes.dimen_18),
                       )
                     : const SizedBox.shrink(),
                 dikey15,
                 controller.channel.isNotEmpty
                     ? Metin(
                         "Kategori: ${controller.channel.value.capitalizeFirst}",
                         stil: const TextStyle(
                             renk: AppColors.white, fontSize: Sizes.dimen_18),
                       )
                     : const SizedBox.shrink(),
               ],
             ),
           );
         },
         başlangıç: NewsController(),
       ),
    /// Ülke Seçimi İçin
          Genişletme Çini(
         daraltılmışTextColor: AppColors.bordo,
         daraltılmışIconColor: AppColors.burgundy,
         iconColor: AppColors.bordo,
         textColor: AppColors.bordo,
         başlık: const Text("Ülke Seçin"),
         çocuklar: <Widget>[
           for (int i = 0; i < listOfCountry.length; i++)
             çekmeceDropDown(
               onCalled: () {
                 newsController.country.value = listOfCountry[i]['kod']!;
                 newsController.cName.value =
                     listOfCountry[i]['name']!.toUpperCase();
                 newsController.getAllNews();
                 newsController.getBreakingNews();
                
               },
               isim: ülke listesi[i]['isim']!.toUpperCase(),
             ),
         ],
       ),
      /// Kategori Seçimi İçin
       Genişletme Çini(
         daraltılmışTextColor: AppColors.bordo,
         daraltılmışIconColor: AppColors.burgundy,
         iconColor: AppColors.bordo,
         textColor: AppColors.bordo,
         başlık: const Text("Kategori Seç"),
         çocuklar: [
           for (int i = 0; i < listOfCategory.length; i++)
             çekmeceDropDown(
                 onCalled: () {
                   newsController.category.value = listOfCategory[i]['kod']!;
                   newsController.getAllNews();
                  
                 },
                 isim: listOfCategory[i]['name']!.toUpperCase())
         ],
       ),
      /// Kanal Seçimi İçin
       Genişletme Çini(
         daraltılmışTextColor: AppColors.bordo,
         daraltılmışIconColor: AppColors.burgundy,
         iconColor: AppColors.bordo,
         textColor: AppColors.bordo,
         başlık: const Text("Kanal Seç"),
         çocuklar: [
           for (int i = 0; i < listOfNewsChannel.length; i++)
             çekmeceDropDown(
               onCalled: () {
                 newsController.channel.value = listOfNewsChannel[i]['kod']!;
                 newsController.getAllNews(
                     kanal: listOfNewsChannel[i]['kod']);
              
               },
               isim: listOfNewsChannel[i]['name']!.toUpperCase(),
             ),
         ],
       ),
       const Bölücü(),
       ListeTile(
           takip eden: const Simge(
             Icons.done_sharp,
             boyut: Sizes.dimen_28,
             renk: Renkler.siyah,
           ),
           başlık: const Metin(
             "Tamamlandı",
             stil: TextStyle(fontSize: Sizes.dimen_16, color: Colors.black),
           ),
           onTap: () => Get.back()),
     ],
   ),
 );
}

sideDrawer görünecek.

yan çekmece
yan çekmece

Ana ekranımızı tamamlıyoruz

Ardından, diğer tüm haberleri yan çekmeceden kullanıcı seçimine göre görüntüleyen carousel widget’ının altına daha önce oluşturduğumuz NewsCard widget’ını ekliyoruz. Bir kullanıcı, arama metin alanına bir arama anahtar sözcüğü girerse, haber makaleleri burada görüntülenecektir.

Dönen pencere aracının yalnızca seçilen ülkeden en iyi manşetleri ve son dakika haberlerini gösterdiğini lütfen unutmayın; kategori veya kanala göre filtrelenmez. Bir kullanıcı bir kategori veya kanal seçerse, dönen pencere öğesi güncellenmez; yalnızca NewsCard widget’ı güncellenir. Ancak bir kullanıcı yeni bir ülke seçtiğinde, atlıkarınca gereci, NewsCard birlikte güncellenecektir.

Yine, NewsCard pencere bileşeni GetX Builder ve ayrıca InkWell pencere öğesi ile paketlenir:

 GetBuilder<NewsController>(
   başlangıç: NewsController(),
   oluşturucu: (kontrolör) {
     controller.articleNotFound.value değerini döndür
         ? sabit Merkez(
             çocuk: Metin('Hiçbir Şey Bulunamadı'),
           )
         : controller.allNews.isBoş
             ? const Center(alt: CircularProgressIndicator())
             : ListView.builder(
                 denetleyici: controller.scrollController,
                 fizik: const NeverScrollableScrollPhysics(),
                 shrinkWrap: doğru,
                 itemCount: controller.allNews.length,
                 itemBuilder: (bağlam, dizin) {
                   dizin == controller.allNews.length - 1 &&
                           controller.isLoading.isTrue
                       ? sabit Merkez(
                           alt: CircularProgressIndicator(),
                         )
                       : const SizedBox();
                   InkWell'i iade et(
                     onTap: () => Get.to(() => WebViewNews(
                         newsUrl: controller.allNews[index].url)),
                     çocuk: NewsCard(
                         imgUrl: denetleyici
                                 .allNews[index].urlToImage ??
                             '',
                         tanım: denetleyici
                                 .allNews[index].description ??
                             '',
                         başlık: controller.allNews[index].title,
                         içerik:
                             controller.allNews[index].content ??
                                 '',
                         postUrl: controller.allNews[index].url),
                   );
                 });
   }),

SingleChildScrollView , Scaffold gövdesi olarak ana ekran için ana pencere öğesidir. appBar , tüm filtreleri temizleyen ve uygulamayı orijinal durumuna varsayılan olarak ayarlayan bir yenileme düğmesine sahiptir.

Flash Haber Varsayılan Görünümü

WebView ekranını ekleme

WebView ekranı, bir kullanıcı atlıkarıncadan veya NewsCard’dan herhangi bir haber öğesine tıkladığında tüm makaleyi görüntüleyen durum bilgisi olan bir pencere öğesidir.

Burada, bir WebViewController bir Completer sınıfı ile başlatmamız gerekiyor. Bir Completer sınıfı, Future nesneleri üretmenin ve bunları daha sonra bir değer veya hatayla tamamlamanın bir yoludur. Scaffold gövdesi, WebView sınıfının doğrudan geçmesine sahiptir. Okuyucunun makalenin tamamını okumasını engellememesi için bu ekranda appBar yoktur:

 class WebViewNews, StatefulWidget'ı genişletir {
 final String newsUrl;
 WebViewNews({Anahtar? anahtar, gerekli this.newsUrl}) : super(anahtar: anahtar);

 @geçersiz kıl
 Durum<WebViewNews> createState() => _WebViewNewsState();
}

class _WebViewNewsState, State<WebViewNews> { öğesini genişletir
 NewsController newsController = NewsController();

 son Tamamlayıcı<WebViewController> denetleyicisi =
     Tamamlayıcı<WebViewController>();

 @geçersiz kıl
 Widget derlemesi(BuildContext bağlamı) {
   dönüş İskelesi(
       gövde: Web Görünümü(
     initialUrl: widget.newsUrl,
     javascriptMode: JavascriptMode.unrestricted,
     onWebViewCreated: (WebViewController webViewController) {
       setState(() {
         controller.complete(webViewController);
       });
     },
   ));
 }
} 
Haber Merkezi

Açılış ekranı yapmak

Uygulamama Flash adını verdim ⚡ Canva’da haberler ve açılış ekranı resmimi tasarladım. Açılış sayfası üç saniyeliğine açılır ve ardından kullanıcı ana giriş ekranına yönlendirilir. Açılış ekranlarının uygulanması çok kolaydır ve tüm uygulamaların kısa bir giriş için bir tane olmasını tavsiye ederim.

Flash Haber Giriş Ekranı
 class SplashScreen, StatefulWidget'ı genişletir {
 const SplashScreen({Anahtar? anahtar}) : super(anahtar: anahtar);

 @geçersiz kıl
 Durum<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState, State<SplashScreen> { öğesini genişletir
 @geçersiz kıl
 geçersiz initState() {
   super.initState();

   Zamanlayıcı(sabit Süre(saniye: 3)), () {
     // görünümü değiştirerek ana ekrana gidin
     Get.offAndToNamed('/homePage');
   });
 }

 @geçersiz kıl
 Widget derlemesi(BuildContext bağlamı) {
   dönüş İskelesi(
     arkaplanRenk: AppColors.bordo,
     gövde: Merkez(alt: Image.asset('assets/flashNews.jpg')),
   );
 }
}

Hepsi bu! Başvurumuzu tamamladık. Aşağıda GitHub bağlantımda bulacağınız daha önce bahsettiğim gibi birkaç Dart dosyası daha var.

Kullanıcı arayüzünü oldukça düzenli tutmaya çalıştım. Tüm odak noktası, kullanıcıların bulması ve okuması kolay haber makaleleridir. API, bir seferde yüzden fazla makale döndürür; koda yakından bakarsanız, koddan yalnızca birkaç sayfa görüntülüyoruz. Yine, sınırlı sayıda sorguya ve aynı anda birkaç makalenin daha hızlı yüklenmesine izin verilir.

Umarım bu size JSON uç noktaları arasındaki etkileşimi nasıl uygulayacağınız, bir API’den veri alıp bu verileri ekranda nasıl görüntüleyeceğiniz konusunda bir fikir verir.

Teşekkürler!

Github deposuna bağlantı: Flash News .

etiketlerETİKETLER
Üzgünüm, bu içerik için hiç etiket bulunmuyor.

Sıradaki içerik:

Flutter ile bir haber uygulaması oluşturma