MDC-102 Flutter: Malzeme Yapısı ve Düzen

1. Giriş

logo_components_color_2x_web_96dp.png

Material Components (MDC), geliştiricilerin Materyal Tasarım'ı uygulamasına yardımcı olur. Google'daki bir mühendis ve kullanıcı deneyimi tasarımcısı ekibi tarafından oluşturulan MDC, düzinelerce güzel ve işlevsel kullanıcı arayüzü bileşeni içerir. Android, iOS, web ve Flutter.material.io/develop için kullanılabilir.

MDC-101 adlı codelab'de, giriş sayfası oluşturmak için iki Material Components kullandınız: mürekkep dalgalanmaları olan metin alanları ve düğmeler. Şimdi de gezinme, yapı ve veri ekleyerek bu temeli genişletelim.

Ne oluşturacaksınız?

Bu codelab'de, giyim ve ev eşyaları satan bir e-ticaret uygulaması olan Shrine adlı uygulama için bir ana ekran oluşturacaksınız. Bu kartta şu bilgiler yer alır:

  • Üst uygulama çubuğu
  • Ürünlerle dolu bir ızgara listesi

Android

iOS

Üst uygulama çubuğu ve ürünlerle dolu bir ızgara içeren e-ticaret uygulaması

Üst uygulama çubuğu ve ürünlerle dolu bir ızgara içeren e-ticaret uygulaması

Bu kod laboratuvarındaki Material Flutter bileşenleri ve alt sistemleri

  • Üst uygulama çubuğu
  • Izgaralar
  • Kartlar

Flutter geliştirme deneyiminizi nasıl değerlendirirsiniz?

Başlangıç Orta İleri

2. Flutter geliştirme ortamınızı kurma

Bu laboratuvarı tamamlamak için iki yazılım gerekir: Flutter SDK ve bir düzenleyici.

Codelab'i aşağıdaki cihazlardan herhangi birini kullanarak çalıştırabilirsiniz:

  • Bilgisayarınıza bağlı ve Geliştirici moduna ayarlanmış fiziksel bir Android veya iOS cihaz.
  • iOS simülatörü (Xcode araçlarının yüklenmesi gerekir).
  • Android Emulator (Android Studio'da kurulum gerektirir).
  • Tarayıcı (hata ayıklama için Chrome gereklidir).
  • Windows, Linux veya macOS masaüstü uygulaması olarak. Dağıtmayı planladığınız platformda geliştirme yapmanız gerekir. Bu nedenle, bir Windows masaüstü uygulaması geliştirmek istiyorsanız uygun derleme zincirine erişmek için Windows'ta geliştirme yapmanız gerekir. docs.flutter.dev/desktop adresinde ayrıntılı olarak ele alınan işletim sistemine özgü gereksinimler vardır.

3. Codelab başlangıç uygulamasını indirin

MDC-101'den devam mı ediyorsunuz?

MDC-101'i tamamladıysanız kodunuz bu codelab'e hazır olmalıdır. Üst uygulama çubuğu ekleme adımına gidin.

Sıfırdan mı başlıyorsunuz?

Başlangıç codelab uygulamasını indirin

Başlangıç uygulaması material-components-flutter-codelabs-102-starter_and_101-complete/mdc_100_series dizininde bulunur.

...veya GitHub'dan kopyalayın

Bu codelab'i GitHub'dan klonlamak için aşağıdaki komutları çalıştırın:

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs/mdc_100_series
git checkout 102-starter_and_101-complete

Projeyi açıp uygulamayı çalıştırın.

  1. Projeyi tercih ettiğiniz düzenleyicide açın.
  2. Seçtiğiniz düzenleyici için Başlarken: Test sürüşü bölümündeki "Uygulamayı çalıştırma" talimatlarını uygulayın.

Başarılı aktarım Cihazınızda MDC-101 kod laboratuvarındaki Shrine giriş sayfasını görmeniz gerekir.

Android

iOS

Kullanıcı adı ve şifre alanları, iptal ve sonraki düğmeleri içeren giriş sayfası

Kullanıcı adı ve şifre alanları, iptal ve sonraki düğmeleri içeren giriş sayfası

Giriş ekranı artık iyi göründüğüne göre uygulamayı bazı ürünlerle dolduralım.

4. Üst uygulama çubuğu ekleme

Şu anda "Sonraki" düğmesini tıkladığınızda "Başardınız!" yazan ana ekranı görebilirsiniz. Harika! Ancak kullanıcımız artık yapacak bir işlem veya uygulamada nerede olduğunu bilmiyor. Yardımcı olmak için navigasyon eklemenin zamanı geldi.

Materyal Tasarım, yüksek düzeyde kullanılabilirlik sağlayan gezinme kalıpları sunar. En görünür bileşenlerden biri üst uygulama çubuğudur.

Gezinme sağlamak ve kullanıcılara diğer işlemlere hızlı erişim imkanı vermek için üst uygulama çubuğu ekleyelim.

AppBar widget'ı ekleme

home.dart içinde, Scaffold'a bir AppBar ekleyin ve vurgulanan const öğesini kaldırın:

return const Scaffold(
  // TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
  ),

Scaffold'un appBar: alanına AppBar eklemek, AppBar'ı sayfanın en üstünde ve gövdeyi altında tutarak ücretsiz olarak mükemmel bir düzen elde etmemizi sağlar.

Metin widget'ı ekleme

home.dart içinde AppBar'a başlık ekleyin:

// TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
    title: const Text('SHRINE'),
    // TODO: Add trailing buttons (102)

Projenizi kaydedin.

Android

iOS

Başlığı Shrine olan bir uygulama çubuğu

Başlığı Shrine olan bir uygulama çubuğu

Birçok uygulama çubuğunda başlığın yanında bir düğme bulunur. Uygulamamıza bir menü simgesi ekleyelim.

Önde bir IconButton ekleme

Hâlâ home.dart içindeyken AppBar'ın leading: alanı için bir IconButton ayarlayın. (Baştan sona doğru sıralamayı taklit etmek için title: alanından önce yerleştirin):

    // TODO: Add buttons and title (102)
    leading: IconButton(
      icon: const Icon(
        Icons.menu,
        semanticLabel: 'menu',
      ),
      onPressed: () {
        print('Menu button');
      },
    ),

Projenizi kaydedin.

Android

iOS

Başlık olarak Shrine'ın ve hamburger menü simgesinin bulunduğu bir uygulama çubuğu

Başlığı Shrine olan ve hamburger menü simgesi içeren bir uygulama çubuğu

Menü simgesi ("hamburger" olarak da bilinir) tam olarak beklediğiniz yerde gösterilir.

Ayrıca başlığın sonuna da düğme ekleyebilirsiniz. Flutter'da bunlara "işlemler" adı verilir.

İşlem ekleme

İki tane daha IconButton eklenebilir.

Başlıktan sonra bunları AppBar örneğine ekleyin:

// TODO: Add trailing buttons (102)
actions: <Widget>[
  IconButton(
    icon: const Icon(
      Icons.search,
      semanticLabel: 'search',
    ),
    onPressed: () {
      print('Search button');
    },
  ),
  IconButton(
    icon: const Icon(
      Icons.tune,
      semanticLabel: 'filter',
    ),
    onPressed: () {
      print('Filter button');
    },
  ),
],

Projenizi kaydedin. Ana ekranınız aşağıdaki gibi görünmelidir:

Android

iOS

Başlığı Shrine olan ve hamburger menü simgesi ile sonda arama ve özelleştirme simgeleri bulunan bir uygulama çubuğu

Başlığı Shrine olan ve hamburger menü simgesi ile sonda arama ve özelleştirme simgeleri bulunan bir uygulama çubuğu

Uygulamada artık birincil düğme, başlık ve sağ tarafta iki işlem var. Uygulama çubuğu, içerikten farklı bir katmanda olduğunu gösteren ince bir gölge kullanarak yükseltmeyi de gösterir.

5. Tabloya kart ekleme

Uygulamamızın yapısı oluştuğuna göre içeriği kartlara yerleştirerek düzenleyelim.

GridView ekleme

Üst uygulama çubuğunun altına bir kart ekleyerek başlayalım. Card widget'ı tek başına, kendisini görebileceğimiz bir yere yerleştirmek için yeterli bilgiye sahip değildir. Bu nedenle, widget'ı GridView widget'ı içine yerleştirmemiz gerekir.

İskele gövdesindeki Center widget'ını GridView ile değiştirin:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  // TODO: Build a grid of cards (102)
  children: <Widget>[Card()],
),

Şimdi bu kodu inceleyelim. GridView, görüntülediği öğelerin sayısı sayılabilir ve sonsuz olmadığından count() oluşturucusunu çağırır. Ancak düzenini tanımlamak için daha fazla bilgiye ihtiyacı var.

crossAxisCount:, kaç öğe olduğunu belirtir. 2 sütun istiyoruz.

padding: alanı, GridView'un 4 tarafında da boşluk sağlar. Elbette, henüz yanlarında GridView alt öğeleri olmadığı için sondaki veya alttaki taraflarda dolguyu göremezsiniz.

childAspectRatio: alanı, öğelerin boyutunu en boy oranına (genişlik/yükseklik) göre tanımlar.

GridView, varsayılan olarak tümü aynı boyutta olan kutular oluşturur.

Bir kartımız var ancak boş. Kartımıza çocuk widget'ları ekleyelim.

İçerikleri düzenleme

Kartlarda resim, başlık ve ikincil metin bölgeleri olmalıdır.

GridView'un alt öğelerini güncelleme:

// TODO: Build a grid of cards (102)
children: <Widget>[
  Card(
    clipBehavior: Clip.antiAlias,
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        AspectRatio(
          aspectRatio: 18.0 / 11.0,
          child: Image.asset('assets/diamond.png'),
        ),
        Padding(
          padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text('Title'),
              const SizedBox(height: 8.0),
              Text('Secondary Text'),
            ],
          ),
        ),
      ],
    ),
  )
],

Bu kod, alt widget'ları dikey olarak yerleştirmek için kullanılan bir Sütun widget'ı ekler.

crossAxisAlignment: field, CrossAxisAlignment.start değerini belirtir. Bu değer, "metni başlangıç kenarına hizala" anlamına gelir.

AspectRatio widget'ı, sağlanan resmin türü ne olursa olsun resmin şekline karar verir.

Dolgu, metni kenardan biraz içeriye getirir.

İki Text widget'ı, aralarında 8 puan boşluk (SizedBox) olacak şekilde dikey olarak yerleştirilir. Bu öğeleri dolgunun içine yerleştirmek için başka bir sütun oluştururuz.

Projenizi kaydedin.

Android

iOS

Resim, başlık ve ikincil metin içeren tek bir öğe

Resim, başlık ve ikincil metin içeren tek bir öğe

Bu önizlemede, kartın kenardan girintili, yuvarlak köşeli ve gölgeli (kartın yüksekliğini ifade eden) olduğunu görebilirsiniz. Şeklin tamamına Material'da "kapsayıcı" adı verilir. (Container adlı gerçek widget sınıfıyla karıştırılmamalıdır.)

Kartlar genellikle diğer kartlarla birlikte bir koleksiyonda gösterilir. Bunları ızgarada koleksiyon olarak düzenleyelim.

6. Kart koleksiyonu oluşturma

Bir ekranda birden fazla kart bulunduğunda bunlar bir veya daha fazla koleksiyonda gruplandırılır. Bir koleksiyondaki kartlar eş düzlemlidir. Yani kartlar, aynı dinlenme yüksekliğini paylaşır (kartlar alınmadığı veya sürüklenmediği sürece, ancak burada bu işlemi yapmayacağız).

Kartı koleksiyona kopyalama

Şu anda kartımız, GridView'un children: alanının satır içi olarak oluşturuluyor. Bu, okunması zor olabilecek çok sayıda iç içe yerleştirilmiş kod demektir. Bu kodu, istediğimiz kadar boş kart oluşturabilen ve Kart listesi döndüren bir işlev olarak çıkaralım.

build() işlevinin üzerinde yeni bir özel işlev oluşturun (alt çizgiyle başlayan işlevlerin özel API olduğunu unutmayın):

// TODO: Make a collection of cards (102)
List<Card> _buildGridCards(int count) {
  List<Card> cards = List.generate(
    count,
    (int index) {
      return Card(
        clipBehavior: Clip.antiAlias,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            AspectRatio(
              aspectRatio: 18.0 / 11.0,
              child: Image.asset('assets/diamond.png'),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: const <Widget>[
                  Text('Title'),
                  SizedBox(height: 8.0),
                  Text('Secondary Text'),
                ],
              ),
            ),
          ],
        ),
      );
    },
  );
  return cards;
}

Oluşturulan kartları GridView'un children alanına atayın. GridView'da bulunan her şeyi bu yeni kodla değiştirmeyi unutmayın:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(10) // Replace
),

Projenizi kaydedin.

Android

iOS

Resim, başlık ve ikincil metin içeren öğe ızgarası

Resim, başlık ve ikincil metin içeren öğe ızgarası

Kartlar görünür ancak henüz hiçbir şey göstermez. Şimdi ürün verilerini ekleme zamanı.

Ürün verileri ekleme

Uygulamada resim, ad ve fiyat bilgileri içeren bazı ürünler var. Bunu, kartta bulunan widget'lara ekleyelim.

Ardından, home.dart içinde yeni bir paket ve veri modeli için sağladığımız bazı dosyaları içe aktarın:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import 'model/product.dart';
import 'model/products_repository.dart';

