Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
Dizi · 42/61 Flutter Türkçe Tutorial
- Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
- Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
- Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
- Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
- Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
- Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
- Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
- Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
- Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
- Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
- Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
- Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
- Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
- Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
- Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
- Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
- Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
- Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
- Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
- Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
- Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
- Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
- Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
- Bölüm 6 — Konu 24: Provider Paketi
- Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
- Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
- Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
- Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
- Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
- Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
- Bölüm 7 — Konu 31: Deep Linking
- Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
- Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
- Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
- Bölüm 8 — Konu 35: Implicit Animasyonlar
- Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
- Bölüm 8 — Konu 37: Hero Animasyonları
- Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
- Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
- Bölüm 9 — Konu 40: Platform Channels
- Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
- Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
- Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
- Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
- Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
- Bölüm 10 — Konu 46: CI/CD
- Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
- Bölüm 10 — Konu 48: DevTools Profiling
- Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
- Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
- Bölüm 11 — Konu 51: Supabase Alternatifi
- Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
- Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
- Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
- Bölüm 12 — Konu 55: Flutter Web / Desktop
- Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
- Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
- Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
- Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
- Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
- Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
İçindekiler 8 başlık
Konu 41'de öğrendiğimiz izin yönetimi, bu dersteki her özelliğin ön koşuludur — kamera, konum ya da sensör verisine erişmeden önce, her zaman ilgili izni kontrol/istemen gerekecek. Bu derste üç yaygın donanım erişimini, hazır paketlerle nasıl kullanacağını göreceğiz.
Kamera — image_picker ve camera
Kamerayla çalışmanın iki farklı seviyesi var, ihtiyacına göre seçersin:
Basit Kullanım — image_picker
Sadece kullanıcının bir fotoğraf çekmesini ya da galeriden seçmesini istiyorsan, kendi kamera arayüzünü yazmana gerek yok:
flutter pub add image_pickerimport 'package:image_picker/image_picker.dart';
Future<void> fotografCek() async {
final picker = ImagePicker();
final XFile? fotograf = await picker.pickImage(
source: ImageSource.camera, // veya ImageSource.gallery
maxWidth: 1024, // büyük dosyaları küçültür
imageQuality: 85, // 0-100 arası sıkıştırma
);
if (fotograf != null) {
setState(() {
_secilenDosya = File(fotograf.path); // dart:io — Dart Bölüm 13'ü hatırla
});
}
}ImagePicker, cihazın kendi native kamera uygulamasını (Android'in kamera app'i, iOS'un kamera app'i) açar — sen kendi kamera arayüzünü yazmıyorsun, sistemin hazır olanını kullanıyorsun. XFile?, Dart Bölüm 2'de öğrendiğimiz nullable tip — kullanıcı iptal ederse null döner, bu yüzden if (fotograf != null) kontrolü zorunludur.
İleri Kullanım — camera Paketi
Kendi özelleştirilmiş kamera ekranını yapmak istiyorsan (örneğin bir Instagram-tarzı kayıt ekranı, canlı filtre önizlemesi), camera paketi doğrudan kamera akışına erişim verir:
flutter pub add cameraFuture<void> kameraBaslat() async {
final kameralar = await availableCameras(); // cihazdaki tüm kameraları listele
final controller = CameraController(
kameralar.first, // genelde arka kamera
ResolutionPreset.medium,
);
await controller.initialize();
// artık controller ile CameraPreview widget'ı gösterilebilir
}CameraPreview(controller) // canlı kamera görüntüsünü widget olarak gösterNe zaman hangisini seçersin? Basit bir "profil fotoğrafı çek" özelliği için image_picker fazlasıyla yeterli ve daha az kod gerektirir. Kendi kamera arayüzünü tasarlaman, canlı önizleme üzerinde işlem yapman gerekiyorsa camera paketine geçersin — bu, Bölüm 6 Konu 28'de Provider/Riverpod/BLoC karşılaştırmasında gördüğümüz "ihtiyaca göre araç seçimi" mantığının aynısı.
Konum — geolocator
flutter pub add geolocatorimport 'package:geolocator/geolocator.dart';
Future<Position?> konumAl() async {
// 1. Konum servisi (GPS) açık mı?
final servisAcikMi = await Geolocator.isLocationServiceEnabled();
if (!servisAcikMi) {
print('Kullanıcının GPS\'i kapalı');
return null;
}
// 2. İzin durumu (Konu 41'i hatırla — geolocator kendi izin API'sini sunar)
LocationPermission izin = await Geolocator.checkPermission();
if (izin == LocationPermission.denied) {
izin = await Geolocator.requestPermission();
if (izin == LocationPermission.denied) {
return null;
}
}
if (izin == LocationPermission.deniedForever) {
return null; // Konu 41'deki permanentlyDenied ile aynı fikir
}
// 3. Artık konumu güvenle alabiliriz
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
}Dikkat et: geolocator, kendi izin API'sini (LocationPermission enum'u) sunuyor — bunun Konu 41'deki permission_handler'ın PermissionStatus'una kavramsal olarak birebir paralel olduğunu görüyorsun (denied/deniedForever, Konu 41'deki denied/permanentlyDenied'a karşılık geliyor). Pratikte genelde ikisinden birini tutarlı şekilde kullanırsın — geolocator'ın kendi izin sistemi, konum için tek başına yeterlidir, permission_handler'ı ayrıca eklemene gerek kalmaz.
Tek seferlik konum yerine sürekli takip:
StreamSubscription<Position>? _konumAbonesi;
void konumTakibiBaslat() {
_konumAbonesi = Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10, // sadece 10 metreden fazla hareket edince güncelle
),
).listen((Position pozisyon) {
print('Yeni konum: ${pozisyon.latitude}, ${pozisyon.longitude}');
});
}
@override
void dispose() {
_konumAbonesi?.cancel(); // Konu 36'daki AnimationController.dispose() ile AYNI prensip!
super.dispose();
}getPositionStream(), Bölüm 5 Konu 19'da öğrendiğimiz Stream kavramının gerçek dünya kullanımı — konum sürekli değiştiği için, tek seferlik bir Future yerine akan bir veri kaynağı daha uygun. distanceFilter: 10, gereksiz güncellemeleri (pil tüketimini) azaltan bir optimizasyon. _konumAbonesi?.cancel()'ı dispose()'ta çağırmayı unutmak, Konu 36'da AnimationController.dispose()'u unutmakla aynı sınıf hatadır — widget kalksa bile dinleme arka planda devam eder.
Sensörler — sensors_plus
flutter pub add sensors_plusimport 'package:sensors_plus/sensors_plus.dart';
StreamSubscription<AccelerometerEvent>? _ivmeAbonesi;
void ivmeOlcerDinlemeBaslat() {
_ivmeAbonesi = accelerometerEventStream().listen((AccelerometerEvent olay) {
print('x: ${olay.x}, y: ${olay.y}, z: ${olay.z}');
});
}
@override
void dispose() {
_ivmeAbonesi?.cancel();
super.dispose();
}Desen tamamen tanıdık geliyor olmalı — sensors_plus, geolocator'daki Stream yaklaşımının aynısını ivmeölçer, jiroskop (gyroscopeEventStream()), manyetometre (magnetometerEventStream()) gibi diğer sensörler için de sunuyor. Bu paket, izin gerektirmez (ivmeölçer/jiroskop gibi hareket sensörleri, çoğu platformda izin gerektirmeyen "hassas olmayan" veri sayılır) — bu da onu konum ve kameraya göre kullanmaya başlaması daha kolay bir paket yapıyor.
Üç Paketin Ortak Deseni
Fark ettiysen, üçü de aynı iskeleti paylaşıyor:
- Gerekliyse izin kontrolü/isteme (Konu 41).
- Ya tek seferlik bir değer al (
Future—getCurrentPosition,pickImage) ya da sürekli bir akışa abone ol (Stream—getPositionStream,accelerometerEventStream). Stream'e abone olduysan,dispose()'ta mutlakacancel()et.
Bu üçünü bir kez kavradığında, Flutter ekosistemindeki düzinelerce benzer donanım-erişim paketini (mikrofon, Bluetooth, NFC) okurken aynı zihinsel modeli kolayca uygulayabilirsin.
🎯 Bu Dersten Çıkarılması Gerekenler
- Basit fotoğraf çekme/seçme için
image_picker(native kamera uygulamasını açar) yeterlidir; özelleştirilmiş bir kamera arayüzü içincamerapaketi (doğrudan akış erişimi) kullanılır. geolocator, kendi izin API'sini (LocationPermission) sunar — Konu 41'dekipermission_handlermantığına paralel çalışır, konum için genelde tek başına yeterlidir.- Tek seferlik konum için
getCurrentPosition()(Future); sürekli takip içingetPositionStream()(Stream) kullanılır. sensors_plus, ivmeölçer/jiroskop/manyetometre verisiniStreamolarak sunar, genelde izin gerektirmez.- Ortak desen: izin kontrolü → Future veya Stream → (Stream ise)
dispose()'tacancel(). Bu deseni unutmak, Konu 36'dakiAnimationControllersızıntısıyla aynı sınıf hatadır.
📝 Ödevler
- [ ]
image_pickerile hem kameradan çekme hem galeriden seçme seçeneği sunan, seçilen resmi ekranda gösteren bir ekran yap. - [ ]
geolocatorile kullanıcının mevcut konumunu (enlem/boylam) alıp ekranda gösteren, izin akışının tüm adımlarını (kontrol → iste → deniedForever durumunda ayarlara yönlendirme) doğru yöneten bir buton yap. - [ ]
getPositionStream()ile, kullanıcı hareket ettikçe güncellenen bir "canlı konum" göstergesi yap;dispose()'ta aboneliği düzgünce iptal ettiğini doğrula. - [ ]
sensors_plusile ivmeölçer verisini canlı gösteren basit bir ekran yap (örn. telefonu eğdikçe x/y/z değerlerinin değiştiğini gözlemle). - [ ] Kendi cümlelerinle, "neden bir
Streamaboneliğinidispose()'ta iptal etmemenin bir bellek sızıntısına yol açtığını" açıkla.
Sıradaki konu: Bölüm 9 — Konu 43: Push Notification (FCM — Firebase Cloud Messaging)