Ders İçeriği
Kullanıcıların uygulamanızla etkileşim kurmasını sağlamak, mobil uygulama geliştirmenin temel bir parçasıdır. Flutter, çeşitli widget'lar ve mekanizmalar aracılığıyla kullanıcı etkileşimini kolaylaştırır.
4.1. Gesture Dedektörleri
Flutter'da, dokunma, sürükleme, uzun basma gibi kullanıcı hareketlerini (jestlerini) algılamak için GestureDetector widget'ı kullanılır. Bu widget, herhangi bir widget'ı dokunulabilir hale getirebilir ve çeşitli jestlere yanıt vermesini sağlayabilir.
import 'package:flutter/material.h';
class GestureDetectorExample extends StatelessWidget {
const GestureDetectorExample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
onTap: () {
print('Kutuya tıklandı!');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Kutuya tıklandı!')),
);
},
onDoubleTap: () {
print('Kutuya çift tıklandı!');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Kutuya çift tıklandı!')),
);
},
onLongPress: () {
print('Kutuya uzun basıldı!');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Kutuya uzun basıldı!')),
);
},
child: Container(
padding: EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: Colors.lightBlueAccent,
borderRadius: BorderRadius.circular(8.0),
),
child: Text('Bana Dokun!', style: TextStyle(fontSize: 20)),
),
),
);
}
}
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('GestureDetector Örneği')),
body: GestureDetectorExample(),
),
));
}
GestureDetector'ın sık kullanılan özellikleri:
•onTap: Widget'a tıklandığında tetiklenir.
•onDoubleTap: Widget'a çift tıklandığında tetiklenir.
•onLongPress: Widget'a uzun basıldığında tetiklenir.
•onPanUpdate: Widget sürüklenirken tetiklenir.
•onVerticalDragUpdate, onHorizontalDragUpdate: Dikey veya yatay sürüklemelerde tetiklenir.
4.2. TextField ve Form İşlemleri
Kullanıcılardan metin girişi almak için TextField widget'ı kullanılır. Formlar, birden fazla giriş alanını yönetmek ve doğrulamak için kullanılır.
TextField Kullanımı
TextField, kullanıcıdan tek satırlık metin girişi almak için en yaygın kullanılan widget'tır. Bir TextEditingController kullanarak TextField'ın değerini kontrol edebilir ve alabilirsiniz.
import 'package:flutter/material.dart';
class TextFieldExample extends StatefulWidget {
const TextFieldExample({Key? key}) : super(key: key);
@override
State<TextFieldExample> createState() => _TextFieldExampleState();
}
class _TextFieldExampleState extends State<TextFieldExample> {
final TextEditingController _textController = TextEditingController();
String _enteredText = '';
@override
void dispose() {
_textController.dispose(); // Controller'ı dispose etmeyi unutmayın!
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
TextField(
controller: _textController,
decoration: InputDecoration(
labelText: 'Adınızı Girin',
hintText: 'Örn: Ali Can',
border: OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
_textController.clear();
setState(() {
_enteredText = '';
});
},
),
),
onChanged: (value) {
setState(() {
_enteredText = value;
});
},
onSubmitted: (value) {
print('Gönderilen Metin: $value');
},
),
SizedBox(height: 20),
Text('Girilen Metin: $_enteredText'),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
setState(() {
_enteredText = _textController.text;
});
print('Buton ile alınan metin: ${_textController.text}');
},
child: Text('Metni Al'),
),
],
),
);
}
}
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('TextField Örneği')),
body: TextFieldExample(),
),
));
}
TextField'ın bazı önemli özellikleri:
•controller: TextEditingController ile metin alanının değerini programatik olarak kontrol etmenizi sağlar.
•decoration: InputDecoration ile metin alanının görünümünü (etiket, ipucu metni, kenarlık, ikonlar vb.) özelleştirmenizi sağlar.
•onChanged: Metin alanı her değiştiğinde tetiklenir.
•onSubmitted: Kullanıcı klavyeden
Enter tuşuna bastığında veya klavyedeki onay düğmesine dokunduğunda tetiklenir.
•keyboardType: Klavyenin tipini belirler (örneğin, TextInputType.number sayısal giriş için).
•obscureText: Metni gizler (şifre alanları için).
Form İşlemleri ve Doğrulama
Birden fazla TextField veya diğer giriş widget'larını içeren formları yönetmek için Form widget'ı kullanılır. Form widget'ı, formun durumunu yönetmek ve girişleri doğrulamak için bir GlobalKey<FormState> ile birlikte kullanılır.
import 'package:flutter/material.dart';
class FormExample extends StatefulWidget {
const FormExample({Key? key}) : super(key: key);
@override
State<FormExample> createState() => _FormExampleState();
}
class _FormExampleState extends State<FormExample> {
final _formKey = GlobalKey<FormState>(); // Formun durumunu yönetmek için anahtar
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
super.dispose();
}
void _submitForm() {
if (_formKey.currentState!.validate()) {
// Form geçerliyse, verileri işleyin
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Form Gönderiliyor...')),
);
print('Ad: ${_nameController.text}');
print('E-posta: ${_emailController.text}');
// Genellikle burada veriler bir API'ye gönderilir veya kaydedilir.
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Lütfen hataları düzeltin.')),
);
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey, // Form anahtarını atayın
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: _nameController,
decoration: InputDecoration(
labelText: 'Adınız',
hintText: 'Adınızı girin',
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Lütfen adınızı girin';
}
return null;
},
),
SizedBox(height: 20),
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'E-posta',
hintText: 'email@example.com',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Lütfen e-posta adresinizi girin';
}
if (!value.contains('@')) {
return 'Geçerli bir e-posta adresi girin';
}
return null;
},
),
SizedBox(height: 20),
Center(
child: ElevatedButton(
onPressed: _submitForm,
child: Text('Gönder'),
),
),
],
),
),
);
}
}
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Form Örneği')),
body: FormExample(),
),
));
}
TextFormField widget'ı, TextField'ın bir Form içinde kullanılmak üzere tasarlanmış halidir. En önemli özelliği validator özelliğidir. validator bir fonksiyon alır ve bu fonksiyon, girişin geçerli olup olmadığını kontrol eder. Eğer giriş geçerli değilse bir hata mesajı döndürür, geçerliyse null döndürür.
_formKey.currentState!.validate() metodu çağrıldığında, formdaki tüm TextFormField'ların validator fonksiyonları çalıştırılır. Eğer herhangi bir validator hata mesajı döndürürse, validate() metodu false döner ve hata mesajları ilgili TextFormField'ların altında görünür.
4.3. Basit Durum Yönetimi (setState)
Flutter'da bir widget'ın kullanıcı arayüzünü güncellemek için en temel yöntem setState() metodunu kullanmaktır. setState() metodu, bir StatefulWidget'ın State sınıfında tanımlanır ve çağrıldığında Flutter'a widget'ın durumunun değiştiğini ve yeniden çizilmesi gerektiğini bildirir.
Bir StatefulWidget'ın build metodu, widget'ın mevcut durumuna göre kullanıcı arayüzünü oluşturur. setState() çağrıldığında, Flutter build metodunu tekrar çalıştırır ve ekranı günceller. Bu, özellikle küçük ve orta ölçekli uygulamalarda durum yönetimi için oldukça etkilidir.
import 'package:flutter/material.dart';
class CounterApp extends StatefulWidget {
const CounterApp({Key? key}) : super(key: key);
@override
State<CounterApp> createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int _counter = 0; // Uygulamanın durumu
void _incrementCounter() {
// Durumu güncelleyen metod
setState(() {
_counter++; // Durumu artır
});
print('Sayaç değeri: $_counter');
}
void _decrementCounter() {
setState(() {
_counter--; // Durumu azalt
});
print('Sayaç değeri: $_counter');
}
@override
Widget build(BuildContext context) {
// Durum değiştikçe bu metod yeniden çalışır
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Mevcut Sayaç Değeri:',
style: TextStyle(fontSize: 20),
),
Text(
'$_counter', // Durum değerini göster
style: Theme.of(context).textTheme.headlineLarge,
),
SizedBox(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _decrementCounter,
child: Icon(Icons.remove),
),
SizedBox(width: 20),
ElevatedButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
],
),
],
),
);
}
}
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Basit Durum Yönetimi (setState)')),
body: CounterApp(),
),
));
}
Yukarıdaki örnekte:
1._counter değişkeni, widget'ın durumunu tutar.
2._incrementCounter ve _decrementCounter metodları, setState() çağrısı içinde _counter değişkenini günceller.
3.setState() çağrıldığında, Flutter _CounterAppState sınıfının build metodunu yeniden çalıştırır.
4.build metodu yeniden çalıştığında, Text('$_counter') widget'ı güncel _counter değerini kullanarak ekranda yeni sayıyı gösterir.
setState Kullanımında Dikkat Edilmesi Gerekenler:
•setState sadece StatefulWidget'ın State sınıfında kullanılabilir.
•Durumu değiştiren tüm kodlar setState(() { ... }); bloğunun içinde olmalıdır. Aksi takdirde, durum değişse bile Flutter widget'ı yeniden çizmez ve ekranda bir güncelleme görmezsiniz.
•Büyük ve karmaşık uygulamalarda setState her zaman en verimli çözüm olmayabilir. Uygulama büyüdükçe, daha gelişmiş durum yönetimi çözümlerine (Provider, BLoC, Riverpod vb.) ihtiyaç duyulabilir. Ancak temel düzeyde setState kavramını anlamak, Flutter'daki durum yönetiminin temelini oluşturur.
Bu bölümle birlikte temel seviye Flutter derslerini tamamlamış bulunmaktayız. Artık Flutter'ın temel yapı taşlarını, Dart dilinin esaslarını ve basit kullanıcı etkileşimlerini nasıl yöneteceğinizi biliyorsunuz. Bir sonraki bölümde orta seviye konulara geçeceğiz.