Creació d’una aplicació per prendre notes a Flutter / Dart

Bloc

Creació d’una aplicació per prendre notes a Flutter / Dart

Creació d’una aplicació per prendre notes a Flutter / Dart

Aplicacions per a les quals hi ha escrit Dard . Aletejar ve pre-equipat amb Disseny de materials components que facilita la creació d'aplicacions amb bon aspecte. A Flutter, tot és un giny apàtrid o estatal. Una aplicació per prendre notes és una cosa per començar, amb un disseny i funcionalitats útils.



Si no heu instal·lat Flutter ni un IDE compatible, podeu trobar les instruccions aquí .

En primer lloc, configurem el projecte:



  1. Creeu un projecte de flutter des d'Android Studio o introduïu l'ordre a terminal / cmd flutter crea notes .
  2. En main.dart elimineu la classe homePage i creeu un fitxer nou amb la nostra pròpia classe HomePage que estén el widget Stateful. Aquesta classe contindrà el nostre cadafal.
  3. Creeu una altra classe de widget amb estat. Això crearà un cos que conté una vista esglaonada per a HomePage. Ho trucarem StaggeredGridPage .

Siguem creatius i intentem presentar les notes en una visualització esglaonada.

Utilitzarem aquest paquet de dards per crear una visualització de quadrícula esglaonada. https://pub.dartlang.org/packages/flutter_staggered_grid_view i SQLite per emmagatzemar les dades de les notes al dispositiu.



cv2 aconsegueix la mida de la imatge

A continuació es mostra un fragment de codi de pubspec.yaml * * amb les dependències requerides a la llista. Afegiu-los, deseu el fitxer i feu servir l'ordre flutter els paquets flutter aconsegueixen per resoldre les dependències acabades d'afegir.

dependencies: flutter: sdk: flutter cupertino_icons: ^0.1.2 flutter_staggered_grid_view: ^0.2.7 auto_size_text: ^1.1.2 sqflite: path: intl: ^0.15.7 share: ^0.6.1

Creeu una classe per a les notes. Necessitarem la funció ** toMap ** per a consultes de bases de dades.

