1. Giriş
Dart 3, yeni bir dil bilgisi kategorisi olan dile kalıplar ekler. Dart kodu yazmanın bu yeni yolunun dışında, aralarında Android'in de bulunduğu bir dizi başka dil geliştirmesi de yapılmıştır.
- Farklı türlerdeki verileri gruplandırmak için kayıtları,
- Erişimi kontrol etmek için sınıf değiştiricileri ve
- yeni switch ifadeleri ve if-case ifadeleri oluşturun.
Bu özellikler Dart kodu yazarken daha fazla seçeneğe sahip olmanızı sağlar. Bu codelab'de, bu kodları kullanarak kodunuzu daha kompakt, sade ve esnek hale nasıl getireceğinizi öğreneceksiniz.
Bu codelab'de Flutter ve Dart hakkında bilginiz olduğu varsayılır. Biraz pasif hissediyorsanız aşağıdaki kaynaklardan yararlanarak temel bilgilerinizi tazeleyebilirsiniz:
Neler oluşturacaksınız?
Bu codelab'de, Flutter'da JSON dokümanı görüntüleyen bir uygulama oluşturulur. Uygulama, harici bir kaynaktan gelen JSON'u simüle eder. JSON dosyasında değişiklik tarihi, başlık, üstbilgi ve paragraflar gibi doküman verileri bulunur. Verileri kayıtlara düzgün bir şekilde paketlemek için kod yazarsınız. Böylece, Flutter widget'larınızın ihtiyacı olan her yerde aktarılıp paketten çıkarılabilir.
Ardından, değer bu kalıpla eşleştiğinde uygun widget'ı oluşturmak için kalıpları kullanırsınız. Ayrıca verileri yerel değişkenlere dönüştürmek için kalıpları nasıl kullanacağınızı da göreceksiniz.
Neler öğreneceksiniz?
- Farklı türlerde birden fazla değeri depolayan bir kayıt oluşturma.
- Kayıt kullanarak işlevden birden çok değer döndürme.
- Kayıtlardan ve diğer nesnelerden verileri eşleştirmek, doğrulamak ve yapılandırmak için kalıpları kullanma
- Kalıp eşleşen değerleri yeni veya mevcut değişkenlere bağlama.
- Yeni "geçiş ifadesi" özelliklerini, değiştirme ifadelerini ve "if-case" ifadelerini kullanma.
- Her destek kaydının bir "switch" veya "geçiş" ifadesinde işlendiğinden emin olmak için kapsamlılık kontrolünden yararlanma
2. Ortamınızı ayarlama
- Flutter SDK'sını yükleyin.
- Visual Studio Code (VS Code) gibi bir düzenleyici kurun.
- En az bir hedef platform (iOS, Android, Masaüstü veya web tarayıcısı) için Platform kurulumu adımlarını uygulayın.
3. Projeyi oluşturma
Kalıplar, kayıtlar ve diğer yeni özelliklerle ilgili ayrıntılara girmeden önce, tüm kodunuzu yazacağınız basit bir Flutter projesi oluşturun.
Flutter projesi oluşturma
patterns_codelab
adında yeni bir proje oluşturmak içinflutter create
komutunu kullanın.--empty
işareti, yine de kaldırmanız gerekeceğilib/main.dart
dosyasında standart sayaç uygulamasının oluşturulmasını engeller.
flutter create --empty patterns_codelab
- Ardından, VS Code'u kullanarak
patterns_codelab
dizinini açın.
code patterns_codelab
Minimum SDK sürümünü belirleme
- Projenizin SDK sürümü kısıtlamasını Dart 3 veya sonraki bir sürüme bağlı olacak şekilde ayarlayın.
pubspec.yaml
environment:
sdk: ^3.0.0
4. Projeyi oluşturma
Bu adımda, iki Dart dosyası oluşturur veya güncellersiniz:
- Uygulama için widget'ları içeren
main.dart
dosyası ve - Uygulama verilerini sağlayan
data.dart
dosyası.
Sonraki adımlarda bu dosyaların ikisini de değiştirmeye devam edeceksiniz.
Uygulamaya ilişkin verileri tanımlama
lib/data.dart
adlı yeni bir dosya oluşturun ve bu dosyaya şu kodu ekleyin:
lib/data.dart
import 'dart:convert';
class Document {
final Map<String, Object?> _json;
Document() : _json = jsonDecode(documentJson);
}
const documentJson = '''
{
"metadata": {
"title": "My Document",
"modified": "2023-05-10"
},
"blocks": [
{
"type": "h1",
"text": "Chapter 1"
},
{
"type": "p",
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"type": "checkbox",
"checked": false,
"text": "Learn Dart 3"
}
]
}
''';
G/Ç akışı veya HTTP isteği gibi harici bir kaynaktan veri alan bir program düşünün. Bu codelab'de, gelen JSON verileriyle alay ederek documentJson
değişkenindeki çok satırlı bir dizeyle bu daha gerçekçi kullanım alanını basitleştireceksiniz.
JSON verileri Document
sınıfında tanımlanır. Bu codelab'in ilerleyen bölümlerinde, ayrıştırılmış JSON'dan veri döndüren işlevler ekleyebilirsiniz. Bu sınıf, kurucusunda _json
alanını tanımlar ve başlatır.
Uygulamayı çalıştırın
flutter create
komutu, lib/main.dart
dosyasını varsayılan Flutter dosya yapısının bir parçası olarak oluşturur.
- Uygulamanın başlangıç noktası oluşturmak için
main.dart
içeriğini aşağıdaki kodla değiştirin:
lib/main.dart
import 'package:flutter/material.dart';
import 'data.dart';
void main() {
runApp(const DocumentApp());
}
class DocumentApp extends StatelessWidget {
const DocumentApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
home: DocumentScreen(
document: Document(),
),
);
}
}
class DocumentScreen extends StatelessWidget {
final Document document;
const DocumentScreen({
required this.document,
super.key,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Title goes here'),
),
body: const Column(
children: [
Center(
child: Text('Body goes here'),
),
],
),
);
}
}
Uygulamaya aşağıdaki iki widget'ı eklediniz:
DocumentApp
, kullanıcı arayüzü teması eklemek için Materyal Tasarım'ın en son sürümünü oluşturuyor.DocumentScreen
,Scaffold
widget'ını kullanarak sayfanın görsel düzenini sağlar.
- Her şeyin düzgün bir şekilde çalıştığından emin olmak için Çalıştır ve Hata Ayıkla'yı tıklayarak uygulamayı ana makinenizde çalıştırın:
- Flutter varsayılan olarak uygun hedef platformu seçer. Hedef platformu değiştirmek için Durum Çubuğu'nda geçerli platformu seçin:
DocumentScreen
widget'ında tanımlı title
ve body
öğelerinin bulunduğu boş bir çerçeve göreceksiniz:
5. Kayıt oluşturma ve geri verme
Bu adımda, bir işlev çağrısından birden fazla değer döndürmek için kayıtları kullanırsınız. Ardından, değerlere erişmek ve bunları kullanıcı arayüzünde yansıtmak için DocumentScreen
widget'ında bu işlevi çağırırsınız.
Kayıt oluşturma ve döndürme
data.dart
ürününde, Doküman sınıfınametadata
adlı ve kayıt döndüren yeni bir getter yöntemi ekleyin:
lib/data.dart
import 'dart:convert';
class Document {
final Map<String, Object?> _json;
Document() : _json = jsonDecode(documentJson);
(String, {DateTime modified}) get metadata { // Add from here...
const title = 'My Document';
final now = DateTime.now();
return (title, modified: now);
} // to here.
}
Bu işlevin dönüş türü, biri String
ve diğeri DateTime
türünde olmak üzere iki alan içeren bir kayıttır.
Döndürme ifadesi, iki değeri parantez içine alarak ((title, modified: now)
) yeni bir kayıt oluşturur.
İlk alan konumsal ve adsız, ikinci alan ise modified
olarak adlandırılmıştır.
Erişim kaydı alanları
- Kaydınızı almak ve değerlerine erişmek için
DocumentScreen
widget'ındabuild
yöntemindemetadata
alıcı yöntemini çağırın:
lib/main.dart
class DocumentScreen extends StatelessWidget {
final Document document;
const DocumentScreen({
required this.document,
super.key,
});
@override
Widget build(BuildContext context) {
final metadataRecord = document.metadata; // Add this line.
return Scaffold(
appBar: AppBar(
title: Text(metadataRecord.$1), // Modify this line,
),
body: Column(
children: [
Center(
child: Text(
'Last modified ${metadataRecord.modified}', // And this one.
),
),
],
),
);
}
}
metadata
alıcı yöntemi, metadataRecord
yerel değişkenine atanmış bir kayıt döndürür. Kayıtlar, tek bir işlev çağrısından birden çok değer döndürmenin ve bunları bir değişkene atamanın kolay ve kolay bir yoludur.
Bu kayıtta oluşturulan her bir alana erişmek için kayıtların yerleşik alıcı söz dizimidir.
- Konumsal bir alan (
title
gibi adsız bir alan) almak için kayıttaki alıcıyı$<num>
kullanın. Bu işlem yalnızca adsız alanları döndürür. modified
gibi adlandırılmış alanların konum alıcısı olmadığındanmetadataRecord.modified
gibi adını doğrudan kullanabilirsiniz.
Konumsal bir alan için alıcının adını belirlemek için $1
ile başlayın ve adlandırılmış alanları atlayın. Örneğin:
var record = (named: 'v', 'y', named2: 'x', 'z');
print(record.$1); // prints y
print(record.$2); // prints z
- Uygulamada gösterilen JSON değerlerini görmek için yeniden yükleyin. VS Code Dart eklentisi, bir dosyayı her kaydettiğinizde çalışır durumda yeniden yüklenir.
Her alanın aslında kendi türünü koruduğunu görebilirsiniz.
Text()
yöntemi, ilk bağımsız değişkeni olarak bir Dizeyi alır.modified
alanı bir DateTime'dır ve dize interpolasyonu kullanılarakString
alanına dönüştürülür.
Farklı veri türlerini döndürmenin diğer tür güvenli yolu, daha ayrıntılı bir sınıf tanımlamaktır.
6. Kalıplarla eşleştirme ve yapılandırma
Kayıtlar farklı veri türlerini etkili bir şekilde toplayabilir ve kolayca aktarabilir. Şimdi de kalıpları kullanarak kodunuzu iyileştirin.
Kalıp, bir veya daha fazla değerin alabileceği yapıyı (ör. şema gibi) temsil eder. Kalıplar, eşleşip eşleşmediklerini belirlemek için gerçek değerlerle karşılaştırılır.
Bazı kalıplar eşleştiklerinde, eşleşen değeri bu değerden çekerek yapılandırılmış hale getirir. Yapılandırma işlemi, bir nesnedeki değerleri yerel değişkenlere atamak için paketten çıkarmanıza veya bu değerler üzerinde daha fazla eşleştirme yapmanıza olanak tanır.
Bir kaydı yerel değişkenlere dönüştürme
metadata
yöntemini çağırmak içinDocumentScreen
öğesininbuild
yöntemini yeniden düzenleyin ve bu yöntemi dize kalıbı değişkeni bildirimini başlatmak için kullanın:
lib/main.dart
class DocumentScreen extends StatelessWidget {
final Document document;
const DocumentScreen({
required this.document,
super.key,
});
@override
Widget build(BuildContext context) {
final (title, modified: modified) = document.metadata; // Modify
return Scaffold(
appBar: AppBar(
title: Text(title), // Modify
),
body: Column(
children: [
Center(
child: Text(
'Last modified $modified', // Modify
),
),
],
),
);
}
}
(title, modified: modified)
kayıt kalıbı, metadata
tarafından döndürülen kaydın alanlarıyla eşleşen iki değişken kalıbı içerir.
- Sonuç, biri
modified
adlı iki alan içeren bir kayıt olduğundan ifade alt kalıpla eşleşir. - Değişken bildirim kalıbı, eşleştikleri için ifadeyi bozar, değerlerine erişir ve bunları aynı tür ve adlardaki yeni yerel değişkenlere (
String title
veDateTime modified
) bağlar.
Bir alanın adı ile onu dolduran değişkenin aynı olması için kullanılan bir kısaltma bulunur. DocumentScreen
öğesinin build
yöntemini aşağıdaki gibi yeniden düzenleyin.
lib/main.dart
class DocumentScreen extends StatelessWidget {
final Document document;
const DocumentScreen({
required this.document,
super.key,
});
@override
Widget build(BuildContext context) {
final (title, :modified) = document.metadata; // Modify
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Center(
child: Text(
'Last modified $modified',
),
),
],
),
);
}
}
:modified
değişken kalıbının söz dizimi modified: modified
ifadesinin kısaltmasıdır. Farklı bir ada sahip yeni bir yerel değişken istiyorsanız bunun yerine modified: localModified
yazabilirsiniz.
- Önceki adımla aynı sonucu görmek için sayfayı yeniden yükleyin. Davranış tamamen aynıdır; kodunuzu daha kısa ve öz hale getirdiniz.
7. Verileri ayıklamak için kalıplar kullanma
Belirli bağlamlarda, kalıplar yalnızca eşleşmek ve yıkım sağlamakla kalmaz, aynı zamanda kalıbın eşleşip eşleşmediğine bağlı olarak kodun ne yapacağı hakkında da bir karar verebilir. Bunlara yeniden değerlendirilebilir kalıplar denir.
Son adımda kullandığınız değişken bildirim kalıbı çürütilemez bir kalıptır: Değerin kalıpla eşleşmesi gerekir; aksi takdirde bu bir hatadır ve yapılandırma işlemi gerçekleşmez. Herhangi bir değişken beyanını veya atamayı düşünün; aynı türde olmayan değişkenlere değer atayamazsınız.
Öte yandan, yeniden yapılandırılabilir kalıplar kontrol akışı bağlamlarında kullanılır:
- Karşılaştırdıkları bazı değerlerin eşleşmeyeceğini beklerler.
- Değerin eşleşip eşleşmediğine bağlı olarak kontrol akışını etkilemesi amaçlanır.
- Eşleşmiyorlarsa bir hata ile yürütmeyi kesintiye uğratmazlar, yalnızca sonraki ifadeye geçerler.
- Yalnızca kullanılabilir olan değişkenleri yapılandırıp bağlayabilirler.
JSON değerlerini kalıplar olmadan okuma
Bu bölümde, kalıpların JSON verileriyle çalışmanıza nasıl yardımcı olabileceğini görmek için verileri kalıp eşleştirme olmadan okuyacaksınız.
metadata
özelliğinin önceki sürümünü,_json
haritasındaki değerleri okuyan bir sürümle değiştirin. Bumetadata
sürümünü kopyalayıpDocument
sınıfına yapıştırın:
lib/data.dart
class Document {
final Map<String, Object?> _json;
Document() : _json = jsonDecode(documentJson);
(String, {DateTime modified}) get metadata {
if (_json.containsKey('metadata')) { // Modify from here...
final metadataJson = _json['metadata'];
if (metadataJson is Map) {
final title = metadataJson['title'] as String;
final localModified =
DateTime.parse(metadataJson['modified'] as String);
return (title, modified: localModified);
}
}
throw const FormatException('Unexpected JSON'); // to here.
}
}
Bu kod, kalıplar kullanılmadan verilerin doğru şekilde yapılandırıldığını doğrular. Daha sonraki bir adımda, aynı doğrulamayı daha az kod kullanarak gerçekleştirmek için kalıp eşleştirmeyi kullanacaksınız. Başka herhangi bir işlem yapmadan önce üç kontrol gerçekleştirir:
- JSON, beklediğiniz veri yapısını içerir:
if (_json.containsKey('metadata'))
- Veriler beklediğiniz türe sahip:
if (metadataJson is Map)
- Verilerin boş olmadığı, önceki kontrolde dolaylı olarak onaylanmıştır.
Harita kalıbı kullanarak JSON değerlerini okuma
Yenilenebilir bir kalıpla, JSON'un beklenen yapıya sahip olduğunu bir harita kalıbı kullanarak doğrulayabilirsiniz.
- Önceki
metadata
sürümünü şu kodla değiştirin:
lib/data.dart
class Document {
final Map<String, Object?> _json;
Document() : _json = jsonDecode(documentJson);
(String, {DateTime modified}) get metadata {
if (_json // Modify from here...
case {
'metadata': {
'title': String title,
'modified': String localModified,
}
}) {
return (title, modified: DateTime.parse(localModified));
} else {
throw const FormatException('Unexpected JSON');
} // to here.
}
}
Burada, yeni bir tür "if" deyimi (Dart 3'te kullanıma sunulan) görürsünüz. if-case Destek kaydı gövdesi yalnızca destek kaydı kalıbının _json
içindeki verilerle eşleşmesi durumunda yürütülür. Bu eşleşme, gelen JSON'u doğrulamak için metadata
ürününün ilk sürümünde yazdığınız kontrollerin aynısını gerçekleştirir. Bu kod aşağıdakileri doğrular:
_json
bir Harita türüdür._json
,metadata
anahtarı içeriyor._json
, boş değil._json['metadata']
aynı zamanda bir harita türüdür._json['metadata']
,title
vemodified
anahtarlarını içeriyor.title
velocalModified
dizedir ve boş değildir.
Değer eşleşmezse model refutes (yürütmeye devam etmeyi reddeder) ve else
ifadesine gider. Eşleştirme başarılı olursa kalıp, title
ve modified
değerlerini haritadan yapılandırır ve yeni yerel değişkenlere bağlar.
Kalıpların tam listesi için özellik spesifikasyonunun Kalıplar bölümündeki tabloya bakın.
8. Uygulamayı daha fazla kalıp için hazırlayın
Şu ana kadar JSON verilerinin metadata
kısmını ele almışsınız. Bu adımda, blocks
listesindeki verileri işleyip uygulamanıza oluşturmak için iş mantığınızı biraz daha hassaslaştıracaksınız.
{
"metadata": {
// ...
},
"blocks": [
{
"type": "h1",
"text": "Chapter 1"
},
// ...
]
}
Verileri depolayan bir sınıf oluşturma
data.dart
hizmetine, JSON verilerindeki bloklardan birine ilişkin verileri okumak ve depolamak için kullanılan yeni bir sınıf (Block
) ekleyin.
lib/data.dart
class Block {
final String type;
final String text;
Block(this.type, this.text);
factory Block.fromJson(Map<String, dynamic> json) {
if (json case {'type': final type, 'text': final text}) {
return Block(type, text);
} else {
throw const FormatException('Unexpected JSON format');
}
}
}
fromJson()
fabrika oluşturucusu, daha önce gördüğünüz bir harita deseniyle aynı "if-case" özelliğini kullanır.
Anahtarlardan biri (checked
) kalıpta dikkate alınmasa da json
değerinin harita deseniyle eşleştiğine dikkat edin. Harita kalıpları, harita nesnesinde bulunan ve kalıpta açıkça hesaba katılmayan tüm girişleri yoksayar.
Blok nesnelerin listesini döndürme
- Sonra,
Document
sınıfına yeni bir işlev (getBlocks()
) ekleyin.getBlocks()
, JSON'uBlock
sınıfının örneklerine ayrıştırır ve kullanıcı arayüzünüzde oluşturulacak blokların listesini döndürür:
lib/data.dart
class Document {
final Map<String, Object?> _json;
Document() : _json = jsonDecode(documentJson);
(String, {DateTime modified}) get metadata {
if (_json
case {
'metadata': {
'title': String title,
'modified': String localModified,
}
}) {
return (title, modified: DateTime.parse(localModified));
} else {
throw const FormatException('Unexpected JSON');
}
}
List<Block> getBlocks() { // Add from here...
if (_json case {'blocks': List blocksJson}) {
return [for (final blockJson in blocksJson) Block.fromJson(blockJson)];
} else {
throw const FormatException('Unexpected JSON format');
}
} // to here.
}
getBlocks()
işlevi, daha sonra kullanıcı arayüzünü oluşturmak için kullanacağınız Block
nesnelerinin listesini döndürür. Tanıdık bir if-case ifadesi, doğrulamayı gerçekleştirir ve blocks
meta verilerinin değerini blocksJson
adlı yeni bir List
öğesine yayınlar (kalıplar olmadan yayınlamak için toList()
yöntemine ihtiyacınız olur).
Değişmez liste, yeni listeyi Block
nesneyle doldurmak için bir koleksiyon içerir.
Bu bölümde, bu codelab'de henüz denemediğiniz kalıplarla ilgili hiçbir özellik tanıtılmıyor. Sonraki adımda, kullanıcı arayüzünüzdeki liste öğelerini oluşturmaya hazırlanırsınız.
9. Dokümanı görüntülemek için desenler kullanma
Artık bir if-case ifadesi ve refuable kalıpları kullanarak JSON verilerinizi başarıyla yapılandırıp yeniden oluşturuyorsunuz. Ancak "if-case", kalıplarla gelen akış yapılarını kontrol etmek için yapılan geliştirmelerden yalnızca biridir. Şimdi, çürütülebilir kalıplar hakkındaki bilginizi kullanarak ifadeleri değiştirebilirsiniz.
Switch ifadeleriyle kalıplar kullanarak nelerin oluşturulduğunu kontrol etme
main.dart
ürününde, her blokuntype
alanına göre stilini belirleyen yeni bir widget (BlockWidget
) oluşturun.
lib/main.dart
class BlockWidget extends StatelessWidget {
final Block block;
const BlockWidget({
required this.block,
super.key,
});
@override
Widget build(BuildContext context) {
TextStyle? textStyle;
switch (block.type) {
case 'h1':
textStyle = Theme.of(context).textTheme.displayMedium;
case 'p' || 'checkbox':
textStyle = Theme.of(context).textTheme.bodyMedium;
case _:
textStyle = Theme.of(context).textTheme.bodySmall;
}
return Container(
margin: const EdgeInsets.all(8),
child: Text(
block.text,
style: textStyle,
),
);
}
}
build
yöntemindeki Switch ifadesi, block
nesnesinin type
alanını açar.
- İlk olgu ifadesinde sabit dize kalıbı kullanılır.
block.type
,h1
sabit değerine eşitse kalıp eşleşir. - İkinci olgu ifadesi, alt kalıp olarak iki sabit dize kalıbına sahip bir mantıksal-veya kalıp kullanır.
block.type
,p
veyacheckbox
alt kalıplarından biriyle eşleşirse kalıp eşleşir.
- Son kullanım, joker karakter kalıbıdır (
_
). Anahtar kelimelerdeki joker karakterler diğer tüm karakterlerle eşleşir. Bunlar, geçiş ifadelerinde hâlâ izin verilen (biraz daha ayrıntılıdır)default
ifadeleriyle aynı şekilde davranırlar.
Joker karakter kalıpları, bir kalıpa izin verilen her yerde kullanılabilir (ör. değişken bildirim kalıbında: var (title, _) = document.metadata;
)
Bu bağlamda joker karakter herhangi bir değişkeni bağlamaz. İkinci alanı siler.
Sonraki bölümde, Block
nesnelerini görüntüledikten sonra değiştirme hakkında daha fazla bilgi edineceksiniz.
Doküman içeriğini göster
DocumentScreen
widget'ının build
yönteminde getBlocks()
yöntemini çağırarak Block
nesnelerinin listesini içeren bir yerel değişken oluşturun.
DocumentationScreen
içerisindeki mevcutbuild
yöntemini bu sürümle değiştirin:
lib/main.dart
class DocumentScreen extends StatelessWidget {
final Document document;
const DocumentScreen({
required this.document,
super.key,
});
@override
Widget build(BuildContext context) {
final (title, :modified) = document.metadata;
final blocks = document.getBlocks(); // Add this line
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Text('Last modified: $modified'), // Modify from here
Expanded(
child: ListView.builder(
itemCount: blocks.length,
itemBuilder: (context, index) {
return BlockWidget(block: blocks[index]);
},
),
), // to here.
],
),
);
}
}
BlockWidget(block: blocks[index])
satırı, getBlocks()
yönteminden döndürülen bloklar listesindeki her bir öğe için bir BlockWidget
widget'ı oluşturur.
- Uygulamayı çalıştırın, daha sonra ekranda blokları göreceksiniz:
10. Geçiş ifadelerini kullanma
Kalıplar, switch
ve case
özelliklerine pek çok özellik ekler. Dart, bunların daha fazla yerde kullanılabilmesini sağlamak için ifadeler arasında geçiş yapmıştır. Vakalar, doğrudan bir değişken atamasına veya döndürülen deyime bir değer sağlayabilir.
Switch deyimini bir geçiş ifadesine dönüştürün
Dart analiz aracı, kodunuzda değişiklik yapmanıza yardımcı olacak destekler sağlar.
- İmlecinizi önceki bölümde bulunan değiştirme ifadesine getirin.
- Mevcut asistleri görüntülemek için ampulü tıklayın.
- Geçiş ifadesine dönüştür yardımını seçin.
Bu kodun yeni sürümü aşağıdaki gibi görünür:
lib/main.dart
class BlockWidget extends StatelessWidget {
final Block block;
const BlockWidget({
required this.block,
super.key,
});
@override
Widget build(BuildContext context) {
TextStyle? textStyle; // Modify from here
textStyle = switch (block.type) {
'h1' => Theme.of(context).textTheme.displayMedium,
'p' || 'checkbox' => Theme.of(context).textTheme.bodyMedium,
_ => Theme.of(context).textTheme.bodySmall
}; // to here.
return Container(
margin: const EdgeInsets.all(8),
child: Text(
block.text,
style: textStyle,
),
);
}
}
Switch ifadesi, Switch deyimine benzer. Ancak case
anahtar kelimesini ortadan kaldırır ve kalıbı destek kaydı gövdesinden ayırmak için =>
değerini kullanır. Switch ifadelerinin aksine, Switch ifadeleri bir değer döndürür ve ifadenin kullanılabileceği her yerde kullanılabilir.
11. Nesne kalıplarını kullanma
Dart, nesne odaklı bir dil olduğundan kalıplar tüm nesneler için geçerlidir. Bu adımda, kullanıcı arayüzünüzün tarih oluşturma mantığını iyileştirmek için bir nesne kalıbını etkinleştirecek ve nesne özelliklerini yapılandıracaksınız.
Nesne kalıplarından özellikleri ayıklama
Bu bölümde, kalıplar kullanılarak son değiştirilme tarihinin görüntülenme şeklini iyileştireceksiniz.
formatDate
yönteminimain.dart
öğesine ekleyin:
lib/main.dart
String formatDate(DateTime dateTime) {
final today = DateTime.now();
final difference = dateTime.difference(today);
return switch (difference) {
Duration(inDays: 0) => 'today',
Duration(inDays: 1) => 'tomorrow',
Duration(inDays: -1) => 'yesterday',
Duration(inDays: final days, isNegative: true) => '${days.abs()} days ago',
Duration(inDays: final days) => '$days days from now',
};
}
Bu yöntem, bir Duration
nesnesi olan difference
değerini açan bir geçiş ifadesi döndürür. JSON verilerindeki today
ile modified
değeri arasındaki süreyi temsil eder.
Switch ifadesinin her durumu, nesnenin inDays
ve isNegative
özelliklerinde alıcıları çağırarak eşleşen bir nesne kalıbı kullanmaktadır. Söz dizimi, bir Duration nesnesi oluşturuyor gibi görünüyor, ancak aslında difference
nesnesindeki alanlara erişiyor.
İlk üç örnekte, inDays
nesne özelliğini eşleştirmek ve karşılık gelen dizeyi döndürmek için 0
, 1
ve -1
sabit alt kalıpları kullanılır.
Son iki destek kaydı bugün, dün ve yarının ötesindeki süreleri kapsar:
isNegative
özelliği, boole sabit kalıbıtrue
ile eşleşirse (değişiklik tarihi geçmişteyse) gün önce gösterilir.- Bu durumda fark söz konusu değilse süre pozitif bir gün sayısı olmalıdır (
isNegative: false
ile açıkça doğrulama yapmaya gerek yoktur). Değişiklik tarihi gelecektedir ve bugünden sonraki gün sayısını gösterir.
Haftalar için biçimlendirme mantığı ekleme
- 7 günden uzun süreleri tanımlamak için biçimlendirme işlevinize iki yeni durum ekleyin. Böylece, kullanıcı arayüzü bunları hafta olarak görüntüleyebilir:
lib/main.dart
String formatDate(DateTime dateTime) {
final today = DateTime.now();
final difference = dateTime.difference(today);
return switch (difference) {
Duration(inDays: 0) => 'today',
Duration(inDays: 1) => 'tomorrow',
Duration(inDays: -1) => 'yesterday',
Duration(inDays: final days) when days > 7 => '${days ~/ 7} weeks from now', // Add from here
Duration(inDays: final days) when days < -7 =>
'${days.abs() ~/ 7} weeks ago', // to here.
Duration(inDays: final days, isNegative: true) => '${days.abs()} days ago',
Duration(inDays: final days) => '$days days from now',
};
}
Bu kodda Guard ifadeler kullanıma sunulmuştur:
- Koruma ifadesi, büyük/küçük harf kalıbından sonra
when
anahtar kelimesini kullanır. - Bunlar; şart-durumları, değiştirme ifadeleri ve değiştirme ifadelerinde kullanılabilir.
- Bir kalıba yalnızca eşleştirildikten sonra koşul eklerler.
- Guard ifadesi yanlış olarak değerlendirilirse kalıbın tamamı reddedilir ve yürütme bir sonraki destek kaydına devam eder.
Yeni biçimlendirilen tarihi kullanıcı arayüzüne ekleyin
- Son olarak,
formatDate
işlevini kullanmak içinDocumentScreen
ürünündebuild
yöntemini güncelleyin:
lib/main.dart
class DocumentScreen extends StatelessWidget {
final Document document;
const DocumentScreen({
required this.document,
super.key,
});
@override
Widget build(BuildContext context) {
final (title, :modified) = document.metadata;
final formattedModifiedDate = formatDate(modified); // Add this line
final blocks = document.getBlocks();
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Text('Last modified: $formattedModifiedDate'), // Modify this line
Expanded(
child: ListView.builder(
itemCount: blocks.length,
itemBuilder: (context, index) {
return BlockWidget(block: blocks[index]);
},
),
),
],
),
);
}
}
- Uygulamanızdaki değişiklikleri görmek için sayfayı yeniden yükleyin:
12. Kapsamlı geçiş için bir sınıfı müdafaa edin
Son geçişin sonunda joker karakter veya varsayılan büyük/küçük harf kullanmadığınıza dikkat edin. Ulaşabilecek değerler için her zaman bir durum eklemek iyi bir uygulama olsa da tanımladığınız durumların inDays
potansiyel olarak alabileceği tüm olası değerleri hesaba kattığını bildiğiniz için bunun gibi basit bir örnekte sorun yaratmaz.
Bir geçişteki tüm durumlar ele alındığında, buna kapsamlı geçiş adı verilir. Örneğin, true
ve false
destek kayıtları olduğunda bool
türünü açmak tam kapsamlıdır. Enumlar sabit değerlerden oluşan sabit sayıları temsil ettiğinden, numaralandırma değerlerinin her biri için bir durum olduğunda enum
türünü açma işlemi kapsamlıdır.
Dart 3, yeni sınıf değiştiricisi sealed
ile kapsamlılık denetimini nesneler ve sınıf hiyerarşilerini kapsayacak şekilde genişletti. Block
sınıfınızı mühürlü bir süper sınıf olarak yeniden düzenleyin.
Alt sınıf oluşturma
data.dart
ürününde,Block
süresini uzatan üç yeni sınıf (HeaderBlock
,ParagraphBlock
veCheckboxBlock
) oluşturun:
lib/data.dart
class HeaderBlock extends Block {
final String text;
HeaderBlock(this.text);
}
class ParagraphBlock extends Block {
final String text;
ParagraphBlock(this.text);
}
class CheckboxBlock extends Block {
final String text;
final bool isChecked;
CheckboxBlock(this.text, this.isChecked);
}
Bu sınıfların her biri, orijinal JSON'deki farklı type
değerlerine karşılık gelir: 'h1'
, 'p'
ve 'checkbox'
.
Süper sınıfı karşılayın
Block
sınıfınısealed
olarak işaretleyin. Ardından, if-case ifadesini, JSON'de belirtilentype
öğesine karşılık gelen alt sınıfı döndüren bir anahtar ifadesi olarak yeniden düzenleyin:
lib/data.dart
sealed class Block {
Block();
factory Block.fromJson(Map<String, Object?> json) {
return switch (json) {
{'type': 'h1', 'text': String text} => HeaderBlock(text),
{'type': 'p', 'text': String text} => ParagraphBlock(text),
{'type': 'checkbox', 'text': String text, 'checked': bool checked} =>
CheckboxBlock(text, checked),
_ => throw const FormatException('Unexpected JSON format'),
};
}
}
sealed
anahtar kelimesi, bir sınıf değiştiricidir. Bu, bu sınıfı yalnızca aynı kitaplıkta genişletebileceğiniz veya uygulayabileceğiniz anlamına gelir. Analiz aracı bu sınıfın alt türlerini bildiğinden, bu türlerden herhangi birini kapsamayan ve tüm öğeleri kapsamayan bir anahtar olduğunda hata bildirir.
Widget'ları görüntülemek için geçiş ifadesi kullanın
main.dart
içindeki BlockWidget sınıfını, her durum için nesne kalıplarını kullanan bir anahtar ifadesiyle güncelleyin:
lib/main.dart
class BlockWidget extends StatelessWidget {
final Block block;
const BlockWidget({
required this.block,
super.key,
});
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(8),
child: switch (block) {
HeaderBlock(:final text) => Text(
text,
style: Theme.of(context).textTheme.displayMedium,
),
ParagraphBlock(:final text) => Text(text),
CheckboxBlock(:final text, :final isChecked) => Row(
children: [
Checkbox(value: isChecked, onChanged: (_) {}),
Text(text),
],
),
},
);
}
}
İlk BlockWidget
sürümünüzde, TextStyle
döndürmek için Block
nesnesinin bir alanını açtınız. Şimdi, Block
nesnesinin bir örneğini değiştirip alt sınıflarını temsil eden nesne kalıplarıyla eşleştirme yapacak ve işlemde nesnenin özelliklerini çıkaracaksınız.
Dart analizcisi, Block
öğesini mühürlü bir sınıf yaptığınız için her bir alt sınıfın anahtar ifadesinde işlenip işlenmediğini kontrol edebilir.
Ayrıca burada bir Switch ifadesi kullandığınızda, daha önce gereken ayrı bir döndürme ifadesinin aksine sonucu doğrudan child
öğesine iletebileceğinizi unutmayın.
- İlk kez oluşturulan onay kutusu JSON verilerini görmek için yoğun yeniden yükleyin:
13. Tebrikler
Kalıplar, kayıtlar, gelişmiş geçiş ve büyük/küçük harf kullanımı ve mühürlü sınıflarla başarılı bir şekilde denemeler yaptınız. Pek çok bilgiyi ele almışsınız, ancak bu özelliklerin yalnızca küçük bir kısmını çizdiniz. Kalıplar hakkında daha fazla bilgi edinmek için özellik spesifikasyonuna bakın.
Farklı kalıp türleri, görünebilecekleri farklı bağlamlar ve alt kalıpların olası iç içe yerleştirilmesi, davranıştaki olasılıkları sonsuz hale getirir. Ancak bu reklamları kolayca görebilirsiniz.
Flutter'da içerik görüntülemenin çeşitli yollarını kalıplar kullanarak düşünebilirsiniz. Kalıpları kullanarak verileri güvenli bir şekilde ayıklayarak kullanıcı arayüzünüzü birkaç satır kodla oluşturabilirsiniz.
Sırada ne var?
- Dart dokümanlarının Dil bölümünde bulunan kalıplar, kayıtlar, gelişmiş geçiş, destek kayıtları ve sınıf değiştiricilerle ilgili belgelere göz atın.
Referans belgeler
Örnek kodun tamamını flutter/codelabs
deposunda adım adım inceleyin.
Her yeni özellikle ilgili ayrıntılı teknik özellikler için orijinal tasarım dokümanlarına göz atın: