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

1. Giriş

logo_components_color_2x_web_96dp.png

Materyal Bileşenleri (MDC), geliştiricilerin Materyal Tasarım'ı uygulamasına yardımcı olur. Google'da mühendislerden ve kullanıcı deneyimi tasarımcılarından oluşan bir ekip tarafından oluşturulan MDC, onlarca güzel ve işlevsel kullanıcı arayüzü bileşeni içerir. Ayrıca Android, iOS, web ve Flutter.material.io/develop'da kullanılabilir.

MDC-101 codelab'inde bir giriş sayfası oluşturmak için iki Materyal Bileşeni kullandınız: metin alanları ve mürekkep dalgalı düğmeler. Şimdi gezinme, yapı ve veri ekleyerek bu temelin kapsamını genişletelim.

Oluşturacaklarınız

Bu codelab'de, giysi ve ev eşyaları satan bir e-ticaret uygulaması olan Shrine adlı uygulama için bir ana ekran oluşturacaksınız. Şunları içerecektir:

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

Android

iOS

Üst uygulama çubuğu ve ürünlerle dolu ızgaraya sahip e-ticaret uygulaması

Üst uygulama çubuğu ve ürünlerle dolu ızgaraya sahip e-ticaret uygulaması

Bu codelab'deki Material Flutter bileşenleri ve alt sistemleri

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

Flutter geliştirme ile ilgili deneyim düzeyinizi nasıl değerlendirirsiniz?

Acemi Orta Yeterli

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

Bu laboratuvarı tamamlamak için iki yazılıma ihtiyacınız vardır: Flutter SDK'sı ve düzenleyici.

Codelab'i aşağıdaki cihazlardan 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üklenmesini gerektirir).
  • Android Emülatör (Android Studio'da kurulum gerektirir).
  • Tarayıcı (hata ayıklama için Chrome gereklidir).
  • Windows, Linux veya macOS masaüstü uygulaması olarak Uygulamayı dağıtmayı planladığınız platformda gerçekleştirmeniz gerekir. Bu nedenle, bir Windows masaüstü uygulaması geliştirmek istiyorsanız uygun derleme zincirine erişmek için Windows'da geliştirme yapmanız gerekir. İşletim sistemine özgü gereksinimler docs.flutter.dev/desktop sayfasında ayrıntılı olarak açıklanmıştır.

3. codelab başlangıç uygulamasını indirme

MDC-101'den mi devam ediyorsunuz?

MDC-101 kursunu tamamladıysanız kodunuz bu codelab için hazırlanmış olmalıdır. Şu adıma atlayın: Üst uygulama çubuğu ekleme.

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

Codelab başlangıç uygulamasını indirin

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

...veya GitHub'dan klonlayın

Bu codelab'i GitHub'dan klonlamak için şu 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çın ve uygulamayı çalıştırın

  1. Projeyi istediğiniz düzenleyicide açın.
  2. "Uygulamayı çalıştırma" talimatlarını izleyin Başlarken: Seçtiğiniz düzenleyici için uygulamayı test edin.

Başarıyla gerçekleştirildi. Cihazınızda MDC-101 codelab'inde bulunan Tapınak giriş sayfası gösterilir.

Android

iOS

kullanıcı adı ve şifre alanları, iptal ve ileri düğmeleri bulunan giriş sayfası

kullanıcı adı ve şifre alanları, iptal ve ileri düğmeleri bulunan giriş sayfası

Artık giriş ekranı iyi göründüğüne göre uygulamaya bazı ürünler ekleyelim.

4. Üst uygulama çubuğu ekle

Hemen şimdi "Sonraki"yi tıklarsanız düğmesini tıkladığınızda, ana ekranda "You do it!" (Başardınız!) ifadesini görürsünüz. Harika! Ama artık kullanıcımızın herhangi bir işlem yapması veya uygulamanın hangi noktasında olduğunu bilmesi gerekmiyor. Yardımcı olmak için navigasyon eklemenin zamanı geldi.

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

Gezinme olanağı sunmak ve kullanıcıların diğer işlemlere hızlı erişmesini sağlamak için üst kısımda uygulama çubuğu ekleyelim.

AppBar widget'ı ekleme

home.dart ürününde, İskeleye bir AppBar ekleyin ve vurgulanan const işaretini kaldırın:

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

İskele'nin appBar: alanına AppBar'ı eklemek, AppBar'ın sayfanın üst kısmında, gövdenin de altında kalmasını sağlayarak bize ücretsiz olarak mükemmel bir düzen sağlar.

Metin widget'ı ekleme

home.dart uygulamasında 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ığında Tapınak olan uygulama çubuğu

Başlığında Tapınak olan uygulama çubuğu

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

Başa bir iconButton ekle

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 bunu title: alanının önüne koyun):

    // 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ığında Shrine ve hamburger menü simgesi olan bir uygulama barı

Başlığında Shrine ve hamburger menü simgesi olan bir uygulama barı

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

Başlığın son tarafına da düğmeler ekleyebilirsiniz. Flutter'da bunlara "eylemler" adı verilir.

İşlem ekleme

İki iconButtons için daha yer var.

Bunları başlıktan sonra 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 şu şekilde görünmelidir:

Android

iOS

Başlığında tapınak ve hamburger menü simgesi, arkasında arama ve özelleştirme simgeleri bulunan bir uygulama çubuğu

Başlığında tapınak ve hamburger menü simgesi, arkasında arama ve özelleştirme simgeleri bulunan bir uygulama çubuğu

Artık uygulamanın başında bir düğme, başlık ve sağ tarafta iki işlem var. Uygulama çubuğu, içerikten farklı bir katmanda olduğunu gösteren hafif bir gölge kullanarak yüksekliği de gösterir.

5. Izgaraya kart ekleme

Artık uygulamamızın bir yapısı var. Şimdi içerikleri kartlara yerleştirerek düzenleyelim.

GridView ekleme

Üst uygulama çubuğunun altına bir kart ekleyerek başlayalım. Card widget'ı tek başına yeterli bilgiye sahip olmadığı için onu bir GridView widget'ında göstermek istiyoruz.

Yapı İskelesinin gövdesindeki Merkezi bir 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()],
),

Kodu açalım. Gösterdiği öğelerin sayısı sonsuz değil, sayılabilir olduğundan GridView count() oluşturucusunu çağırır. Ancak düzenini tanımlamak için daha fazla bilgiye ihtiyacı vardır.

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

padding: alanı, GridView'un 4 tarafında da alan sağlar. Elbette, henüz yanlarında GridView alt öğesi olmadığından sondaki veya alt kenarlardaki dolguyu göremezsiniz.

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

Varsayılan olarak GridView, aynı boyutta bloklar oluşturur.

Bir kartımız var ama o kart boş. Kartımıza alt widget'ları ekleyelim.

İçerikleri düzenleme

Kartlarda resim, başlık ve ikincil metin için bölgeler bulunmalıdır.

GridView'un alt öğelerini güncelleyin:

// 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, "metni ön kenara hizala" anlamına gelen CrossAxisAlignment.start değerini belirtir.

AspectRatio widget'ı, sağlanan resmin türünden bağımsız olarak resmin hangi şekle sahip olacağını belirler.

Dolgu, metni kenardan biraz daha içe aktarır.

İki Text widget'ı, aralarında 8 nokta boşluk olacak şekilde dikey olarak üst üste dizilmiştir (SizedBox). Bunları Dolgu'nun içinde barındırmak 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 yuvarlatılmış köşeleri ve bir gölge (kartın yüksekliğini ifade eden) ile kenardan içe yerleştirildiğini görebilirsiniz. Şeklin tamamına "kapsayıcı" adı verilir Materyal. (Kapsayıcı adlı gerçek widget sınıfıyla karıştırılmamalıdır.)

Kartlar genellikle diğer kartlarla birlikte bir koleksiyonda gösterilir. Şimdi, bunları bir koleksiyon halinde bir ızgara üzerine yerleştirelim.

6. Kart koleksiyonu oluşturma

Bir ekranda birden fazla kart olduğunda, bunlar bir veya daha fazla koleksiyonda gruplanır. Bir koleksiyondaki kartlar aynı düzlemde yer alır, yani kartların alınma veya sürüklenmedikleri sürece aynı dinlenme yüksekliğine sahiptirler, ancak burada bunu yapmayacağız.

Kartı bir koleksiyon halinde çoğaltın

Şu anda Kartımız GridView'un children: alanında satır içinde oluşturuluyor. Bu iç içe yerleştirilmiş çok fazla sayıda kod olduğu için okunması zor olabilir. Bunu, istediğimiz sayıda boş kart oluşturabilen ve Kartlar listesi döndüren bir işleve çıkaralım.

build() işlevinin üzerinde yeni bir gizli işlev oluşturun (Alt çizgiyle başlayan işlevlerin gizli 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 yer alan 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 öğeler ızgarası

resim, başlık ve ikincil metin içeren öğeler ızgarası

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

Ürün verileri ekleme

Uygulamada resimler, adlar ve fiyatlar içeren bazı ürünler var. Bunu kartta bulunan widget'lara ekleyelim.

Ardından home.dart aracında, yeni bir paketi ve bir 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() değerini 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 derleme ve çalıştırılamaz. Bir değişikliğimiz daha var.

Ayrıca, derlemeyi denemeden önce build() işlevini, BuildContext değerini _buildGridCards() olarak 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ı çalışırken yeniden başlatın.

Android

iOS

Resim, ürün başlığı ve fiyatın yer aldığı öğeler ızgarası

Resim, ürün başlığı ve fiyatın yer aldığı öğeler ızgarası

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

Projenizi kaydedin.

Ürün verileri gösteriliyor ancak resimlerin etrafında fazladan boşluk var. Resimler varsayılan olarak .scaleDown değerine sahip bir BoxFit ile çizilir (bu örnekte). Bunu biraz yakınlaştırması ve fazla boşlukları kaldırması için .fitWidth olarak değiştirelim.

Resme BoxFit.fitWidth değerine sahip 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ın yer aldığı öğeler ızgarası

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

7. Tebrikler!

Uygulamamız, kullanıcıyı giriş ekranından ürünlerin görüntülenebileceği bir ana ekrana yönlendiren temel bir akışa sahip. Sadece birkaç satır kodla üst uygulama çubuğu (bir başlık ve üç düğmeli) ve kartlar (uygulamamızın içeriğini sunmak için) ekledik. Artık basit ve işlevsel olan ana ekranımız, temel bir yapı ve üzerinde işlem yapılabilir içerik içeriyor.

Sonraki adımlar

Üst uygulama çubuğu, kart, metin alanı ve düğmeyle birlikte Material Flutter kitaplığından dört temel bileşeni kullanıyoruz. Malzeme bileşenleri widget kataloğunu ziyaret ederek daha fazlasını keşfedebilirsiniz.

Uygulamamız tam olarak işlevsel olsa da henüz belirli bir markayı veya bakış açısını yansıtmıyor. MDC-103: Renk, Şekil, Yükseklik ve Tür ile Materyal Tasarım Teması bölümünde canlı ve modern bir markayı ifade etmek için bu bileşenlerin stilini özelleştireceğiz.

Bu codelab'i makul bir zaman ve çabayla tamamlayabildim

Kesinlikle katılıyorum Katılıyorum Ne memnunum ne değilim Katılmıyorum Kesinlikle katılmıyorum

Gelecekte Materyal Bileşenleri kullanmaya devam etmek istiyorum

Kesinlikle katılıyorum Katılıyorum Ne memnunum ne değilim Katılmıyorum Kesinlikle katılmıyorum