Flutter ile Duyarlı Web ve Masaüstü Geliştirme
Yayınlanan: 2022-03-10Bu eğitim, Flutter'ın kendisine bir giriş değildir. Flutter'ın temellerini öğrenmenize yardımcı olacak basit tanıtımlarla çevrimiçi olarak sunulan çok sayıda makale, video ve birkaç kitap var. Bunun yerine, aşağıdaki iki hedefi ele alacağız:
- Flutter'ın mobil olmayan geliştirmesinin mevcut durumu ve Flutter kodunu bir masaüstü veya dizüstü bilgisayarda tarayıcıda nasıl çalıştırabileceğiniz;
- Flutter kullanarak duyarlı uygulamalar nasıl oluşturulur, böylece gücünü - özellikle bir web çerçevesi olarak - tam ekranda görebilirsiniz ve URL'ye dayalı yönlendirme hakkında bir notla biter.
Hadi içeri girelim!
Flutter Nedir, Neden Önemlidir, Neye Evrildi, Nereye Gidiyor?
Flutter, Google'ın en son uygulama geliştirme çerçevesidir. Google, her şeyi kapsayıcı olmasını öngörüyor: Aynı kodun tüm markaların akıllı telefonlarında, tabletlerde ve masaüstü ve dizüstü bilgisayarlarda yerel uygulamalar veya web sayfaları olarak yürütülmesini sağlayacak.
Bu çok iddialı bir proje, ancak Google şimdiye kadar özellikle iki açıdan inanılmaz derecede başarılı oldu: Android ve iOS yerel uygulamaları için gerçekten platformdan bağımsız, harika çalışan ve üretim kullanımına tamamen hazır bir çerçeve oluşturma ve etkileyici bir cephe oluşturma. - Kodun %100'ünü uyumlu bir Flutter uygulamasıyla paylaşabilen son web çerçevesi.
Bir sonraki bölümde, uygulamayı neyin uyumlu kıldığını ve şu an itibariyle mobil olmayan Flutter geliştirmenin durumunu göreceğiz.
Flutter ile Mobil Olmayan Geliştirme
Flutter ile mobil olmayan geliştirme, ilk olarak Google I/O 2019'da önemli bir şekilde duyuruldu. Bu bölüm, nasıl çalıştırılacağı ve ne zaman çalıştığı hakkındadır.
Web ve Masaüstü Geliştirme Nasıl Etkinleştirilir
Web geliştirmeyi etkinleştirmek için öncelikle Flutter'ın beta kanalında olmanız gerekir. Bu noktaya ulaşmanın iki yolu vardır:
- SDK arşivinden uygun en son beta sürümünü indirerek Flutter'ı doğrudan beta kanalına kurun.
- Flutter'ı zaten yüklediyseniz,
$ flutter channel beta
ile beta kanalına geçin ve ardından Flutter sürümünüzü (aslında Flutter kurulum klasöründe birgit pull
olan)$ flutter upgrade
ile güncelleyerek geçişin kendisini gerçekleştirin.
Bundan sonra şunu çalıştırabilirsiniz:
$ flutter config --enable-web
Masaüstü desteği, özellikle Linux ve Windows için araç eksikliği nedeniyle, eklenti geliştirmeyi özellikle büyük bir sorun haline getirdiğinden ve bunun için kullanılan API'lerin kavram kanıtı kullanımına yönelik olması nedeniyle çok daha deneyseldir. üretim. Bu, Windows ve Linux yerel masaüstü uygulamaları için bile desteklenmeyen sürüm derlemeleri için denenmiş ve test edilmiş dart2js derleyicisini kullanan web geliştirmeden farklıdır.
Not : macOS desteği, Windows ve Linux desteğinden biraz daha iyidir, ancak yine de web desteği kadar iyi değil ve neredeyse mobil platformlar için tam destek kadar iyi değil.
Masaüstü geliştirme desteğini etkinleştirmek için, daha önce beta
kanalı için özetlenen adımların aynısını izleyerek master
yayın kanalına geçmeniz gerekir. Ardından, <OS_NAME>
yerine linux
, windows
veya macos
ile değiştirerek aşağıdakileri çalıştırın:
$ flutter config --enable-<OS_NAME>-desktop
Bu noktada, Flutter aracı yapması gerektiğini söylediğim şeyi yapmadığı için açıklayacağım aşağıdaki adımlardan herhangi birinde sorun yaşıyorsanız, bazı yaygın sorun giderme adımları şunlardır:
- Sorunları kontrol etmek için
flutter doctor
çalıştırın. Bu Flutter komutunun bir yan etkisi, ihtiyaç duyduğu ve sahip olmadığı araçları indirmesidir. -
flutter upgrade
çalıştırın. - Kapatıp tekrar açın. Bilgisayarınızı yeniden başlatmanın eski 1. kademe teknik destek yanıtı, Flutter'ın tüm zenginliklerinden yararlanabilmeniz için tam da ihtiyacınız olan şey olabilir.
Flutter Web Uygulamalarını Çalıştırma ve Oluşturma
Flutter web desteği hiç de fena değil ve bu, web için geliştirme kolaylığına yansıyor.
Bunu çalıştırmak…
$ flutter devices
… bunun gibi bir şey için hemen bir giriş göstermelidir:
Web Server • web-server • web-javascript • Flutter Tools
Ek olarak, Chrome tarayıcısını çalıştırmak, Flutter'ın bunun için de bir giriş göstermesine neden olmalıdır. Flutter'ı uyumlu bir Flutter projesinde flutter run
(daha sonra bahsedeceğiz), görünen tek "bağlı cihaz" web sunucusu olduğunda Flutter'ın localhost:<RANDOM_PORT>
üzerinde bir web sunucusu başlatmasına neden olur, bu da Flutter'ınıza erişmenizi sağlar herhangi bir tarayıcıdan web uygulaması.
Chrome'u yüklediyseniz ancak görünmüyorsa, Chrome yürütülebilir dosyasının yoluna CHROME_EXECUTABLE
ortam değişkenini ayarlamanız gerekir.
Flutter Masaüstü Uygulamalarını Çalıştırma ve Oluşturma
Flutter masaüstü desteğini etkinleştirdikten sonra, flutter run -d <OS_NAME>
ile geliştirme iş istasyonunuzda yerel olarak bir Flutter uygulaması çalıştırabilir, <OS_NAME>
OS_NAME> yerine masaüstü desteğini etkinleştirirken kullandığınız değerle değiştirebilirsiniz. Ayrıca flutter build <OS_NAME>
ile build
dizininde ikili dosyalar oluşturabilirsiniz.
Ancak bunlardan herhangi birini yapmadan önce, Flutter'ın platformunuz için oluşturması gerekenleri içeren bir dizine sahip olmanız gerekir. Bu, yeni bir proje oluşturduğunuzda otomatik olarak oluşturulacaktır, ancak onu flutter create .
. Ayrıca, Linux ve Windows API'leri kararsızdır, bu nedenle uygulama bir Flutter güncellemesinden sonra çalışmayı durdurursa bunları bu platformlar için yeniden oluşturmanız gerekebilir.
Bir Uygulama Ne Zaman Uyumludur?
Bir Flutter uygulamasının masaüstünde veya web'de çalışabilmesi için "uyumlu bir proje" olması gerektiğini söylerken başından beri ne demek istedim? Basitçe söylemek gerekirse, oluşturmaya çalıştığınız platform için platforma özel bir uygulaması olmayan herhangi bir eklenti kullanmaması gerektiğini kastediyorum.
Bu noktayı herkes için kesinlikle netleştirmek ve yanlış anlaşılmayı önlemek için, lütfen Flutter eklentisinin , özelliklerini sağlaması için gerekli olan platforma özel kodu içeren belirli bir Flutter paketi olduğunu unutmayın.
Örneğin, Google tarafından geliştirilen url_launcher
paketini istediğiniz kadar kullanabilirsiniz (ve web'in köprüler üzerine kurulu olduğu göz önüne alındığında, isteyebilirsiniz).
Kullanımı web geliştirmeyi engelleyebilecek, Google tarafından geliştirilen bir pakete örnek, dosyaların kaydedileceği yerel depolama yolunu almak için kullanılan path_provider
. Bu, tesadüfen, bir web uygulaması için herhangi bir şekilde kullanılmayan bir paket örneğidir, bu nedenle, kodunuzu değiştirmek için kodunuzu değiştirmeniz gerektiği gerçeği dışında, onu kullanamamak gerçekten bir serseri değildir. kullanıyorsanız, web'de çalışması için.
Örneğin, web'de HTML localStorage
dayanan shared_preferences paketini kullanabilirsiniz.
Benzer uyarılar masaüstü platformları için de geçerlidir: Çok az eklenti masaüstü platformlarıyla uyumludur ve bu yinelenen bir tema olduğundan, bu konuda Web için Flutter'da gerçekten gerekli olandan çok daha fazla çalışmanın masaüstü tarafında yapılması gerekir.
Flutter'da Duyarlı Düzenler Oluşturma
Yukarıda açıkladıklarımdan ve basitlik için, bu yazının geri kalanında hedef platformunuzun web olduğunu varsayacağım, ancak temel kavramlar masaüstü geliştirme için de geçerlidir.
Web'i desteklemenin yararları ve sorumlulukları vardır. Farklı ekran boyutlarını desteklemeye zorlanmış olmak bir dezavantaj gibi görünebilir, ancak uygulamayı web tarayıcılarında çalıştırmanın, uygulamanızın farklı boyut ve en boy oranlarındaki ekranlarda nasıl görüneceğini ayrı ayrı çalıştırmanıza gerek kalmadan çok kolay bir şekilde görmenizi sağladığını düşünün. mobil cihaz emülatörleri.
Şimdi koddan bahsedelim. Uygulamanızı nasıl duyarlı hale getirebilirsiniz?
Bu analizin yapıldığı iki bakış açısı vardır:
- "Farklı boyutlardaki ekranlara uyum sağlayabilen veya uyarlaması gereken hangi widget'ları kullanıyorum veya kullanabilir miyim?"
- “Ekranın boyutu hakkında nasıl bilgi alabilirim ve bunu UI kodu yazarken nasıl kullanabilirim?”
İlk soruyu sonra cevaplayacağız. Önce ikincisinden bahsedelim çünkü çok kolay halledilebilir ve meselenin merkezinde yer alır. Bunu yapmanın iki yolu vardır:
- Bir yol, bir Flutter uygulamasının çalışması için widget ağacında bulunması gereken
MediaQuery
köküInheritedWidget
MediaQueryData
öğesinden bilgi almaktır (bu,MaterialApp/WidgetsApp/CupertinoApp
bir parçasıdır), tıpkı aşağıdaki gibiSize
türünde birsize
özelliğine sahip olan ve bu nedenledouble
türünde ikiwidth
veheight
özelliğine sahip olanMediaQuery.of(context)
içeren herhangi birInheritedWidget
. - Diğer yol,
builder
işlevine (context
birlikte) geçen bir oluşturucu pencere aracı olan (tıpkıStreamBuilder
veyaFutureBuilder
gibi) bir LayoutBuilderminWidth
LayoutBuilder
minHeight
maxHeight
maxWidth
birBoxConstraints
nesnesi.
Kısıtlamaları almak için MediaQuery
kullanan bir DartPad örneği, kodu aşağıdaki gibidir:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { @override Widget build(context) => Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( "Width: ${MediaQuery.of(context).size.width}", style: Theme.of(context).textTheme.headline4 ), Text( "Height: ${MediaQuery.of(context).size.height}", style: Theme.of(context).textTheme.headline4 ) ] ) ) ); }
Ve işte aynı şey için LayoutBuilder
kullanan bir tane:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { @override Widget build(context) => Scaffold( body: LayoutBuilder( builder: (context, constraints) => Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( "Width: ${constraints.maxWidth}", style: Theme.of(context).textTheme.headline4 ), Text( "Height: ${constraints.maxHeight}", style: Theme.of(context).textTheme.headline4 ) ] ) ) ) ); }
Şimdi hangi widget'ların kısıtlamalara uyum sağlayabileceğini düşünelim.
Öncelikle, ekranın boyutuna göre birden çok widget'ı yerleştirmenin farklı yollarını düşünelim.
En kolay uyarlanan pencere öğesi GridView
. Aslında, bu çok basit örnekte görebileceğiniz gibi, GridView.extent
yapıcısı kullanılarak oluşturulan bir GridView
duyarlı hale getirilmesi için katılımınıza bile ihtiyacı yoktur:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { final List elements = [ "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit" ]; @override Widget build(context) => Scaffold( body: GridView.extent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, children: elements.map((el) => Card(child: Center(child: Padding(padding: EdgeInsets.all(8.0), child: Text(el))))).toList() ) ); }
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { final List elements = [ "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit" ]; @override Widget build(context) => Scaffold( body: GridView.extent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, children: elements.map((el) => Card(child: Center(child: Padding(padding: EdgeInsets.all(8.0), child: Text(el))))).toList() ) ); }
maxCrossAxisExtent
değiştirerek farklı boyutlardaki içeriği barındırabilirsiniz.
Bu örnek çoğunlukla GridView.extent
GridView
yapıcısının varlığını gösterme amacına hizmet etti, ancak bunu yapmanın çok daha akıllı bir yolu, bu durumda widget'ların ızgarada gösterileceği SliverGridDelegateWithMaxCrossAxisExtent
ile bir GridView.builder
kullanmak olacaktır. bu örnekte görebileceğiniz gibi, başka bir veri yapısından dinamik olarak oluşturulur:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { final List<String> elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => Scaffold( body: GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ) ); }
Farklı ekranlara uyum sağlayan bir GridView örneği, Cards
biraz daha karmaşık ve daha büyük olması dışında, tıpkı önceki örnek kodda olduğu gibi, bir grup Cards
içeren bir GridView
içeren çok basit bir Flutter web uygulaması olan kişisel açılış sayfamdır. .
Telefonlar için tasarlanmış uygulamalarda yapılabilecek çok basit bir değişiklik, yer olduğunda Çekmeceyi soldaki kalıcı bir Drawer
değiştirmek olacaktır.
Örneğin, gezinme için kullanılan aşağıdaki gibi bir widget'ların ListView
sahip olabiliriz:
class Menu extends StatelessWidget { @override Widget build(context) => ListView( children: [ FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_one), title: Text("First Link"), ) ), FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_two), title: Text("Second Link"), ) ) ] ); }
Bir akıllı telefonda, Drawer
içinde (hamburger menüsü olarak da bilinir) ortak bir kullanım yeri bulunur.

Bunun alternatifleri, TabBarView ile kombinasyon halinde BottomNavigationBar
veya TabBar
TabBarView
, ancak her ikisinde de çekmecede gerekenden daha fazla değişiklik yapmamız gerekecek, bu yüzden çekmeceye bağlı kalacağız.
Daha önce daha küçük ekranlarda gördüğümüz Menu
içeren Drawer
göstermek için, aşağıdaki kod parçasına benzeyen bir kod yazar, Scaffold
MediaQuery.of(context)
kullanarak genişliği kontrol eder ve yalnızca bir Drawer
nesnesini İskeleye iletirsiniz. uygulamamız için uygun olduğuna inandığımız bir genişlik değerinden daha az:
Scaffold( appBar: AppBar(/* ... \*/), drawer: MediaQuery.of(context).size.width < 500 ? Drawer( child: Menu(), ) : null, body: /* ... \*/ )
Şimdi Scaffold
body
düşünelim. Uygulamamızın örnek ana içeriği olarak, daha önce oluşturduğumuz ve karışıklığı önlemek için Content
adlı ayrı bir pencere öğesinde tuttuğumuz GridView
kullanacağız:
class Content extends StatelessWidget { final List elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
class Content extends StatelessWidget { final List elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
Daha büyük ekranlarda, gövdenin kendisi iki widget gösteren bir Row
olabilir: sabit bir genişlikle sınırlandırılmış Menu
ve ekranın geri kalanını dolduran Content
.
Daha küçük ekranlarda, tüm body
Content
olacaktır.
Her şeyi bir SafeArea
ve bir Center
pencere aracına saracağız, çünkü bazen Flutter web uygulaması pencere öğeleri, özellikle Row
s ve Column
s kullanılırken, görünür ekran alanının dışında kalır ve bu, SafeArea
ve/veya Center
ile düzeltilir.
Bu, Scaffold
body
aşağıdaki gibi olacağı anlamına gelir:
SafeArea( child:Center( child: MediaQuery.of(context).size.width < 500 ? Content() : Row( children: [ Container( width: 200.0, child: Menu() ), Container( width: MediaQuery.of(context).size.width-200.0, child: Content() ) ] ) ) )
İşte bunların hepsi bir araya getirildi:

import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: HomePage() ); } class HomePage extends StatelessWidget { @override Widget build(context) => Scaffold( appBar: AppBar(title: Text("test")), drawer: MediaQuery.of(context).size.width < 500 ? Drawer( child: Menu(), ) : null, body: SafeArea( child:Center( child: MediaQuery.of(context).size.width < 500 ? Content() : Row( children: [ Container( width: 200.0, child: Menu() ), Container( width: MediaQuery.of(context).size.width-200.0, child: Content() ) ] ) ) ) ); } class Menu extends StatelessWidget { @override Widget build(context) => ListView( children: [ FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_one), title: Text("First Link"), ) ), FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_two), title: Text("Second Link"), ) ) ] ); } class Content extends StatelessWidget { final List<String> elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
Bu, Flutter'daki duyarlı kullanıcı arayüzüne genel bir giriş olarak ihtiyaç duyacağınız şeylerin çoğu. Uygulamasının çoğu, uygulamanızın özel kullanıcı arayüzüne bağlı olacaktır ve uygulamanızı duyarlı hale getirmek için tam olarak ne yapabileceğinizi belirlemek zordur ve tercihinize bağlı olarak birçok yaklaşımda bulunabilirsiniz. Şimdi, ortak uygulama öğelerini ve UI akışlarını düşünerek, duyarlı bir uygulamaya nasıl daha eksiksiz bir örnek oluşturabileceğimizi görelim.
Bağlamına Yerleştirmek: Bir Uygulamayı Duyarlı Hale Getirmek
Şimdiye kadar sadece bir ekranımız var. Bunu, çalışan URL tabanlı gezinme ile iki ekranlı bir uygulamaya genişletelim!
Duyarlı Giriş Sayfası Oluşturma
Uygulamanızın bir giriş sayfası olma ihtimali yüksektir. Bunu nasıl duyarlı hale getirebiliriz?
Mobil cihazlarda giriş ekranları genellikle birbirine oldukça benzer. Kullanılabilir alan fazla değil; genellikle sadece widget'larının etrafında bir miktar Padding
bulunan bir Column
ve bir kullanıcı adı ve parola yazmak için TextField
s ve oturum açmak için bir düğme içerir. Yani, oldukça standart (diğer şeylerin yanı sıra, bunun gerektirdiği gibi çalışmıyor olsa da) , bir mobil uygulama için her TextField
için bir TextEditingController
) giriş sayfası aşağıdaki olabilir:
Scaffold( body: Container( padding: const EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text("Welcome to the app, please log in"), TextField( decoration: InputDecoration( labelText: "username" ) ), TextField( obscureText: true, decoration: InputDecoration( labelText: "password" ) ), RaisedButton( color: Colors.blue, child: Text("Log in", style: TextStyle(color: Colors.white)), onPressed: () {} ) ] ), ), )
Bir mobil cihazda iyi görünüyor, ancak bu çok geniş TextField
daha büyük bir ekran bir yana, tablette bile sarsıcı görünmeye başlıyor. Ancak, telefonların farklı ekran boyutları olduğu için sabit bir genişliğe karar veremiyoruz ve bir dereceye kadar esnekliği korumalıyız.
Örneğin, deney yoluyla, maksimum genişliğin 500 olması gerektiğini bulabiliriz. Peki, Container
constraints
500'e ayarlardık (önceki örnekte Padding
yerine bir Container
kullandım çünkü bununla nereye gideceğimi biliyordum. ) ve gitmeye hazırız, değil mi? Pek değil, çünkü bu, oturum açma widget'larının ekranın sol tarafına yapışmasına neden olur ve bu, her şeyi uzatmaktan bile daha kötü olabilir. Bu nedenle, aşağıdaki gibi bir Center
widget'ına sarıyoruz:
Center( child: Container( constraints: BoxConstraints(maxWidth: 500), padding: const EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), child: Column(/* ... \*/) ) )
Bu zaten iyi görünüyor ve ne LayoutBuilder
ne de MediaQuery.of MediaQuery.of(context).size
kullanmak zorunda kalmadık. Yine de bunun çok iyi görünmesi için bir adım daha ileri gidelim. Ön plan kısmı arka plandan bir şekilde ayrılmış olsaydı, bence daha iyi görünürdü. Bunu, girdi widget'ları ile Container
arkasında ne olduğuna bir arka plan rengi vererek ve ön plan Container
beyaz tutarak başarabiliriz. Biraz daha iyi görünmesini sağlamak için, Container
büyük cihazlarda ekranın üstüne ve altına doğru esnemesini engelleyelim, köşeleri yuvarlatalım ve iki düzen arasında ona güzel bir animasyonlu geçiş yapalım.
Artık bunların tümü, hem arka plan rengini ayarlamak hem de yalnızca daha büyük ekranlarda yanlara değil, Container
her tarafına dolgu eklemek için bir LayoutBuilder
ve bir dış Container
gerektirir. Ayrıca, dolgu miktarındaki değişikliği animasyonlu hale getirmek için, bu dış Container
bir AnimatedContainer
çevirmemiz yeterlidir; bu, animasyon için bir duration
gerektirir, bu da yarım saniyeye ayarlayacağız, yani Duration(milliseconds: 500)
kod.
İşte duyarlı bir giriş sayfası örneği:

