Slide 1

Slide 1 text

Flutter੡νϟοτΞϓϦ Λࢧ͑Δٕज़ Flutter Meetup Osaka #2 2020/02/28

Slide 2

Slide 2 text

• Տຊ ହ޹(͔Θ΋ͱ ΍͔ͨ͢) • ॴଐɿגࣜձࣾ tech vein 
 AndroidɺiOSΞϓϦΤϯδχΞ • kwmt • @kwmt27 • Flutter Meetup Osaka #1(2018/06)͔Β
 FlutterΛ৮Γͩͨ͠ • ࣗݾ঺հ ʮॳग़ɿٕज़ධ࿦ࣾץʰιϑτ΢ΣΞσβΠϯ2019೥4݄߸ʱʯ

Slide 3

Slide 3 text

2018೥ʹνϟοτΞϓϦΛϦϦʔε

Slide 4

Slide 4 text

QiitaʹνϟοτΞϓϦ։ൃͷ஌ݟΛॻ͍ͨ ※2020/02/27ݱࡏ

Slide 5

Slide 5 text

• Google is able to guarantee a high quality camera performance • Automated CameraX test lab • Populated with devices from various manufactures • Test hundreds of devices • Various test types • Functional, integration, end-to-end use case, performance, etc. ݄͝ͱͷ͍͍Ͷ਺ ※2020/02/27ݱࡏ

Slide 6

Slide 6 text

• Google is able to guarantee a high quality camera performance • Automated CameraX test lab • Populated with devices from various manufactures • Test hundreds of devices • Various test types • Functional, integration, end-to-end use case, performance, etc. ݄͝ͱͷ͍͍Ͷ਺ ※2020/02/27ݱࡏ

Slide 7

Slide 7 text

• νϟοτΞϓϦͷػೳ • ձһొ࿥ɾϩάΠϯ • νϟοτϧʔϜʢҎԼɺϧʔϜʣ࡞੒Ͱ͖Δ • ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ • ϧʔϜҰཡΛݟΔ͜ͱ͕Ͱ͖Δ • طଘͷϧʔϜʹϢʔβʔ͕ࢀՃͰ͖Δ • ࣗ෼ͷϓϩϑΟʔϧΛݟΔ͜ͱ͕Ͱ͖Δ • ΞϓϦ಺՝ۚͰఆظߪಡͰ͖Δ • ͳͲ… • ։ൃऀͷͨΊͷػೳ • Analytics • Crashlytics • AdMob ͜ͷهࣄͰॻ͍ͨͷ͸

Slide 8

Slide 8 text

• ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ ࠓճ঺հ͢Δػೳ

Slide 9

Slide 9 text

• จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

Slide 10

Slide 10 text

• จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

Slide 11

Slide 11 text

จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ

Slide 12

Slide 12 text

จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ

Slide 13

Slide 13 text

TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(() { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });

Slide 14

Slide 14 text

TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(() { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });

Slide 15

Slide 15 text

TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(() { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });

Slide 16

Slide 16 text

TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(() { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });

Slide 17

Slide 17 text

ૹ৴Ϙλϯͷ४උ IconButton( icon: Icon(Icons.send), color: Colors.blueAccent, onPressed: _isEmpty ? null : () {…} ); bool _isEmpty = true;

Slide 18

Slide 18 text

ૹ৴Ϙλϯͷ४උ IconButton( icon: Icon(Icons.send), color: Colors.blueAccent, onPressed: _isEmpty ? null : () {…} ); bool _isEmpty = true;

Slide 19

Slide 19 text

ϦεφʔΛ࣮૷ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(() { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });

Slide 20

Slide 20 text

ϦεφʔΛ࣮૷ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(() { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ setState(() { _isEmpty = _textEditingController.text.isEmpty; }); });

Slide 21

Slide 21 text

• จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

Slide 22

Slide 22 text

νϟοτϝοηʔδΛૹ৴͢Δ ϝοηʔδΛ σʔλϕʔεʹอଘ

Slide 23

Slide 23 text

Firestoreͷσʔλొ࿥ྫ _firestore .collection("rooms") .document(room.id) .collection("messages") .document() .setData({ 'content': "͸Ζʔ", 'created_at': createdAt, … }); );

Slide 24

Slide 24 text

Firestoreͷσʔλొ࿥ྫ _firestore .collection("rooms") .document(room.id) .collection("messages") .document() .setData({ 'content': "͸Ζʔ", 'created_at': createdAt, … }); );

Slide 25

Slide 25 text

ϝοηʔδϦετʹϦΞϧλΠϜʹ൓ө

Slide 26

Slide 26 text

ϝοηʔδϦετʹϦΞϧλΠϜʹ൓ө

Slide 27

Slide 27 text

ϝοηʔδϦετʹϦΞϧλΠϜʹ൓ө _firestore .collection(“rooms") .document(room.id) .collection("messages") .orderBy("created_at", descending: true) .snapshots() .listen((querySnapshot) { // σʔλ͕มߋ͞Εͨͱ͖ɺ͜͜ʹ௨஌͕͘Δɻ // querySnapShot.documentsͷ֤documentͷdataͰɺ // อଘͨ͠σʔλΛऔಘͰ͖Δɻ }

Slide 28

Slide 28 text

ը૾ΛΞοϓϩʔυ͢Δ

Slide 29

Slide 29 text

ը૾ΛΞοϓϩʔυ͢Δ

Slide 30

Slide 30 text

ը૾ΛΞοϓϩʔυ͢Δ <ը૾>

Slide 31

Slide 31 text

ը૾ΛΞοϓϩʔυ͢Δ <ը૾> ը૾μ΢ϯϩʔυURL

Slide 32

Slide 32 text

ը૾ΛΞοϓϩʔυ͢Δ <ը૾> ը૾μ΢ϯϩʔυURL ը૾μ΢ϯϩʔυURL

Slide 33

Slide 33 text

ը૾Ξοϓϩʔυͷίʔυྫ var snapshot = await _storage .ref() .child('${timestamp}_${basename(file.path)}') .putFile( file, StorageMetadata( contentType: "image/jpeg", )) .onComplete; if (snapshot.error == null) { var url = await snapshot.ref.getDownloadURL(); // FirestoreʹurlΛૹ৴ }

Slide 34

Slide 34 text

ը૾Ξοϓϩʔυͷίʔυྫ var snapshot = await _storage .ref() .child('${timestamp}_${basename(file.path)}') .putFile( file, StorageMetadata( contentType: "image/jpeg", )) .onComplete; if (snapshot.error == null) { var url = await snapshot.ref.getDownloadURL(); // FirestoreʹurlΛૹ৴ }

Slide 35

Slide 35 text

• จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

Slide 36

Slide 36 text

ϝοηʔδϦετΛදࣔ͢Δ 1൪Լ͕࠷৽ͷϝοηʔδ

Slide 37

Slide 37 text

ListView ListView.builder( itemBuilder: (context, position) { return <֤ߦͷWidget>; }, );

Slide 38

Slide 38 text

ListViewΛٯॱͰදࣔ ListView.builder( reverse: true, itemBuilder: (context, position) { return <֤ߦͷWidget>; }, );

Slide 39

Slide 39 text

Ϧετͷ֤ߦͷϨΠΞ΢τ

Slide 40

Slide 40 text

Ϧετͷ֤ߦͷϨΠΞ΢τ

Slide 41

Slide 41 text

Ϧετͷ֤ߦͷϨΠΞ΢τ Row

Slide 42

Slide 42 text

Ϧετͷ֤ߦͷϨΠΞ΢τ Row

Slide 43

Slide 43 text

Ϧετͷ֤ߦͷϨΠΞ΢τ Row Column

Slide 44

Slide 44 text

γϯϓϧͳϦετͷϨΠΞ΢τ https://api.flutter.dev/flutter/material/ListTile-class.html

Slide 45

Slide 45 text

γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here is a second line'), trailing: Icon(Icons.more_vert), )

Slide 46

Slide 46 text

γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here is a second line'), trailing: Icon(Icons.more_vert), )

Slide 47

Slide 47 text

γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here is a second line'), trailing: Icon(Icons.more_vert), )

Slide 48

Slide 48 text

γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here is a second line'), trailing: Icon(Icons.more_vert), )

Slide 49

Slide 49 text

γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here is a second line'), trailing: Icon(Icons.more_vert), )

Slide 50

Slide 50 text

νϟοτΞϓϦͰ͸ϧʔϜҰཡͰ࢖༻

Slide 51

Slide 51 text

·ͱΊ

Slide 52

Slide 52 text

• ϝοηʔδೖྗத͔Ͳ͏͔͸ɺTextEditingControllerͰ൑ அͰ͖Δ • ը૾΋ςΩετͷૹ৴͸ɺFirebaseͷϓϥάΠϯͰ؆୯ ʹอଘͰ͖Δ • FlutterͷϦετදࣔ͸ListViewͰ௒؆୯ ·ͱΊ

Slide 53

Slide 53 text

Φʔϓϯιʔεʹ͠·ͨ͠ʂ TODO: GitHubͷը૾ΛషΔ https://github.com/kwmt/flutter-inconne ˑελʔΛ๨Εͣʹ͆

Slide 54

Slide 54 text

Clean Architectureʹؔͯ͠͸ͪ͜Β https://speakerdeck.com/yasi/flutter-development-as-usual

Slide 55

Slide 55 text

Thank you @kwmt27