class Note { int id; String title; String content; DateTime date_created; DateTime date_last_edited; Color note_color; int is_archived = 0; Note(this.id, this.title, this.content, this.date_created, this.date_last_edited,this.note_color); Map toMap(bool forUpdate) { var data = { // 'id': id, since id is auto incremented in the database we don't need to send it to the insert query. 'title': utf8.encode(title), 'content': utf8.encode( content ), 'date_created': epochFromDate( date_created ), 'date_last_edited': epochFromDate( date_last_edited ), 'note_color': note_color.value, 'is_archived': is_archived // for later use for integrating archiving }; if(forUpdate){ data['id'] = this.id; } return data; } // Converting the date time object into int representing seconds passed after midnight 1st Jan, 1970 UTC int epochFromDate(DateTime dt) { return dt.millisecondsSinceEpoch ~/ 1000; } void archiveThisNote(){ is_archived = 1; } }

Agafeu el codi de les consultes de bases de dades SQLite per a la classe de notes i la taula aquí .

Ara la casa de l'aplicació Material hauria de tenir un Bastida de HomePage.dart que hauria de tenir StaggeredGridView com a cos. A la AppBar del cadafal col·loqueu un botó d'acció per permetre a l'usuari alternar entre la visualització de llista i la visualització esglaonada. No us oblideu d’embolicar-hi el cos SafeArea , volem que l’aplicació sigui amigable als darrers telèfons.

La biblioteca de visualització esglaonada requereix un recompte d’eixos transversals per a la visualització que oferirem dinàmicament en funció de l’amplada de la mida de la pantalla. Això és necessari per indicar el nombre de visualitzacions de notes que volem mostrar una al costat de l’altra. En mode horitzontal en una pantalla de telèfon o tauleta, farem que organitzi 3 notes horitzontalment i 2 per a un telèfon en mode vertical.

import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import '../Models/Note.dart'; import '../Models/SqliteHandler.dart'; import '../Models/Utility.dart'; import '../Views/StaggeredTiles.dart'; import 'HomePage.dart'; class StaggeredGridPage extends StatefulWidget { final notesViewType; const StaggeredGridPage({Key key, this.notesViewType}) : super(key: key); @override _StaggeredGridPageState createState() => _StaggeredGridPageState(); } class _StaggeredGridPageState extends State { var noteDB = NotesDBHandler(); List _allNotesInQueryResult = []; viewType notesViewType ; @override void initState() { super.initState(); this.notesViewType = widget.notesViewType; } @override void setState(fn) { super.setState(fn); this.notesViewType = widget.notesViewType; } @override Widget build(BuildContext context) { GlobalKey _stagKey = GlobalKey(); if(CentralStation.updateNeeded) { retrieveAllNotesFromDatabase(); } return Container(child: Padding(padding: _paddingForView(context) , child: new StaggeredGridView.count(key: _stagKey, crossAxisSpacing: 6, mainAxisSpacing: 6, crossAxisCount: _colForStaggeredView(context), children: List.generate(_allNotesInQueryResult.length, (i){ return _tileGenerator(i); }), staggeredTiles: _tilesForView() , ), ) ); } int _colForStaggeredView(BuildContext context) { if (widget.notesViewType == viewType.List) { return 1; } // for width larger than 600, return 3 irrelevant of the orientation to accommodate more notes horizontally return MediaQuery.of(context).size.width > 600 ? 3 : 2 ; } List _tilesForView() { // Generate staggered tiles for the view based on the current preference. return List.generate(_allNotesInQueryResult.length,(index){ return StaggeredTile.fit( 1 ); } ) ; } EdgeInsets _paddingForView(BuildContext context){ double width = MediaQuery.of(context).size.width; double padding ; double top_bottom = 8; if (width > 500) { padding = ( width ) * 0.05 ; // 5% padding of width on both side } else { padding = 8; } return EdgeInsets.only(left: padding, right: padding, top: top_bottom, bottom: top_bottom); } MyStaggeredTile _tileGenerator(int i){ return MyStaggeredTile( Note( _allNotesInQueryResult[i]['id'], _allNotesInQueryResult[i]['title'] == null ? '' : utf8.decode(_allNotesInQueryResult[i]['title']), _allNotesInQueryResult[i]['content'] == null ? '' : utf8.decode(_allNotesInQueryResult[i]['content']), DateTime.fromMillisecondsSinceEpoch(_allNotesInQueryResult[i]['date_created'] * 1000), DateTime.fromMillisecondsSinceEpoch(_allNotesInQueryResult[i]['date_last_edited'] * 1000), Color(_allNotesInQueryResult[i]['note_color'] )) ); } void retrieveAllNotesFromDatabase() { // queries for all the notes from the database ordered by latest edited note. excludes archived notes. var _testData = noteDB.testSelect(); _testData.then((value){ setState(() { this._allNotesInQueryResult = value; CentralStation.updateNeeded = false; }); }); } }

Aquesta vista necessita mosaics per mostrar notes. El mosaic que dissenyem per a la visualització ha de previsualitzar el títol i el contingut de la nota. Per gestionar el text de diferent longitud a la fitxa, utilitzarem un biblioteca per crear una visualització de text que s'expandeixi automàticament. Només hem de definir el límit de línia i el widget s’expandirà automàticament per adaptar-lo al contingut fins a aquest límit.

Igual que segue a iOS i Intent a Android, per navegar entre les pàgines de Flutter que fem servir Navegador .

com canviar de versió de node
import 'package:flutter/material.dart'; import 'package:auto_size_text/auto_size_text.dart'; import '../ViewControllers/NotePage.dart'; import '../Models/Note.dart'; import '../Models/Utility.dart'; class MyStaggeredTile extends StatefulWidget { final Note note; MyStaggeredTile(this.note); @override _MyStaggeredTileState createState() => _MyStaggeredTileState(); } class _MyStaggeredTileState extends State { String _content ; double _fontSize ; Color tileColor ; String title; @override Widget build(BuildContext context) { _content = widget.note.content; _fontSize = _determineFontSizeForContent(); tileColor = widget.note.note_color; title = widget.note.title; return GestureDetector( onTap: ()=> _noteTapped(context), child: Container( decoration: BoxDecoration( border: tileColor == Colors.white ? Border.all(color: CentralStation.borderColor) : null, color: tileColor, borderRadius: BorderRadius.all(Radius.circular(8))), padding: EdgeInsets.all(8), child: constructChild(),) , ); } void _noteTapped(BuildContext ctx) { CentralStation.updateNeeded = false; Navigator.push(ctx, MaterialPageRoute(builder: (ctx) => NotePage(widget.note))); } Widget constructChild() { List contentsOfTiles = []; if(widget.note.title.length != 0) { contentsOfTiles.add( AutoSizeText(title, style: TextStyle(fontSize: _fontSize,fontWeight: FontWeight.bold), maxLines: widget.note.title.length == 0 ? 1 : 3, textScaleFactor: 1.5, ), ); contentsOfTiles.add(Divider(color: Colors.transparent,height: 6,),); } contentsOfTiles.add( AutoSizeText( _content, style: TextStyle(fontSize: _fontSize), maxLines: 10, textScaleFactor: 1.5,) ); return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: contentsOfTiles ); } double _determineFontSizeForContent() { int charCount = _content.length + widget.note.title.length ; double fontSize = 20 ; if (charCount > 110 ) { fontSize = 12; } else if (charCount > 80) { fontSize = 14; } else if (charCount > 50) { fontSize = 16; } else if (charCount > 20) { fontSize = 18; } return fontSize; } }

La rajola de la vista tindrà un aspecte semblant.

Tingueu en compte els quadres en visualització esglaonada a HomePage

Ara necessitem una vista per editar / crear una nota. que també tindrà diverses accions útils a l'AppBar per desfer, arxivar i molt més. Com més acció apareixerà un full inferior amb opcions com compartir, duplicar, suprimir permanentment i un selector de colors desplaçable horitzontalment amb el qual podrem canviar el color de fons d'aquesta nota en concret.

Segregarem els widgets NotePage, BottomSheet i ColorSlider en diferents classes i fitxers per mantenir el codi net i manejable. Per canviar el color de tots ells quan l’usuari en tria un de ColorSlider, hem d’actualitzar l’estat. Podem connectar aquests tres ginys mitjançant funcions de devolució de trucada per respondre als canvis perquè puguin actualitzar-se.

Flux de CallBack. El veureu en acció a continuació.

import 'package:flutter/material.dart'; class ColorSlider extends StatefulWidget { final void Function(Color) callBackColorTapped ; final Color noteColor ; ColorSlider({@required this.callBackColorTapped, @required this.noteColor}); @override _ColorSliderState createState() => _ColorSliderState(); } class _ColorSliderState extends State { final colors = [ Color(0xffffffff), // classic white Color(0xfff28b81), // light pink Color(0xfff7bd02), // yellow Color(0xfffbf476), // light yellow Color(0xffcdff90), // light green Color(0xffa7feeb), // turquoise Color(0xffcbf0f8), // light cyan Color(0xffafcbfa), // light blue Color(0xffd7aefc), // plum Color(0xfffbcfe9), // misty rose Color(0xffe6c9a9), // light brown Color(0xffe9eaee) // light gray ]; final Color borderColor = Color(0xffd3d3d3); final Color foregroundColor = Color(0xff595959); final _check = Icon(Icons.check); Color noteColor; int indexOfCurrentColor; @override void initState() { super.initState(); this.noteColor = widget.noteColor; indexOfCurrentColor = colors.indexOf(noteColor); } @override Widget build(BuildContext context) { return ListView( scrollDirection: Axis.horizontal, children: List.generate(colors.length, (index) { return GestureDetector( onTap: ()=> _colorChangeTapped(index), child: Padding( padding: EdgeInsets.only(left: 6, right: 6), child:Container( child: new CircleAvatar( child: _checkOrNot(index), foregroundColor: foregroundColor, backgroundColor: colors[index], ), width: 38.0, height: 38.0, padding: const EdgeInsets.all(1.0), // border width decoration: new BoxDecoration( color: borderColor, // border color shape: BoxShape.circle, ) ) ) ); }) ,); } void _colorChangeTapped(int indexOfColor) { setState(() { noteColor = colors[indexOfColor]; indexOfCurrentColor = indexOfColor; widget.callBackColorTapped(colors[indexOfColor]); }); } Widget _checkOrNot(int index){ if (indexOfCurrentColor == index) { return _check; } return null; } }

pirateria amb tutorial Python

També he afegit algunes funcions útils per desfer canvis, arxivar, compartir, duplicar i suprimir permanentment la nota.

# mobile-apps #flutter #ios #dart