Bu codelab hakkında
1. Giriş
Dart 3, dile yeni bir dil bilgisi kategorisi olan kalıpları ekler. Dart kodu yazmanın bu yeni yolunun yanı sıra aşağıdakiler gibi başka dil geliştirmeleri de vardır:
- Farklı türde 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.
Bu özellikler, Dart kodu yazarken sahip olduğunuz seçenekleri genişletir. Bu codelab'de, kodunuzu daha kompakt, basit ve esnek hale getirmek için bunları nasıl kullanacağınızı öğreneceksiniz.
Bu kod laboratuvarının hedef kitlesi, Flutter ve Dart hakkında bilgi sahibi olan kullanıcılardır. Bilgilerinizi tazelemek istiyorsanız aşağıdaki kaynaklardan yararlanabilirsiniz:
Ne oluşturacaksınız?
Bu kod laboratuvarında, Flutter'da JSON belgesi 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, üstbilgiler ve paragraflar gibi doküman verileri bulunur. Flutter widget'larınızın ihtiyaç duyduğu her yerde aktarılıp paketten çıkarılabilmesi için verileri kayıtlara düzgün bir şekilde paketleyecek kod yazarsınız.
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şkenler halinde yapılandırmamak için kalıpların nasıl kullanıldığını da göreceksiniz.
Neler öğreneceksiniz?
- Farklı türlerde birden fazla değer depolayan bir kayıt oluşturma.
- Bir işlevden kayıt kullanarak birden çok değer döndürme.
- Kayıtlardaki ve diğer nesnelerdeki verileri eşleştirmek, doğrulamak ve yapısını kaldırmak için desenleri kullanma.
- Desenle eşleşen değerleri yeni veya mevcut değişkenlere bağlama.
- Yeni switch ifadesi özelliklerini, switch ifadelerini ve if-case ifadelerini kullanma
- Her durumun bir switch ifadesi veya switch ifadesinde ele alındığından emin olmak için kapsamlı kontrol özelliğinden nasıl yararlanılır?
2. Ortamınızı ayarlama
- Flutter SDK'yı yükleyin.
- Visual Studio Code (VS Code) gibi bir düzenleyici ayarlayın.
- 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 özellikleri incelemeden önce, tüm kodunuzu yazacağınız basit bir Flutter projesi oluşturmak için biraz zaman ayırın.
Flutter projesi oluşturma
patterns_codelab
adlı yeni bir proje oluşturmak içinflutter create
komutunu kullanın.--empty
işareti,lib/main.dart
dosyasında standart sayaç uygulamasının oluşturulmasını engeller. Bu uygulamayı zaten kaldırmanız gerekir.
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ü ayarlama
- Projenizin SDK sürümü kısıtlamasını Dart 3 veya sonraki sürümlere 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:
- Uygulamanın widget'larını içeren
main.dart
dosyası ve - Uygulamanın verilerini sağlayan
data.dart
dosyası.
Sonraki adımlarda bu dosyaların ikisini de değiştirmeye devam edeceksiniz.
Uygulamanın verilerini tanımlama
lib/data.dart
adlı yeni bir dosya oluşturun ve dosyaya aşağıdaki 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 verilerini documentJson
değişkeninde çok satırlı bir dizeyle taklit ederek 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ılan JSON'dan veri döndüren işlevler ekleyeceksiniz. Bu sınıf, _json
alanını oluşturucuda tanımlar ve başlatır.
Uygulamayı çalıştırma
flutter create
komutu, varsayılan Flutter dosya yapısının bir parçası olarak lib/main.dart
dosyasını oluşturur.
- Uygulama için bir başlangıç noktası oluşturmak üzere
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ünün temasını belirlemek için Materyal Tasarım'ın en son sürümünü kurar.DocumentScreen
,Scaffold
widget'ını kullanarak sayfanın görsel düzenini sağlar.
- Her şeyin sorunsuz ç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 kullanılabilir olan hedef platformu seçer. Hedef platformu değiştirmek için durum çubuğunda mevcut platformu seçin:
DocumentScreen
widget'ında tanımlanan title
ve body
öğelerini içeren boş bir çerçeve görürsünüz:
5. Kayıt oluşturma ve döndürme
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üne 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
dosyasında, Document sınıfınametadata
adlı ve kayıt döndüren yeni bir alıcı 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
türüne, diğeri DateTime
türüne sahip iki alana sahip bir kayıttır.
Döndürme ifadesi, iki değeri paranteze (title, modified: now)
alarak yeni bir kayıt oluşturur.
İlk alan konumsal ve adsız, ikinci alan ise modified
olarak adlandırılmıştır.
Kayıt alanlarına erişim
DocumentScreen
widget'ında, kaydınızı alıp değerlerine erişebilmek içinbuild
yöntemindekimetadata
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 atanan 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 hafif ve kolay bir yoludur.
Bu kayıtta oluşturulan alanlara erişmek için kayıtların yerleşik alıcı söz dizimini kullanabilirsiniz.
- Konumsal bir alanı (
title
gibi adsız bir alan) almak için kayıtta$<num>
alıcısını kullanın. Bu işlem yalnızca adlandırılmamış alanları döndürür. modified
gibi adlandırılmış alanların konumsal alıcıları yoktur. Bu nedenle, adını doğrudan kullanabilirsiniz (ör.metadataRecord.modified
).
Konumsal bir alan için alıcı adının belirlenmesi amacıyla $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
- JSON değerlerini uygulamada görmek için anında yeniden yükleyin. VS Code Dart eklentisi, her dosya kaydettiğinizde anında yeniden yüklenir.
Her alanın türünü koruduğunu görebilirsiniz.
Text()
yöntemi, ilk bağımsız değişkeni olarak bir dize alır.modified
alanı bir DateTime olup dize ekleme kullanılarakString
değerine dönüştürülür.
Farklı veri türlerini döndürmenin tür açısından güvenli diğer yolu, daha ayrıntılı bir sınıf tanımlamaktır.
6. Desenlerle eşleştirme ve yapıyı bozma
Kayıtlar, farklı veri türlerini verimli bir şekilde toplayabilir ve kolayca aktarabilir. Artık desenleri kullanarak kodunuzu iyileştirebilirsiniz.
Desen, bir veya daha fazla değerin alabileceği bir yapıyı (ör. plan) 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ştiğinde verileri çıkararak eşleşen değeri yapısını bozar. Yapıyı bölme, bir nesnenin değerlerini yerel değişkenlere atamak veya bunlarla daha fazla eşleştirme yapmak için paketini açmanıza olanak tanır.
Bir kaydı yerel değişkenler halinde yapılandırma
DocumentScreen
sınıfınınbuild
yöntemini,metadata
'yi çağıracak ve kalıp değişkeni beyanını başlatmak için kullanacak şekilde yeniden yapılandı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 (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ıp içerir.
- Sonuç, biri
modified
adlı iki alana sahip bir kayıt olduğundan ifade alt kalıpla eşleşir. - Eşleştiklerinden, değişken beyanı kalıbı ifadenin yapısını bozar, değerlerine erişir ve bunları aynı tür ve adlara sahip yeni yerel değişkenlere (
String title
veDateTime modified
) bağlar.
Bir alanın adı ile onu dolduran değişkenin aynı olduğu durumlar için kısa bir yöntem vardır. DocumentScreen
sınıfının build
yöntemini aşağıdaki gibi yeniden yapılandı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 (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
kısaltmasıdır. Farklı bir ada sahip yeni bir yerel değişken istiyorsanız bunun yerine modified: localModified
yazabilirsiniz.
- Önceki adımdakiyle aynı sonucu görmek için anında yeniden yükleyin. Davranış tam olarak aynıdır; yalnızca kodunuzu daha kısa hale getirdiniz.
7. Verileri ayıklamak için kalıpları kullanma
Belirli bağlamlarda kalıplar yalnızca eşleşip yapısını bozmakla kalmaz, aynı zamanda kalıbın eşleşip eşleşmediğine bağlı olarak kodun ne yaptığı hakkında karar verebilir. Bunlara çürütülebilir kalıplar denir.
Son adımda kullandığınız değişken beyanı kalıbı reddedilemez bir kalıptır: Değer kalıpla eşleşmelidir. Aksi takdirde hata oluşur ve yapı bozma işlemi gerçekleşmez. Herhangi bir değişken beyanını veya atamasını düşünün. Aynı türde değilse bir değişkene değer atayamazsınız.
Öte yandan, reddedilebilir 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şmemesine bağlı olarak kontrol akışını etkilemek için kullanılırlar.
- Eşleşmezlerse bir hatayla yürütmeyi kesintiye uğratmazlar, sadece bir sonraki ifadeye geçerler.
- Eşleştiğinde yalnızca kullanılabilen değişkenlerin yapısını bozabilir ve bu değişkenleri bağlayabilir
JSON değerlerini kalıp 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 okursunuz.
metadata
'ün önceki sürümünü,_json
haritasındaki değerleri okuyan bir sürümle değiştirin.metadata
'nin bu 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ıp kullanmadan verilerin doğru şekilde yapılandırıldığını doğrular. Daha sonraki bir adımda, daha az kod kullanarak aynı doğrulamayı gerçekleştirmek için kalıp eşleştirmeyi kullanırsınız. 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ürdedir:
if (metadataJson is Map)
- Verilerin boş olmadığı (önceki kontrolde dolaylı olarak onaylanır).
Harita kalıbı kullanarak JSON değerlerini okuma
Yanlışlanabilir bir kalıpla, harita kalıbı kullanarak JSON'un beklenen yapıya sahip olduğunu doğrulayabilirsiniz.
metadata
'nin önceki 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, Dart 3'te kullanıma sunulan yeni bir tür if-ifadesi (if-case) görüyorsunuz. Destek kaydı metni yalnızca destek kaydı kalıbı _json
'teki verilerle eşleşirse yürütülür. Bu eşleşme, gelen JSON'u doğrulamak için metadata
işlevinin ilk sürümünde yazdığınız kontrolleri gerçekleştirir. Bu kod aşağıdakileri doğrular:
_json
bir harita türüdür._json
,metadata
anahtarı içeriyor._json
null değil._json['metadata']
de bir harita türüdür._json['metadata']
,title
vemodified
anahtarlarını içerir.title
velocalModified
dizedir ve null değildir.
Değer eşleşmezse desen reddedilir (yürütmeye devam etmeyi reddeder) ve else
yan tümcesine geçilir. Eşleşme başarılı olursa kalıp, haritadaki title
ve modified
değerlerinin yapısını bozar ve bunları yeni yerel değişkenlere bağlar.
Desenlerin tam listesi için özellik spesifikasyonunun Desenler bölümündeki tabloya bakın.
8. Uygulamayı daha fazla kalıba hazırlayın
Şimdiye kadar JSON verilerinin metadata
bölümünü ele aldınız. Bu adımda, blocks
listesindeki verileri işlemek ve uygulamanızda oluşturmak için iş mantığınızı biraz daha hassaslaştırırsınız.
{
"metadata": {
// ...
},
"blocks": [
{
"type": "h1",
"text": "Chapter 1"
},
// ...
]
}
Veri depolayan bir sınıf oluşturma
- JSON verilerindeki bloklardan birinin verilerini okumak ve depolamak için kullanılan
data.dart
sınıfınaBlock
adlı yeni bir sınıf 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');
}
}
}
Fabrika kurucusu fromJson()
, daha önce gördüğünüz harita deseniyle aynı if-case'i kullanır.
JSON verilerinin, checked
adlı ve kalıpta bulunmayan ek bir bilgi parçasına sahip olmasına rağmen beklenen kalıba benzediğini göreceksiniz. Bunun nedeni, bu tür kalıpları ("harita kalıpları" olarak adlandırılır) kullandığınızda yalnızca kalıpta tanımladığınız belirli şeyleri dikkate almaları ve verilerdeki diğer her şeyi yok saymalarıdır.
Engelleme nesnelerinin listesini döndürme
- Ardından,
Document
sınıfınagetBlocks()
adlı yeni bir işlev ekleyin.getBlocks()
, JSON'uBlock
sınıfının örneklerine ayı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 bir listesini döndürür. Bilinen bir if-case ifadesi doğrulama yapar ve blocks
meta verilerinin değerini blocksJson
adlı yeni bir List
değerine dönüştürür (desenler olmadan dönüştürmek için toList()
yöntemine ihtiyacınız vardır).
Liste değişmezi, yeni listeyi Block
nesneleriyle doldurmak için bir collection for içerir.
Bu bölümde, bu kod laboratuvarındaki denemediğiniz kalıplarla ilgili özellikler tanıtılmaz. Sonraki adımda, liste öğelerini kullanıcı arayüzünüzde oluşturmaya hazırlanırsınız.
9. Belgeyi göstermek için kalıpları kullanma
Artık bir if-case ifadesi ve çürütülebilir kalıplar kullanarak JSON verilerinizi başarıyla yapısını bozabilir ve yeniden oluşturabilirsiniz. Ancak if-case, kalıplarla birlikte gelen akış yapılarını kontrol etmeye yönelik geliştirmelerden yalnızca biridir. Şimdi, reddedilebilir kalıplarla ilgili bilginizi ifade değiştirme ifadelerine uygulayın.
Switch ifadeleri ile kalıpları kullanarak nelerin oluşturulacağını kontrol etme
main.dart
alanında, her bloğun stilinitype
alanına göre 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 case ifadesi sabit dize kalıbı kullanır.
block.type
, sabit değerh1
ile eşitse kalıp eşleşir. - İkinci durum ifadesi, alt kalıpları olarak iki sabit dize kalıbı içeren bir mantıksal-veya kalıbı kullanır.
block.type
,p
veyacheckbox
alt kalıplarından biriyle eşleşirse kalıp eşleşir.
- Son örnek ise
_
olan bir joker karakter kalıbıdır. Geçiş durumlarındaki joker karakterler diğer her şeyle eşleşir. Bunlar, switch ifadelerinde hâlâ izin verilendefault
yan tümceleriyle aynı şekilde çalışır (yalnızca biraz daha ayrıntılıdır).
Joker karakter kalıpları, bir kalıba izin verilen her yerde kullanılabilir (ör. değişken beyanı kalıbında): var (title, _) = document.metadata;
Bu bağlamda joker karakter herhangi bir değişkene bağlanmaz. İkinci alan atılır.
Sonraki bölümde, Block
nesnelerini görüntüledikten sonra daha fazla anahtar özelliği hakkında bilgi edineceksiniz.
Doküman içeriğini görüntüleme
DocumentScreen
widget'ının build
yönteminde getBlocks()
'ı çağırarak Block
nesnelerinin listesini içeren yerel bir değişken oluşturun.
DocumentationScreen
içindeki mevcutbuild
yöntemini şu 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 blok listesinde her öğe için bir BlockWidget
widget'ı oluşturur.
- Uygulamayı çalıştırdığınızda ekranda bloklar gösterilir:
10. Switch ifadelerini kullanma
Kalıplar, switch
ve case
'a birçok özellik ekler. Dart, bu ifadeleri daha fazla yerde kullanılabilir hale getirmek için switch ifadelerine sahiptir. Bir dizi durum, doğrudan bir değişken atamasına veya dönüş beyanına değer sağlayabilir.
switch ifadesini switch ifadesine dönüştürme
Dart analiz aracı, kodunuzda değişiklik yapmanıza yardımcı olmak için destekler sağlar.
- İmlecinizi önceki bölümdeki switch ifadesine getirin.
- Mevcut yardımları görüntülemek için ampul simgesini tıklayın.
- Dönüşüm ifadesi olarak dönüştür yardımını seçin.
Bu kodun yeni sürümü şu şekilde 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 ifadesine benzer ancak case
anahtar kelimesini kaldırır ve kalıbı case gövdesinden ayırmak için =>
kullanır. switch ifadeleri, switch ifadelerinin aksine bir değer döndürür ve ifadenin kullanılabileceği her yerde kullanılabilir.
11. Nesne kalıplarını kullanma
Dart, nesne yönelimli 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ı etkinleştirir ve nesne özelliklerini yapısını bozarsınız.
Nesne kalıplarından özellikleri ayıklama
Bu bölümde, son değiştirilme tarihinin nasıl gösterildiğini kalıplar kullanarak iyileştirirsiniz.
formatDate
yönteminimain.dart
'a 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, difference
değerini (Duration
nesnesi) açan bir anahtar ifadesi döndürür. today
ile JSON verilerindeki modified
değeri arasındaki süreyi temsil eder.
switch ifadesinin her bir durumu, nesnenin inDays
ve isNegative
özelliklerinde alıcıları çağırarak eşleşen bir nesne kalıbı kullanır. Söz dizimi, bir Duration nesnesi oluşturacak gibi görünse de aslında difference
nesnesinde bulunan alanlara erişiyor.
İlk üç durumda, inDays
nesne özelliğini eşleştirmek ve ilgili dizeyi döndürmek için sabit alt desenler 0
, 1
ve -1
kullanılır.
Son iki durum, bugün, dün ve yarın dışındaki süreleri ele alır:
isNegative
mülkü boole sabit kalıbıyla eşleşirse (değişiklik tarihi geçmişteyse) gün önce ifadesi gösterilir.true
- Bu durum farkı yakalamıyorsa süre pozitif bir gün sayısı olmalıdır (
isNegative: false
ile açıkça doğrulamanız gerekmez). Bu nedenle, değişiklik tarihi gelecektedir ve şu andan itibaren gün sayısı olarak gösterilir.
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österebilir:
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 koruyucu yan tümceler tanıtılmaktadır:
- Koruyucu yan tümce, bir durum deseninden sonra
when
anahtar kelimesini kullanır. - Bunlar; if-case, switch ifadeleri ve switch ifadelerinde kullanılabilir.
- Yalnızca eşleşmeden sonra bir kalıba koşul eklenir.
- Koruyucu yan tümce false olarak değerlendirilirse kalıbın tamamı reddedilir ve yürütme işlemi bir sonraki duruma geçer.
Yeni biçimlendirilmiş tarihi kullanıcı arayüzüne ekleme
- Son olarak,
DocumentScreen
işlevindekibuild
yönteminiformatDate
işlevini kullanacak şekilde 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 anında yeniden yükleme yapın:
12. Sınıfları kapsamlı geçiş için mühürleme
Son geçişin sonunda joker karakter veya varsayılan büyük/küçük harf kullanmadığınıza dikkat edin. Her zaman geçersiz olabilecek değerler için bir durum eklemek iyi bir uygulama olsa da, tanımladığınız durumların inDays
'nin olası tüm değerlerini hesaba kattığını bildiğiniz için bu gibi basit bir örnekte bunu yapmanıza gerek yoktur.
Bir anahtardaki her durum ele alındığında buna kapsamlı anahtar denir. Örneğin, true
ve false
için durumlar olduğunda bool
türünü etkinleştirmek kapsamlı bir işlemdir. Enum'ler sabit değerler için sabit bir sayı temsil ettiğinden, enum değerlerinin her biri için de durum olduğunda enum
türünü etkinleştirmek kapsamlı bir işlemdir.
Dart 3, yeni sınıf değiştirici sealed
ile kapsamlı kontrol özelliğini nesneler ve sınıf hiyerarşileri için genişletti. Block
sınıfınızı mühürlü bir üst sınıf olarak yeniden yapılandırın.
Alt sınıfları oluşturma
data.dart
içinde,Block
'i genişleten üç 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'daki farklı type
değerlerine ('h1'
, 'p'
ve 'checkbox'
) karşılık gelir.
Üst sınıfı mühürleme
Block
sınıfınısealed
olarak işaretleyin. Ardından, if-case ifadesini JSON'da belirtilentype
değerine karşılık gelen alt sınıfı döndüren bir switch ifadesi olarak yeniden yapılandırın:
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ştiricisidir. Yani bu sınıfı yalnızca aynı kitaplıkta genişletebilir veya uygulayabilirsiniz. Analizör bu sınıfın alt türlerini bildiğinden, bir anahtar bunlardan birini kapsamazsa ve kapsamlı değilse hata bildirir.
Widget'ları görüntülemek için bir switch ifadesi kullanın
main.dart
sınıfınımain.dart
içinde, her durum için nesne kalıplarını kullanan bir switch ifadesiyle güncelleyin:BlockWidget
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),
],
),
},
);
}
}
BlockWidget
işlevinin ilk sürümünde, TextStyle
döndürmek için bir Block
nesnesinin alanını etkinleştirdiniz. Ardından, Block
nesnesinin bir örneğini değiştirir ve alt sınıflarını temsil eden nesne kalıplarıyla eşleştirirsiniz. Bu süreçte nesnenin özelliklerini ayıklayabilirsiniz.
Dart analizörü, Block
sınıfını kapalı bir sınıf haline getirdiğiniz için her alt sınıfın switch ifadesinde işlenip işlenmediğini kontrol edebilir.
Ayrıca, burada bir switch ifadesi kullanmanız durumunda sonucu doğrudan child
öğesine iletebileceğinizi de unutmayın. Daha önce ayrı bir return ifadesi kullanmanız gerekiyordu.
- Onay kutusu JSON verilerinin ilk kez oluşturulduğunu görmek için sayfayı anında yeniden yükleyin:
13. Tebrikler
Kalıpları, kayıtları, gelişmiş switch ve case'i ve mühürlü sınıfları başarıyla denediniz. Çok fazla bilgi verdiniz ancak bu özelliklerin yüzeyini zar zor çizdiniz. Kalıplar hakkında daha fazla bilgi için özellik spesifikasyonuna bakın.
Farklı kalıp türleri, görünebilecekleri farklı bağlamlar ve alt kalıpların potansiyel olarak iç içe yerleştirilmesi, davranıştaki olasılıkları sonsuz hale getirir. Ancak bunları kolayca görebilirsiniz.
Flutter'da kalıpları kullanarak içerikleri göstermenin her türlü yolunu düşünebilirsiniz. Kalıpları kullanarak, kullanıcı arayüzünüzü birkaç kod satırı halinde oluşturmak için verileri güvenli bir şekilde ayıklayabilirsiniz.
Sırada ne var?
- Dart dokümanlarının Dil bölümündeki kalıplar, kayıtlar, gelişmiş switch ve cases ifadeleri ve sınıf değiştiricilerle ilgili belgelere göz atın.
Referans dokümanları
Örnek kodun tamamını adım adım flutter/codelabs
deposunda bulabilirsiniz.
Her yeni özelliğin ayrıntılı spesifikasyonları için orijinal tasarım dokümanlarına göz atın: