[Di dermaga] Berkibar. Bagian 1. Untuk pengembang Android

Flutter telah menulis banyak artikel. Setiap bulan menjadi lebih populer. Jadi saya memutuskan untuk menafsirkan dokumentasi Flutter resmi dalam format tanya jawab yang ringkas. Saya pikir banyak orang, seperti saya, tidak memiliki cukup waktu luang untuk mempelajari secara detail dokumentasi kerangka kerja yang dengannya mereka masih belum berfungsi.

Jika Anda ingin memahami untuk apa kerangka kerja ini, dan untuk mengevaluasi berapa banyak usaha yang harus Anda lakukan untuk menggunakannya, selamat datang di cat.



Konten:


  1. Tampilan

  2. Maksud

  3. Async ui

  4. Struktur dan Sumber Daya Proyek

  5. Aktivitas & Fragmen

  6. Tata letak

  7. Gerakan dan penanganan acara sentuh.

  8. Tampilan daftar & adaptor

  9. Bekerja dengan teks

  10. Formulir input

  11. Flutter Plugins

  12. Tema

  13. Database dan penyimpanan lokal

  14. Notifikasi


Tampilan


Pertanyaan:


Apa yang setara dengan View in Flutter?

Jawabannya adalah:


Widget

Perbedaan:


Lihat - pada kenyataannya, apa yang akan ada di layar. Validate () dipanggil untuk menampilkan perubahan.

Widget - deskripsi tentang apa yang akan ada di layar. Untuk perubahan dibuat lagi.

Informasi tambahan:


Saat diluncurkan di Android sendiri, View berada di bawah naungan Widget. Flutter termasuk perpustakaan Material Components . Ini berisi widget yang menerapkan pedoman Desain Bahan .

Pertanyaan:


Bagaimana cara memperbarui tampilan widget?

Jawabannya adalah:


Menggunakan StatefulWidget dan State -nya. Flutter memiliki 2 jenis widget: StatelessWidget dan StatefulWidget . Mereka bekerja dengan cara yang sama, satu-satunya perbedaan adalah dalam keadaan rendering.

Perbedaan:


StatelessWidget memiliki status yang tidak dapat diubah. Cocok untuk menampilkan teks, logo, dll. Yaitu jika elemen pada layar tidak boleh berubah selama seluruh waktu tampilan, maka itu cocok untuk Anda. Ini juga dapat digunakan sebagai wadah untuk widget stateful.

StatefulWidget memiliki status Negara, yang menyimpan informasi tentang keadaan saat ini. Jika Anda ingin mengubah elemen di layar saat melakukan beberapa tindakan (respons datang dari server, pengguna mengklik tombol, dll.) - ini adalah pilihan Anda.

Contoh:


1) StatelessWidget - Teks

Text( 'I like Flutter!', style: TextStyle(fontWeight: FontWeight.bold), ); 

2) StatefulWidget - ketika Anda mengklik tombol (FloatingActionButton), teks dalam widget Teks berubah dari "I Like Flutter" menjadi "Flutter is Awesome!".

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { //     . @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { //   String textToShow = "  Flutter"; void _updateText() { setState(() { //   textToShow = "Flutter !"; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center(child: Text(textToShow)), floatingActionButton: FloatingActionButton( onPressed: _updateText, tooltip: ' ', child: Icon(Icons.update), ), ); } } 

Pertanyaan:


Bagaimana cara menata layar dengan widget? Di mana file tata letak XML?

Jawabannya adalah:


Flutter tidak memiliki tata letak XML untuk layar. Semuanya mengeset di pohon widget langsung di kode.

Contoh:


 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: MaterialButton( onPressed: () {}, child: Text('Hello'), padding: EdgeInsets.only(left: 10.0, right: 10.0), ), ), ); } 

Semua widget default di Flutter dapat dilihat di katalog widget .

Pertanyaan:


Bagaimana cara menambah atau menghapus komponen dalam tata letak saat aplikasi sedang berjalan?

Jawabannya adalah:


Melalui fungsi yang akan mengembalikan widget yang diinginkan tergantung pada negara.

Perbedaan:


Di Android, Anda dapat melakukan addView () atau removeView () di ViewGroup. Di Flutter itu tidak mungkin karena widget tidak berubah. Hanya kondisinya yang bisa berubah.

Contoh:


Cara mengubah Teks ke Tombol dengan mengklik FloatingActionButton.

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { //     . @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { //     bool toggle = true; void _toggle() { setState(() { toggle = !toggle; }); } _getToggleChild() { if (toggle) { return Text('Toggle One'); } else { return MaterialButton(onPressed: () {}, child: Text('Toggle Two')); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: _getToggleChild(), ), floatingActionButton: FloatingActionButton( onPressed: _toggle, tooltip: 'Update Text', child: Icon(Icons.update), ), ); } } 

Pertanyaan:


Bagaimana cara menghidupkan widget?

Jawabannya adalah:


Menggunakan kelas AnimationController , yang merupakan turunan dari kelas abstrak Animation <T> . Selain memulai animasi, ia dapat menjeda, memundurkan, berhenti dan memainkannya dengan arah yang berlawanan. Bekerja dengan Ticker , yang melaporkan redraw layar.

Perbedaan:


Di Android, Anda dapat membuat animasi dalam XML atau animate View menggunakan animate (). Dalam Flutter, animasi harus ditulis dalam kode menggunakan AnimationController.

Informasi tambahan:


Anda dapat mempelajari lebih lanjut di widget Animasi & Gerak , tutorial Animasi, dan ikhtisar Animasi .

Contoh:


Animasi fade dari logo Flutter.

 import 'package:flutter/material.dart'; void main() { runApp(FadeAppTest()); } class FadeAppTest extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Fade Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyFadeTest(title: 'Fade Demo'), ); } } class MyFadeTest extends StatefulWidget { MyFadeTest({Key key, this.title}) : super(key: key); final String title; @override _MyFadeTest createState() => _MyFadeTest(); } class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin { AnimationController controller; CurvedAnimation curve; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Container( child: FadeTransition( opacity: curve, child: FlutterLogo( size: 100.0, )))), floatingActionButton: FloatingActionButton( tooltip: 'Fade', child: Icon(Icons.brush), onPressed: () { controller.forward(); }, ), ); } } 

Pertanyaan:


Bagaimana cara menggunakan Canvas ?

Jawabannya adalah:


Android dan Flutter memiliki API yang sama untuk Canvas, seperti mereka menggunakan mesin Skia tingkat rendah yang sama.

Perbedaan:


Tidak.

Informasi tambahan:


Flutter memiliki dua kelas untuk menggambar di atas Kanvas - CustomPaint dan CustomPainter . Yang kedua mengimplementasikan algoritma rendering Anda.

Baca lebih lanjut di sini: StackOverflow

Contoh:


 import 'package:flutter/material.dart'; void main() => runApp(MaterialApp(home: DemoApp())); class DemoApp extends StatelessWidget { Widget build(BuildContext context) => Scaffold(body: Signature()); } class Signature extends StatefulWidget { SignatureState createState() => SignatureState(); } class SignatureState extends State<Signature> { List<Offset> _points = <Offset>[]; Widget build(BuildContext context) { return GestureDetector( onPanUpdate: (DragUpdateDetails details) { setState(() { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); _points = List.from(_points)..add(localPosition); }); }, onPanEnd: (DragEndDetails details) => _points.add(null), child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite), ); } } class SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset> points; void paint(Canvas canvas, Size size) { var paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5.0; for (int i = 0; i < points.length - 1; i++) { if (points[i] != null && points[i + 1] != null) canvas.drawLine(points[i], points[i + 1], paint); } } bool shouldRepaint(SignaturePainter other) => other.points != points; } 

Pertanyaan:


Bagaimana cara membuat widget khusus?

Jawabannya adalah:


Tulis widget di dalam satu (bukan warisan).

Perbedaan:


Di Android, kita dapat mewarisi dari View yang kita minati dan menambahkan logika kita sendiri. Di Flutter, ini mirip dengan ViewGroup, hanya widget yang selalu diwarisi dari StatelessWidget atau StatefulWidget. Yaitu Anda perlu membuat widget baru dan menggunakannya seperangkat widget yang Anda butuhkan sebagai parameter atau bidang.

Contoh:


 class CustomButton extends StatelessWidget { final String label; CustomButton(this.label); @override Widget build(BuildContext context) { return RaisedButton(onPressed: () {}, child: Text(label)); } } @override Widget build(BuildContext context) { return Center( child: CustomButton("Hello"), ); } 

Maksud


Pertanyaan:


Apa yang dimaksud dengan analog Intent in Flutter?

Jawabannya adalah:


Dia tidak ada di sana. Untuk menavigasi antara layar, kelas Navigator dan Rute digunakan.

Untuk berinteraksi dengan komponen eksternal (misalnya, kamera atau pemilih file), Anda dapat menggunakan plugin atau integrasi asli pada setiap platform. Pelajari lebih lanjut tentang integrasi asli: Mengembangkan Paket dan Plugin .

Perbedaan:


Flutter tidak memiliki aktivitas dan fragmen. Ada Navigator (Navigator) dan Rute (rute). Aplikasi Flutter menyerupai aplikasi aktivitas tunggal, di mana layar yang berbeda mewakili fragmen yang berbeda, dan FragmentManager mengendalikannya. Navigator mirip dengan FragmentManager pada prinsipnya. Itu dapat melakukan push () atau pop () ke rute yang Anda tentukan. Rute adalah sejenis Fragmen, tetapi dalam Flutter biasanya membandingkannya dengan layar atau halaman.

Di Android, kami menjelaskan semua Kegiatan yang dapat kami navigasikan di AndroidManifest.xml.

Flutter memiliki dua cara:

  • Jelaskan Peta yang bernama Route (MaterialApp)
  • Navigasi langsung ke Rute (WidgetApp).

Contoh:


 void main() { runApp(MaterialApp( home: MyAppHome(), // becomes the route named '/' routes: <String, WidgetBuilder> { '/a': (BuildContext context) => MyPage(title: 'page A'), '/b': (BuildContext context) => MyPage(title: 'page B'), '/c': (BuildContext context) => MyPage(title: 'page C'), }, )); } Navigator.of(context).pushNamed('/b'); 

Pertanyaan:


Bagaimana cara memproses maksud yang berasal dari aplikasi lain?

Jawabannya adalah:


Berinteraksi dengan lapisan aplikasi Android melalui MethodChannel .

Contoh:


Kami menulis intent-filter di AndroidManifest.xml:

 <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <!-- ... --> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity> 

Kami memproses Intent di MainActivity dan memanggil kode dari Flutter melalui MethodChannel:

 package com.example.shared; import android.content.Intent; import android.os.Bundle; import java.nio.ByteBuffer; import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.ActivityLifecycleListener; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { private String sharedText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); Intent intent = getIntent(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { handleSendText(intent); // Handle text being sent } } new MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { if (call.method.contentEquals("getSharedText")) { result.success(sharedText); sharedText = null; } } }); } void handleSendText(Intent intent) { sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); } } 

Kami meminta data saat widget mulai ditarik:

 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample Shared App Handler', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { static const platform = const MethodChannel('app.channel.shared.data'); String dataShared = "No data"; @override void initState() { super.initState(); getSharedText(); } @override Widget build(BuildContext context) { return Scaffold(body: Center(child: Text(dataShared))); } getSharedText() async { var sharedData = await platform.invokeMethod("getSharedText"); if (sharedData != null) { setState(() { dataShared = sharedData; }); } } } 

Pertanyaan:


Apa analog dari startActivityForResult () ?

Jawabannya adalah:


Kata kunci yang menunggu dan hasil dari kelas Future .

Perbedaan:


Setelah memanggil startActivityForResult () di Android, kita perlu mengimplementasikan pemrosesan di onActivityResult (). Flutter tidak perlu mengimplementasikan apa pun, karena push navigator method () mengembalikan objek Future.

Contoh:


 Map coordinates = await Navigator.of(context).pushNamed('/location'); 

Dan ketika kami mendapatkan koordinat di layar '/ lokasi', lakukan pop ():

 Navigator.of(context).pop({"lat":43.821757,"long":-79.226392}); 

Async ui


Pertanyaan:


Apa analog dari runOnUiThread () di Flutter?

Jawabannya adalah:


Dart mengimplementasikan model eksekusi single-threaded yang berjalan pada Isolates . Eksekusi asinkron menggunakan async / menunggu, yang mungkin Anda kenal dari C #, JavaScript, atau koroutine Kotlin.

Contoh:


Memenuhi permintaan dan mengembalikan hasilnya untuk memperbarui UI:

 loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } 

Ketika respons terhadap permintaan diterima, Anda perlu memanggil metode setState () untuk menggambar ulang pohon widget dengan data baru.

Contoh:


Memuat dan memperbarui data dalam ListView :

 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); })); } Widget getRow(int i) { return Padding( padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}") ); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Pertanyaan:


Bagaimana cara mengeksekusi kode di utas latar?

Jawabannya adalah:


Seperti disebutkan di atas - menggunakan async / await and isolation (Isolate).

Perbedaan:


Di luar kotak di Android, Anda dapat menggunakan AsyncTask. Anda perlu mengimplementasikan onPreExecute () , doInBackground () , onPostExecute () di dalamnya . Di Flutter "out of the box" Anda hanya perlu menggunakan async / menunggu, Dart akan mengurus sisanya.

Contoh:


Di sini metode dataLoader () diisolasi. Dalam isolasi, Anda dapat menjalankan operasi berat seperti mem-parsing JSON besar, enkripsi, pemrosesan gambar, dll.

 loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // The entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; }   : import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:async'; import 'dart:isolate'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { if (widgets.length == 0) { return true; } return false; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // the entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; } } 

Pertanyaan:


Apa yang dimaksud dengan Flutter setara OkHttp ?

Jawabannya adalah:


Flutter memiliki paket HTTP sendiri.

Informasi tambahan:


Sejauh ini, tidak semua fitur OkHttp telah diimplementasikan dalam Paket HTTP, begitu banyak fitur yang hilang diabstraksikan dan Anda dapat mengimplementasikannya sendiri sesuai kebutuhan.

Contoh:


Untuk menggunakan paket HTTP, tambahkan itu sebagai dependensi di pubspec.yaml:

 dependencies: ... http: ^0.11.3+16 

Untuk menjalankan permintaan, panggilan tunggu di fungsi async http.get ():

 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; [...] loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Pertanyaan:


Bagaimana cara menunjukkan kemajuan?

Jawabannya adalah:


Menggunakan widget ProgressIndicator .

Contoh:


 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { return widgets.length == 0; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Struktur dan Sumber Daya Proyek


Pertanyaan:


Di mana menyimpan sumber daya dari berbagai resolusi?

Jawabannya adalah:


Dalam aset.

Perbedaan:


Di Android, sumber daya memiliki folder res dan memiliki aset. Flutter hanya memiliki aset. Folder aset dapat ditemukan di mana saja di dalam proyek, yang paling penting, tulis path untuk itu di file pubspec.yaml.

Informasi tambahan:


Perbandingan ukuran sumber daya grafis di Android dan Flutter.
Kualifikasi kepadatan AndroidRasio piksel bergetar
ldpi0,75x
mdpi1.0x
hdpi1,5x
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4.0x
Flutter menggunakan AssetManager atau kelas khusus yang dimulai dengan Asset untuk menggunakan sumber daya dalam kode.

Contoh:


Pengelola Aset:

 val flutterAssetStream = assetManager.open("flutter_assets/assets/my_flutter_asset.png") 

Lokasi Sumber Daya:

 images/my_icon.png // Base: 1.0x image images/2.0x/my_icon.png // 2.0x image images/3.0x/my_icon.png // 3.0x image 

Path dalam file pubspec.yaml:

 assets: - images/my_icon.jpeg 

Menggunakan AssetImage :

 return AssetImage("images/a_dot_burr.jpeg"); 

Menggunakan aset secara langsung:

 @override Widget build(BuildContext context) { return Image.asset("images/my_image.png"); } 

Pertanyaan:


Di mana menyimpan string? Bagaimana cara melokalkannya?

Jawabannya adalah:


Simpan di bidang statis. Lokalisasi menggunakan paket intl .

Contoh:


 class Strings { static String welcomeMessage = "Welcome To Flutter"; } Text(Strings.welcomeMessage) 

Pertanyaan:


Apa analog dari file gradle? Bagaimana cara menambahkan dependensi?

Jawabannya adalah:


pubspec.yaml.

Informasi tambahan:


Flutter mendelegasikan perakitan ke pembuat Android dan iOS asli. Lihat daftar semua perpustakaan populer untuk Flutter di Pub .

Aktivitas & Fragmen


Pertanyaan:


Apa yang setara dengan Activity dan Fragment in Flutter?

Jawabannya adalah:


Semua yang ada di Flutter adalah widget. Peran aktivitas dan fragmen untuk bekerja dengan UI dimainkan oleh widget. Dan peran navigasi, sebagaimana disebutkan dalam paragraf tentang navigasi, adalah Navigator dan Rute.

Informasi tambahan:


Flutter Untuk Pengembang Android: Cara merancang UI Aktivitas di Flutter .

Pertanyaan:


Bagaimana cara menangani acara siklus hidup?

Jawabannya adalah:


Menggunakan metode WidgetsBinding dan didChangeAppLifecycleState () .

Informasi tambahan:


Flutter menggunakan FlutterActivity dalam kode asli, dan mesin Flutter membuat perubahan status pemrosesan sesederhana mungkin. Tetapi jika Anda masih perlu melakukan beberapa pekerjaan tergantung pada negara, maka siklus hidupnya sedikit berbeda:

  • tidak aktif - metode ini hanya di iOS, di Android tidak ada analog;
  • dijeda - mirip dengan onPause () di Android;
  • dilanjutkan - mirip dengan onPostResume () di Android;
  • menangguhkan - mirip dengan onStop di Android, di iOS tidak ada analog.

Ini dijelaskan secara lebih rinci dalam dokumentasi AppLifecycleStatus .

Contoh:


 import 'package:flutter/widgets.dart'; class LifecycleWatcher extends StatefulWidget { @override _LifecycleWatcherState createState() => _LifecycleWatcherState(); } class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver { AppLifecycleState _lastLifecycleState; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { setState(() { _lastLifecycleState = state; }); } @override Widget build(BuildContext context) { if (_lastLifecycleState == null) return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr); return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.', textDirection: TextDirection.ltr); } } void main() { runApp(Center(child: LifecycleWatcher())); } 

Tata letak


Pertanyaan:


Apa analog dari LinearLayout ?

Jawabannya adalah:


Baris untuk horizontal, Kolom untuk vertikal.

Informasi tambahan:


Flutter Untuk Pengembang Android: Bagaimana cara mendesain LinearLayout di Flutter?

Contoh:


 @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Column One'), Text('Column Two'), Text('Column Three'), Text('Column Four'), ], ); } 

Pertanyaan:


Apa yang setara dengan RelativeLayout ?

Jawabannya adalah:


Widget Tumpukan .

Lebih detail:

Stackoverflow

Pertanyaan:


Apa analog dari ScrollView ?

Jawabannya adalah:


ListView dengan widget.

Contoh:


 @override Widget build(BuildContext context) { return ListView( children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); } 

Pertanyaan:


Bagaimana cara menangani transisi antara potret dan lanskap?

Jawabannya adalah:


FlutterView menangani flips jika AndroidManifest.xml mengandung
android: configChanges = "orientasi | screenSize"

Gerakan dan penanganan acara sentuh


Pertanyaan:


Bagaimana cara menambahkan pendengar onClick untuk widget di Flutter?

Jawabannya adalah:


Jika widget mendukung klik, maka dalam onPressed (). Jika tidak, maka di onTap ().

Contoh:


Di onPressed ():

 @override Widget build(BuildContext context) { return RaisedButton( onPressed: () { print("click"); }, child: Text("Button")); } 

Di onTap ():

 class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: FlutterLogo( size: 200.0, ), onTap: () { print("tap"); }, ), )); } } 

Pertanyaan:


Bagaimana cara menangani gerakan lain pada widget?

Jawabannya adalah:


Menggunakan GestureDetector . Mereka dapat menangani tindakan berikut:

Ketuk



Ketuk dua kali



Tekan lama



Seret vertikal



Seret horizontal



Contoh:


Memproses onDoubleTap:

 AnimationController controller; CurvedAnimation curve; @override void initState() { controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: RotationTransition( turns: curve, child: FlutterLogo( size: 200.0, )), onDoubleTap: () { if (controller.isCompleted) { controller.reverse(); } else { controller.forward(); } }, ), )); } } 

Tampilan daftar & adaptor


Pertanyaan:


Apakah analog dari ListView in Flutter?

Jawabannya adalah:


ListView

Perbedaan:


Flutter tidak harus berpikir tentang membersihkan dan menggunakan kembali item (yang dilakukan ListView / RecyclerView di Android, menggunakan pola ViewHolder).

Contoh:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(Padding(padding: EdgeInsets.all(10.0), child: Text("Row $i"))); } return widgets; } } 

:


?

Jawabannya adalah:


GestureDetector .

Contoh:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { print('row tapped'); }, )); } return widgets; } } 

:


ListView ?

Jawabannya adalah:


, setState() . , ListView.Builder , RecyclerView .

Contoh:


setState() :

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = <Widget>[]; @override void initState() { super.initState(); for (int i = 0; i < 100; i++) { widgets.add(getRow(i)); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: widgets), ); } Widget getRow(int i) { return GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { setState(() { widgets = List.from(widgets); widgets.add(getRow(widgets.length + 1)); print('row $i'); }); }, ); } } 

ListView.Builder :

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = <Widget>[]; @override void initState() { super.initState(); for (int i = 0; i < 100; i++) { widgets.add(getRow(i)); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); })); } Widget getRow(int i) { return GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { setState(() { widgets.add(getRow(widgets.length + 1)); print('row $i'); }); }, ); } } 


:


?

Jawabannya adalah:


( ) pubspec.yaml.

Contoh:


 fonts: - family: MyCustomFont fonts: - asset: fonts/MyCustomFont.ttf - style: italic 

 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: Text( 'This is a custom font text', style: TextStyle(fontFamily: 'MyCustomFont'), ), ), ); } 

:


?

Jawabannya adalah:


:

  • color;
  • decoration;
  • decorationColor;
  • decorationStyle;
  • fontFamily;
  • fontSize;
  • fontStyle;
  • fontWeight;
  • hashCode;
  • height;
  • inherit;
  • letterSpacing;
  • textBaseline;
  • wordSpacing.


: Retrieve the value of a text field .

:


hint TextInput ?

Jawabannya adalah:


InputDecoration , .

Contoh:


 body: Center( child: TextField( decoration: InputDecoration(hintText: "This is a hint"), ) ) 

:


?

Jawabannya adalah:


โ€” InputDecoration .

Contoh:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { String _errorText; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: TextField( onSubmitted: (String text) { setState(() { if (!isEmail(text)) { _errorText = 'Error: This is not an email'; } else { _errorText = null; } }); }, decoration: InputDecoration(hintText: "This is a hint", errorText: _getErrorText()), ), ), ); } _getErrorText() { return _errorText; } bool isEmail(String em) { String emailRegexp = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; RegExp regExp = RegExp(emailRegexp); return regExp.hasMatch(em); } } 

Flutter


:


GPS?

Jawabannya adalah:


geolocator .

:


?

Jawabannya adalah:


image_picker .

:


Facebook?

Jawabannya adalah:


flutter_facebook_login .

:


Firebase?

Jawabannya adalah:


Firebase Flutter first party plugins .


:


() ?

Jawabannya adalah:


Flutter EventBus . : developing packages and plugins .

:


NDK?

Jawabannya adalah:


NDK- Flutter. Flutter .

Themes


:


(Theme) ?

Jawabannya adalah:


MaterialApp WidgetApp .

Contoh:


 class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, textSelectionColor: Colors.red ), home: SampleAppPage(), ); } } 


:


Shared Preferences?

Jawabannya adalah:


Shared_Preferences plugin ( NSUserDefaults iOS ).

Contoh:


 import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { runApp( MaterialApp( home: Scaffold( body: Center( child: RaisedButton( onPressed: _incrementCounter, child: Text('Increment Counter'), ), ), ), ), ); } _incrementCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); int counter = (prefs.getInt('counter') ?? 0) + 1; print('Pressed $counter times.'); prefs.setInt('counter', counter); } 

:


SQLite Flutter?

Jawabannya adalah:


SQFlite .


:


push-?

Jawabannya adalah:


Firebase_Messaging .

Kesimpulan


. , , . ยซ ยป . ยซ-ยป . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). โ€” ! , โ€” . Itu semua untuk saya. Google Play!

Source: https://habr.com/ru/post/id442432/


All Articles