class LoginPage extends StatelessWidget { @override Widget build(context) => Scaffold( body: LayoutBuilder( builder: (context, constraints) { return AnimatedContainer( duration: Duration(milliseconds: 500), color: Colors.lightGreen[200], padding: constraints.maxWidth < 500 ? EdgeInsets.zero : EdgeInsets.all(30.0), child: Center( child: Container( padding: EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), constraints: BoxConstraints( maxWidth: 500, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5.0), ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text("Welcome to the app, please log in"), TextField( decoration: InputDecoration( labelText: "username" ) ), TextField( obscureText: true, decoration: InputDecoration( labelText: "password" ) ), RaisedButton( color: Colors.blue, child: Text("Log in", style: TextStyle(color: Colors.white)), onPressed: () { Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => HomePage() ) ); } ) ] ), ), ) ); } ) ); }
Gördüğünüz gibi, RaisedButton
'ın onPressed
, bizi HomePage
adlı bir ekrana yönlendiren bir geri aramaya değiştirdim (bu, örneğin, daha önce GridView
ve bir menü veya çekmece ile oluşturduğumuz görünüm olabilir). Şimdi, yine de, bu navigasyon kısmı, odaklanacağımız şey.
Adlandırılmış Rotalar: Uygulamanızın Navigasyonunu Daha Uygun Bir Web Uygulaması Gibi Hale Getirme
Web uygulamalarının sahip olduğu yaygın bir şey, ekranları URL'ye göre değiştirme yeteneğidir. Örneğin, https://appurl/login
somethingelse'den farklı bir şey https://appurl/somethingelse
. Aslında Flutter, iki amacı olan adlandırılmış rotaları destekler:
- Bir web uygulamasında, bir önceki cümlede bahsettiğim özelliğe tam olarak sahipler.
- Herhangi bir uygulamada, uygulamanız için rotaları önceden tanımlamanıza ve onlara adlar vermenize ve ardından yalnızca adlarını belirterek onlara gitmenize olanak tanırlar.
Bunu yapmak için MaterialApp
yapıcısını aşağıdakine benzer bir şekilde değiştirmemiz gerekiyor:
MaterialApp( initialRoute: "/login", routes: { "/login": (context) => LoginPage(), "/home": (context) => HomePage() } );
Ardından Navigator.push(context, route Navigator.push(context, route)
ve Navigator.pushReplacement(context, route)
(context, route) yerine Navigator.pushNamed(context, routeName)
ve Navigator.pushReplacementNamed(context, routeName)
kullanarak farklı bir rotaya geçebiliriz.
İşte bu makalenin geri kalanında oluşturduğumuz varsayımsal uygulamaya uygulananlar. DartPad'de eylemdeki adlandırılmış yolları gerçekten göremezsiniz, bu nedenle bunu kendi makinenizde flutter run
ile denemeli veya örneği çalışırken kontrol etmelisiniz:

import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( initialRoute: "/login", routes: { "/login": (context) => LoginPage(), "/home": (context) => HomePage() } ); } class LoginPage extends StatelessWidget { @override Widget build(context) => Scaffold( body: LayoutBuilder( builder: (context, constraints) { return AnimatedContainer( duration: Duration(milliseconds: 500), color: Colors.lightGreen[200], padding: constraints.maxWidth < 500 ? EdgeInsets.zero : const EdgeInsets.all(30.0), child: Center( child: Container( padding: const EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), constraints: BoxConstraints( maxWidth: 500, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5.0), ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text("Welcome to the app, please log in"), TextField( decoration: InputDecoration( labelText: "username" ) ), TextField( obscureText: true, decoration: InputDecoration( labelText: "password" ) ), RaisedButton( color: Colors.blue, child: Text("Log in", style: TextStyle(color: Colors.white)), onPressed: () { Navigator.pushReplacementNamed( context, "/home" ); } ) ] ), ), ) ); } ) ); } class HomePage extends StatelessWidget { @override Widget build(context) => Scaffold( appBar: AppBar(title: Text("test")), drawer: MediaQuery.of(context).size.width < 500 ? Drawer( child: Menu(), ) : null, body: SafeArea( child:Center( child: MediaQuery.of(context).size.width < 500 ? Content() : Row( children: [ Container( width: 200.0, child: Menu() ), Container( width: MediaQuery.of(context).size.width-200.0, child: Content() ) ] ) ) ) ); } class Menu extends StatelessWidget { @override Widget build(context) => ListView( children: [ FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_one), title: Text("First Link"), ) ), FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_two), title: Text("Second Link"), ) ), FlatButton( onPressed: () {Navigator.pushReplacementNamed( context, "/login");}, child: ListTile( leading: Icon(Icons.exit_to_app), title: Text("Log Out"), ) ) ] ); } class Content extends StatelessWidget { final List<String> elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
Flutter Maceranızla İlerleyin
Bu size Flutter ile daha büyük ekranlarda, özellikle de web'de neler yapabileceğiniz konusunda bir fikir verecektir. Çok hoş bir çerçeve, kullanımı çok kolay ve platformlar arası aşırı desteği, öğrenmeyi ve kullanmaya başlamayı daha da gerekli kılıyor. Öyleyse devam edin ve web uygulamaları için de Flutter'a güvenmeye başlayın!
Diğer Kaynaklar
- "Masaüstü kabukları", GitHub
Flutter'ın masaüstünde mevcut, her zaman güncel durumu - Flutter için masaüstü desteği, Flutter
Tam olarak desteklenen masaüstü platformları hakkında bilgi - “Flutter için web desteği”, Flutter
Web için Flutter hakkında bilgi - "Tüm Örnekler", Flutter
Flutter örneklerinin ve uygulamalarının küratörlüğünde bir listesi