{"id":201,"date":"2020-06-14T23:21:06","date_gmt":"2020-06-15T04:21:06","guid":{"rendered":"https:\/\/80bits.blog\/?p=201"},"modified":"2020-07-25T18:56:27","modified_gmt":"2020-07-25T23:56:27","slug":"calendario-en-flutter-paquete-g-simple-calendar-0-0-1","status":"publish","type":"post","link":"https:\/\/80bits.blog\/index.php\/2020\/06\/14\/calendario-en-flutter-paquete-g-simple-calendar-0-0-1\/","title":{"rendered":"Calendario en flutter. Paquete g_simple_calendar 0.0.1"},"content":{"rendered":"\n<p>Para poder mostrar un calendario en flutter existe, la funci\u00f3n <em><a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/material\/showDatePicker.html\" target=\"_blank\">showDatePicker<\/a><\/em> , la cual esta bastante bien, pero personalmente no me gusta y le hacia falta una caracter\u00edstica que buscaba que es: fijar solo un mes de determinado a\u00f1o y el poder seleccionar un rango de d\u00edas. <\/p>\n\n\n\n<p>Vi unos paquetes muy buenos para implementar un calendario, como este <a rel=\"noreferrer noopener\" href=\"https:\/\/pub.dev\/packages\/flutter_calendar_carousel\" target=\"_blank\">flutter_calendar_carousel<\/a>, si buscan un calendario bastante bonito y funcional, este podr\u00eda ser el que quieren, pero a este ultimo le hacia falta seleccionar el rango de d\u00edas.<\/p>\n\n\n\n<p>Entonces se me ocurri\u00f3 hacer uno parecido al <em>calendar_caroucel<\/em>, mas simple y con opci\u00f3n de seleccionar un el rango de d\u00edas.<\/p>\n\n\n\n<p>Siguiendo mi aprendizaje sobre flutter, como este de <a rel=\"noreferrer noopener\" href=\"https:\/\/80bits.blog\/index.php\/2020\/04\/30\/atomic-design-con-flutter-metodologia-de-diseno\/\" target=\"_blank\">aqu\u00ed<\/a>, les explico lo que hice a continuaci\u00f3n. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Desarrollo del calendario<\/h2>\n\n\n\n<p><em>Nota: Solo quieres usar el componente? entonces ve directo al paquete de flutter <a rel=\"noreferrer noopener\" href=\"https:\/\/pub.dev\/packages\/g_simple_calendar\" target=\"_blank\">aqu\u00ed<\/a>.<\/em><\/p>\n\n\n\n<p>El widget con fecha del mes de Junio 2020 se ve as\u00ed:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"467\" height=\"864\" src=\"https:\/\/80bits.blog\/wp-content\/uploads\/2020\/06\/calendar_flutter_cap1.png\" alt=\"Vista previa del calendario\" class=\"wp-image-210\"\/><\/figure>\n\n\n\n<p>Como se ve la organizaci\u00f3n de los d\u00edas esta de este modo: Lunes, Martes, Mi\u00e9rcoles, Jueves, Viernes, S\u00e1bado, Domingo.<\/p>\n\n\n\n<p>Lo programe de este modo por que la funci\u00f3n para obtener el d\u00eda de la semana en dart empieza por el d\u00eda lunes (<a href=\"https:\/\/es.wikipedia.org\/wiki\/ISO_8601\" target=\"_blank\" rel=\"noreferrer noopener\">ISO 8601<\/a>) y no quise liarme con eso, ejemplo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">int year = DateTime(2020,6,1).year;\u2029\nint month = DateTime(2020,6,1).month;\u2029\nDateTime initDate = DateTime(2020,6,1);\u2029\nint totalDays = lastDayOfMonth(initDate).day;\/\/30\u2029\nint weekday = initDate.weekday;\/\/1 dia lunes<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Obtener los d\u00edas del Mes<\/h2>\n\n\n\n<p>Para obtener el dato <em>totalDays<\/em>, me base en el siguiente algoritmo:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"656\" height=\"276\" src=\"https:\/\/80bits.blog\/wp-content\/uploads\/2020\/06\/lastDayOfMonth.png\" alt=\"lastDayOfMonth\" class=\"wp-image-263\"\/><\/figure><\/div>\n\n\n\n<p>Basado en lo anterior se obtiene las siguientes conclusiones:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>La primer columna de la tabla empieza el d\u00eda lunes y la ultima el viernes.<\/li><li>El texto de los d\u00edas deber\u00e1 ir dentro de la tabla, igual que los n\u00fameros, entonces..<\/li><li>la tabla sera de 7&#215;7, con un total de 49 celdas.<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Algoritmo<\/h3>\n\n\n\n<p>Todos los datos de la tabla estar\u00e1n en un vector que luego se partira cada 7 posiciones, de esta manera:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\">L<\/td><td class=\"has-text-align-center\" data-align=\"center\">M<\/td><td class=\"has-text-align-center\" data-align=\"center\">M<\/td><td class=\"has-text-align-center\" data-align=\"center\">.<\/td><td class=\"has-text-align-center\" data-align=\"center\">.<\/td><td class=\"has-text-align-center\" data-align=\"center\">.<\/td><td class=\"has-text-align-center\" data-align=\"center\">.<\/td><td class=\"has-text-align-center\" data-align=\"center\">30<\/td><td class=\"has-text-align-center\" data-align=\"center\">31<\/td><td class=\"has-text-align-center\" data-align=\"center\">n=42<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Tenemos dos Widgets que podemos usar para posicionar elementos verticales <a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/Column-class.html\" target=\"_blank\">Column()<\/a> y horizontales <a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/Row-class.html\" target=\"_blank\">Row()<\/a><\/p>\n\n\n\n<p>El dise\u00f1o entonces quedar\u00eda de la siguiente manera:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"395\" height=\"474\" src=\"https:\/\/80bits.blog\/wp-content\/uploads\/2020\/06\/simple_calendar_code1.png\" alt=\"c\u00f3digo de columnas y filas\" class=\"wp-image-214\"\/><\/figure>\n\n\n\n<p>As\u00ed tendremos un dise\u00f1o de una tabla en flutter, en la imagen hay 7 elementos dentro de un Row(), los primeros 7 pertenecen a las letras de los d\u00edas de la semana y los siguientes ser\u00e1n los d\u00edas y\/o espacios en blanco en caso de que, o bien el d\u00eda 1 empiece en un d\u00eda que no sea lunes o el d\u00eda 31 termine en un d\u00eda que no sea domingo, y todo eso dentro de un elemento Column().<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Llenar vector<\/h3>\n\n\n\n<p>Ya comente que los datos se guardaran en un vector de tama\u00f1o N=42, este vector se partir\u00e1 en 6 secciones.<\/p>\n\n\n\n<p>El vector que se declara es de este tipo: <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">List&lt;Widget&gt; _celds = List&lt;Widget&gt;();<\/pre>\n\n\n\n<p>Las primeras posiciones sera el texto de los d\u00edas, ejemplo:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\">L<\/td><td class=\"has-text-align-center\" data-align=\"center\">M<\/td><td class=\"has-text-align-center\" data-align=\"center\">M<\/td><td class=\"has-text-align-center\" data-align=\"center\">M<\/td><td class=\"has-text-align-center\" data-align=\"center\">J<\/td><td class=\"has-text-align-center\" data-align=\"center\">V<\/td><td class=\"has-text-align-center\" data-align=\"center\">S<\/td><td class=\"has-text-align-center\" data-align=\"center\">D<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Estas est\u00e1n hardcode dentro del c\u00f3digo, cosa que pienso cambiar despu\u00e9s ya que las letras est\u00e1n en Espa\u00f1ol y quisiera soportar el ingles.<\/p>\n\n\n\n<p>Una vez agregadas las letras, nos queda llenar los d\u00edas del mes, para ello hago una comprobaci\u00f3n al inicio y otra al final. <\/p>\n\n\n\n<p>Los d\u00edas del mes son de tipo <a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/material\/FlatButton-class.html\" target=\"_blank\">FlatButton<\/a>, esto para que cada d\u00eda, tenga un evento click y pueda saber que d\u00eda estoy seleccionando.<\/p>\n\n\n\n<p>Inicio, si el d\u00eda 1 del mes establecido empieza en un d\u00eda que no sea lunes, entonces el vector se llena, N posiciones con texto vaci\u00f3, hasta <em>weekday-1.<\/em><\/p>\n\n\n\n<p>Comprobaci\u00f3n final, si el d\u00eda ultimo del mes establecido es menor al d\u00eda viernes, entonces se termina de llenar el vector hasta la posici\u00f3n 42, en un ciclo que empieza por la posici\u00f3n <em>totalDays<\/em>.<\/p>\n\n\n\n<p>En medio de esas dos comprobaciones simplemente se llena el vector desde el d\u00eda 1 hasta el d\u00eda <em>totalDays<\/em>.<\/p>\n\n\n\n<p>Una vez que este el vector este lleno, lo que hice fue ir partiendo el vector cada 7 posiciones y tomando 7 elementos, (aqu\u00ed son 7 debido a que los vectores empiezan en 0 y en tama\u00f1o es es N-1 ).<\/p>\n\n\n\n<p>Como el vector es de tipo List, en dart existe unas funciones para trabajar con vectores que utilize, para este caso son <a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/dart-core\/Iterable\/skip.html\" target=\"_blank\">skip()<\/a> y <a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/package-async_async\/StreamQueue\/take.html\" target=\"_blank\">take()<\/a><\/p>\n\n\n\n<p>Skip(), lo que hace es que omite N elementos dentro de una secuencia de elementos.<\/p>\n\n\n\n<p>take(), toma N elementos dentro de la secuencia de elementos empezando por el primer elemento.<\/p>\n\n\n\n<p>Al final para armar todos los elementos tipo Row(), que necesito meter en la Column(), hago lo que se muestra en la siguiente imagen:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"572\" height=\"348\" src=\"https:\/\/80bits.blog\/wp-content\/uploads\/2020\/06\/simple_calendar_code2.png\" alt=\"simple_calendar_code2\" class=\"wp-image-217\"\/><\/figure>\n\n\n\n<p>Hay una lista ahi que tiene por nombre rows y no es mas que una lista de Row() elementos.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">List&lt;Row&gt; rows = List&lt;Row&gt;();<\/pre>\n\n\n\n<p>Al final incluso en el c\u00f3digo tengo harcode la parte de agregar a Column(), los Row(), ya que que la cantidad exacta que se tiene que agregar que son 6.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/80bits.blog\/wp-content\/uploads\/2020\/06\/simple_calendar_code3.png\" alt=\"simple_calendar_code3\" class=\"wp-image-219\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Seleccionar rango de d\u00edas <\/h3>\n\n\n\n<p>Como mencione lineas atr\u00e1s, cada celda que contiene un d\u00eda del mes es de tipo FlatButton, por lo que este reaccionara al momento de hacer touch en cualquiera de ellos.<\/p>\n\n\n\n<p>Dentro del c\u00f3digo hay un m\u00e9todo que se llama <em>_celdButton<\/em>, este metodo se encarga de generar cada boton de un numero del mes, y se configura para que reaccione al evento onPressed.<\/p>\n\n\n\n<p>Dentro de los par\u00e1metros que recibe el elemento hay uno que se llama <em>value<\/em>, y no es mas que el valor del numero de d\u00eda que le corresponde.<\/p>\n\n\n\n<p>El evento onPressed dentro tiene implementada una function llamada: <em>_onPressedceld<\/em>, esta es una funci\u00f3n declarada en la clase y que recibe el valor: <em>value<\/em>.<\/p>\n\n\n\n<p>La funci\u00f3n implementa un algoritmo que recrea el la vista cada vez que se toca una celda\/d\u00eda, pero con la diferencia de que, dentro del m\u00e9todo, se aplican valores dependiendo de lo siguiente:<\/p>\n\n\n\n<p><strong>Primera vez <\/strong>que se toco una celda, se le pasa un valor a la variable <em>_selectedRange<\/em>, que es un listado de enteros <em>List&lt;int&gt;<\/em>, que determinara desde donde se pintara el rango de fechas. Para esta parte solo se agrega un valor. <\/p>\n\n\n\n<p><strong>Segunda vez,<\/strong> se determina si, la posici\u00f3n que se toco es mayor a la posicion que se tiene ya almacenada en <em>_selectedRange<\/em>, si es as\u00ed quiere decir que se toco dos d\u00edas uno menor y otro mayor, y se procede a pintar esos dias.<\/p>\n\n\n\n<p>Posteriormente se dispara un evento llamado <em>onRangeSelected<\/em>, este pasa el rango de d\u00edas seleccionado a un evento que se puede obtener por fuera del widget, para as\u00ed quien lo implemente pueda obtener los valores seleccionados.<\/p>\n\n\n\n<p><em>Nota: Lo anterior debido a la arquitectura de flutter en donde no puedo instaciar m\u00e9todos o propiedades que pueda usar fuera del Widget, ya que es de tipo <a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/StatefulWidget-class.html\" target=\"_blank\">StatefulWidget<\/a> y la l\u00f3gica reside en una clase privada de tipo <a rel=\"noreferrer noopener\" href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/State-class.html\" target=\"_blank\">State<\/a>, a la cual no se deberia poder acceder de ninguna manera mas que mediante el padre que es StatefulWidget.<\/em><\/p>\n\n\n\n<p>Ejemplo: si la primera vez se toca el d\u00eda 10 y despu\u00e9s el d\u00eda 12, entonces se pintan en la primera vuelta, el d\u00eda 10 y en la segunda los d\u00edas: 10,11,12.<\/p>\n\n\n\n<p><strong>Tercera vez<\/strong>, aqu\u00ed lo que se hace es limpiar el vector con los valores seleccionados, para regenerar el widget sin d\u00edas seleccionados, y despu\u00e9s pasar el valor mediante <em>onRangeSelected<\/em> nuevamente para avisar que no hay valores seleccionados.<\/p>\n\n\n\n<p>Aqu\u00ed pueden ver una animaci\u00f3n del calendario en flutter<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"360\" height=\"638\" src=\"https:\/\/80bits.blog\/wp-content\/uploads\/2020\/06\/simple_calendar_anin1.gif\" alt=\"vista previa del funcionamiento del calendario\" class=\"wp-image-222\"\/><\/figure>\n\n\n\n<p>Para pintar una sola celda, mando a llamar a la funci\u00f3n<em> _buildDesign<\/em>, lo que hace esta funci\u00f3n es recrear una y otra vez el widget completo para pintar una o mas celdas.<\/p>\n\n\n\n<p><em>Nota: Estoy analizando la mejor manera de hacer esto, para no tener que crear cada vez el widget completo, aun que en celulares recientes no he tenido problemas de rendimiento.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Version 0.0.1<\/h2>\n\n\n\n<p>Hay mas cosas dentro del c\u00f3digo que pase por alto aqu\u00ed, que si las sigo comentando la publicaci\u00f3n se har\u00eda aun mas extensa de lo que ya es, pero si les interesa saber, puede revisar el c\u00f3digo, que esta publicado en github.<\/p>\n\n\n\n<p>Esta es una version muy preliminar pero totalmente funcional, que espero mejorar en cuanto tenga la oportunidad.<\/p>\n\n\n\n<p>Tambi\u00e9n es el primer c\u00f3digo que subo a <a rel=\"noreferrer noopener\" href=\"https:\/\/pub.dev\/\" target=\"_blank\">pub.dev<\/a>, este es el repositorio de paquetes de flutter.<\/p>\n\n\n\n<p>Si quieres ver los par\u00e1metros para poder implementar el widget, revisa la documentaci\u00f3n en pub.dev<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cosas a mejorar<\/h3>\n\n\n\n<p>Dentro de este proyecto hay muchas cosas a mejorar y refactorizar a nivel c\u00f3digo. <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>C\u00f3digo que no se utiliza. Hay partes de c\u00f3digo y variables que pueden quitarse.<\/li><li>Implementar los d\u00edas de la semana, por lo menos en idioma ingles. El nombre del mes que se ve en la parte superior ya soporta la localizaci\u00f3n, no as\u00ed los d\u00edas, que esta hardcode.<\/li><li>Implementar pintado de d\u00edas por default. Esto es que si quieres que la vista se implemente con determinados d\u00edas coloreados se pueda hacer.<\/li><li>Bloque de d\u00edas. Que se implemente con los d\u00edas espec\u00edficos bloqueados, esto es que no se puedan seleccionar.<\/li><li>Buscar una mejor manera de pintar las celdas para no rehacer el widget cada vez.<\/li><\/ul>\n\n\n\n<p>Si se te ocurre una funcionalidad adicional, no dudes ponerla en los comentarios o en los issues de github, o mejor aun edita el c\u00f3digo.<\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/pub.dev\/packages\/g_simple_calendar\" target=\"_blank\">g_simple_calendar (pub.dev)<\/a><\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/genitalico\/g_simple_calendar\" target=\"_blank\">C\u00f3digo en gihub.<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/unsplash.com\/photos\/tG4waP7YiAg\" target=\"_blank\" rel=\"noreferrer noopener\">Imagen de portada<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Simple calendar, es una implementaci\u00f3n de un calendario fijo para flutter, con la funcionalidad de seleccionar un rango de d\u00edas.<\/p>\n","protected":false},"author":1,"featured_media":205,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[7,21,23,22],"tags":[48,47,25,24],"class_list":["post-201","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-apps","category-dart","category-flutter","category-frameworks","tag-app","tag-calendar","tag-dart","tag-flutter"],"jetpack_featured_media_url":"https:\/\/80bits.blog\/wp-content\/uploads\/2020\/06\/nathan-dumlao-tG4waP7YiAg-unsplash.jpg","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/posts\/201","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/comments?post=201"}],"version-history":[{"count":57,"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/posts\/201\/revisions"}],"predecessor-version":[{"id":271,"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/posts\/201\/revisions\/271"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/media\/205"}],"wp:attachment":[{"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/media?parent=201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/categories?post=201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/80bits.blog\/index.php\/wp-json\/wp\/v2\/tags?post=201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}