Son olarak, ürün bilgilerini getirmek için _buildGridCards() simgesini değiştirin ve bu verileri kartlarda kullanın:

// TODO: Make a collection of cards (102)

// Replace this entire method
List<Card> _buildGridCards(BuildContext context) {
  List<Product> products = ProductsRepository.loadProducts(Category.all);

  if (products.isEmpty) {
    return const <Card>[];
  }

  final ThemeData theme = Theme.of(context);
  final NumberFormat formatter = NumberFormat.simpleCurrency(
      locale: Localizations.localeOf(context).toString());

  return products.map((product) {
    return Card(
      clipBehavior: Clip.antiAlias,
      // TODO: Adjust card heights (103)
      child: Column(
        // TODO: Center items on the card (103)
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          AspectRatio(
            aspectRatio: 18 / 11,
            child: Image.asset(
              product.assetName,
              package: product.assetPackage,
             // TODO: Adjust the box size (102)
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
               // TODO: Align labels to the bottom and center (103)
               crossAxisAlignment: CrossAxisAlignment.start,
                // TODO: Change innermost Column (103)
                children: <Widget>[
                 // TODO: Handle overflowing labels (103)
                 Text(
                    product.name,
                    style: theme.textTheme.titleLarge,
                    maxLines: 1,
                  ),
                  const SizedBox(height: 8.0),
                  Text(
                    formatter.format(product.price),
                    style: theme.textTheme.titleSmall,
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }).toList();
}

NOT: Henüz derlenip çalıştırılamaz. Bir değişiklik daha yapıyoruz.

Ayrıca, derlemeyi denemeden önce build() işlevini BuildContext'i _buildGridCards()'ye iletecek şekilde değiştirin:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(context) // Changed code
),

Uygulamayı hızlıca yeniden başlatın.

Android

iOS

Resim, ürün başlığı ve fiyat içeren bir öğe ızgarası

Resim, ürün başlığı ve fiyat içeren bir öğe ızgarası

Kartlar arasına dikey boşluk eklemediğimizi fark edebilirsiniz. Bunun nedeni, varsayılan olarak üst ve alt kısımlarında 4 puanlık kenar boşluğu olmasıdır.

Projenizi kaydedin.

Ürün verileri gösteriliyor ancak resimlerin etrafında fazladan boşluk var. Resimler varsayılan olarak .scaleDown BoxFit ile çizilir (bu örnekte). Bunu .fitWidth olarak değiştirelim. Böylece biraz yakınlaştırma yapılır ve fazladan boşluk kaldırılır.

Resme değeri BoxFit.fitWidth olan bir fit: alanı ekleyin:

  // TODO: Adjust the box size (102)
  fit: BoxFit.fitWidth,

Android

iOS

Kırpılmış resim, ürün başlığı ve fiyat içeren bir öğe ızgarası

Ürünlerimiz artık uygulamada mükemmel bir şekilde gösteriliyor.

7. Tebrikler!

Uygulamamızda, kullanıcıyı giriş ekranından ürünlerin görüntülenebildiği ana ekrana yönlendiren temel bir akış var. Yalnızca birkaç satır kodla üst uygulama çubuğu (başlık ve üç düğmeyle) ve kartlar (uygulamamızın içeriğini sunmak için) ekledik. Ana ekranımız artık basit ve işlevsel olup temel bir yapıya ve üzerinde işlem yapılabilecek içeriklere sahip.

Sonraki adımlar

Üst uygulama çubuğu, kart, metin alanı ve düğme ile Material Flutter kitaplığındaki dört temel bileşeni kullanmış olduk. Material Components Widget Kataloğu'nu ziyaret ederek daha fazla bilgi edinebilirsiniz.

Uygulamamız tam olarak işlevsel olsa da henüz belirli bir markayı veya bakış açısını ifade etmiyor. MDC-103: Materyal Tasarım Renk, Şekil, Yükseklik ve Tür ile Temalandırma (MDC-103: Renk, Şekil, Yükseklik ve Tür ile Materyal Tasarım Temalandırma) başlıklı dokümanda, bu bileşenlerin stilini canlı ve modern bir markayı ifade edecek şekilde özelleştireceğiz.

Bu codelab'i makul bir süre ve çabayla tamamlayabildim.

Kesinlikle katılıyorum Katılıyorum Ne katılıyorum ne katılmıyorum Katılmıyorum Kesinlikle katılmıyorum

Gelecekte Material Components'ı kullanmaya devam etmek istiyorum

Kesinlikle katılıyorum Katılıyorum Ne katılıyorum ne katılmıyorum Katılmıyorum Kesinlikle katılmıyorum