class: center, middle, inverse # ItbCalendar .footnote[Mateu Yábar] --- # Objectiu final .fullscreen70[![](exercicis/itbcalendar/screenshots/DayOfWeek_5x3_portrait.jpeg)] --- # Objectiu final .fullscreen70[![](exercicis/itbcalendar/screenshots/MpDetail_5x3_portrait.jpeg)] --- # Definicions inicials - Activity - Fragment - Arquitectura - ViewModel --- # Activity - Una Activity és un component de l'aplicació que conté una pantalla amb la qual els usuaris poden interactuar per realitzar una acció, com marcar un número de telèfon, fer una foto, enviar un correu electrònic o veure un mapa. - Una aplicació generalment consisteix en múltiples activitats vinculades de manera flexible entre si. --- # Fragment - Un fragment representa un comportament o una part de la interfície d'usuari d'una Activity. - Podeu combinar diversos fragments en una sola activitat. - Es pot pensar en un fragment com una secció modular d’una activitat. --- # App architecture - L’arquitectura d’aplicacions és una __manera de dissenyar__ les classes de les vostres aplicacions i les relacions entre elles, de manera que el codi estigui organitzat, funcioni bé en diversos escenaris i sigui fàcil treballar. - L’arquitectura d’aplicacions d’Android (usant Android Architecture Components) és similar al patró arquitectònic __MVVM__ (model-view-viewmodel) i és el que treballarem a classe. --- # UI controller - Un controlador d’UI és una classe basada en IU com ara __Activitat o Fragment__. - Un controlador d’UI __només__ ha de contenir una lògica que gestioni les __interaccions__ de la interfície d'usuari i del sistema operatiu com ara visualitzar visualitzacions i capturar l’entrada de l’usuari. - __No__ poseu __lògica de presa de decisions__, com la lògica que determina el text a mostrar, al controlador de la interfície d'usuari. --- # ViewModel - Un ViewModel __conté dades__ que es mostraran en un fragment o activitat associada al ViewModel. - Un ViewModel pot fer càlculs i transformacions simples de les dades per __preparar les dades__ que es mostren pel controlador de la interfície d'usuari. - En aquesta arquitectura, ViewModel realitza la __presa de decisions__. --- # Arquitectura .fullscreen70[![](img/view-viewmodel.png)] --- # Arquitectura .fullscreen70[![](img/repositories_architecture.png)] --- # Explicació en viu - Creació d'un projecte amb una Activity i un Fragment + ViewModel a l'Android Studio. - Visió del codi - Java - Xml - Execució --- # BoxModel .fullscreen70[![](img/box-model.png)] --- # Padding - android:padding specifies padding for all four edges of the view. - android:paddingTop specifies padding for the top edge. - android:paddingBottom specifies padding for the bottom edge. - android:paddingStart specifies padding for the "starting" edge of the view. - android:paddingEnd specifies padding for the "ending" edge of the view. - android:paddingLeft specifies padding for the left edge. - android:paddingRight specifies padding for the right edge. --- # Left-Right vs End-Start - LRT / RLT .fullscreen70[![](img/LRTvsRLT.png)] --- # Exemple LRT / RLT - Obrir l'aplicació de mapes a l'emulador. - Canvia l'idioma de l'emulador a Arab - No tanquis la finestra de preferencies! Després has de poder tornar a canviar l'idioma. - Mira els canvis de l'aplicació de mapes --- # Left-Right vs End-Start - LTR - start = left - end=right - RTL - start=right - end=left. --- # Left-Right vs End-Start - minSdkVersion >=17 - usa start i end - minSdkVersion <=16 - Posa les dues versions --- # Explicació en viu - ConstraintLayout - Constraints - GuideLines - https://developer.android.com/training/constraint-layout --- # Exercicis - creació del layout Fes els aprtats següents - Preparació del projecte - Layout simplificat de llistat de classes - Layout del detall d'una classe
--- # XML Resources - dimen - espais - dp - font-size - sp - font - color - style --- # Exercicis - recursos - Extreu els recursos del layout
--- # Android navigation Component - Ens ajuda a navegar entre Fragments - https://developer.android.com/guide/navigation/navigation-getting-started --- # Navegació - Gradle ## Projecte ```gradle buildscript { dependencies { def nav_version = "2.1.0" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } } ``` --- # Navegació - Gradle ## Modul ```gradle // a l'inici del fitxer apply plugin: "androidx.navigation.safeargs" dependencies { def nav_version = "2.1.0" implementation "androidx.navigation:navigation-fragment:$nav_version" implementation "androidx.navigation:navigation-ui:$nav_version" } ``` --- # Navegació - crear fitxer - Podem crear una nova navegació amb: - botó dret a carpeta res - new -> Android Resource File - Indicar que és navació - Per defecte l'anomenarem nav_graph --- # Navegació canvis a l'Activity - xml ```xml
``` --- # Navegació canvis a l'Activity - java - Si has creat l'Activity com a Activity+Fragment eliminar ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); // Afegir si es vol mostrar el 'back' a la actionBar NavigationUI.setupActionBarWithNavController(this,findNavController(this, R.id.nav_host_fragment)); } @Override public boolean onSupportNavigateUp() { // Afegir si es vol mostrar el 'back' a la actionBar return findNavController(this, R.id.nav_host_fragment).navigateUp(); } ``` --- # Navegació - navegar a un fragment Per navegar d'un fragment a un altre podem usar: ```java Navigation.findNavController(view).navigate(R.id.theNameOfTheAction); ``` --- # Navegació - pas de parametres - Podem definir que un fragment necessita d'un parametre d'entrada - Per exemple id d'un element a mostrar - Es defineix al XML --- # Navegació - navegar a un fragment amb parametres ```java int parametreExemple = 1; NomDelFragmentDirections.NomDeLaAction action = NomDelFragmentDirections.nomDeLaAction(parametreExemple); Navigation.findNavController(itemView).navigate(action); ``` --- # Navegació - obtenció del parametre Desde el Fragment destí podem usar ```java int parametreExemple = NomDelFragmentDestiArgs.fromBundle(getArguments()).getParametreExemple(); ``` --- # Exercicis - Navegació - Fes l'apartat: _Afegeix la navegació_
.footnote[Notes: recordatori findViewById, ViewModel i explicació de classes] --- # Exercicis - ViewModel - Fes l'apartat: _Mostra els detalls de la classe actual_
.footnote[Notes: recordatori findViewById, ViewModel i explicació de classes] --- # RecycerView - Permet mostrar llistes d'elements d'una forma senzilla i eficient. --- # RecycerView - Elements - RecyclerView - RecyclerView.Adapter - RecyclerView.ViewHolder - LayoutManagers --- # RecycerView - estructura .fullscreen70[![](img/RecyclerView.png)] --- # RecycerView - Gradle ```gradle dependencies { ... implementation 'androidx.recyclerview:recyclerview:1.0.0' } ``` --- # RecycerView - XML - Crear layout nou amb la vista d'un item - Afegir el RecyclerView al Layout fragment ```xml
``` --- # RecyclerView.Adapter ```java - RecyclerView.Adapter
- public int getItemCount(); - public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) - public void onBindViewHolder(MyViewHolder holder, int position) { ``` --- # RecyclerView.Adapter - data ```java public class MyAdapter extends RecyclerView.Adapter
{ private List
dataSet; public MyAdapter(List
dataSet) { this.dataSet = dataSet; } // Return the size of your dataset @Override public int getItemCount() { return mDataset.length; } } ``` --- # RecyclerView.Adapter - ViewHolder ``` public class MyAdapter extends RecyclerView.Adapter
{ public static class MyViewHolder extends RecyclerView.ViewHolder { public TextView textView; public MyViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.someId); } } } ``` --- # RecyclerView.Adapter - funcions ```java public class MyAdapter extends RecyclerView.Adapter
{ @Override public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view TextView v = (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.my_text_view, parent, false); return new MyViewHolder(v); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { // - replace the contents of the view with data holder.textView.setText(mDataset.get(position).toString()); } } ``` --- # Fragment / Activity ```java public class MyFragment extends Fragment { private RecyclerView recyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager layoutManager; @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); recyclerView = (RecyclerView) view.findViewById(R.id.my_recycler_view); // use if changes in content do not change the size of the RecyclerView recyclerView.setHasFixedSize(true); layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); mAdapter = new MyAdapter(myData); recyclerView.setAdapter(mAdapter); } } ``` --- # RecyclerView - onClick - Adapter ```java public class MyAdapter extends RecyclerView.Adapter
{ OnItemClickListener onItemClickListener ; public interface OnItemClickListener { void onItemClicked(SomeClass someClass); } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } ``` --- # RecyclerView - onClick - ViewHolder ```java public static class MyViewHolder extends RecyclerView.ViewHolder { public MyViewHolder(@NonNull View itemView) { // (...) itemView.setOnItemClickListener(this::itemClicked); } } public void itemClicked(View view){ SomeClass someClass = dataSet.get(getAdapterPosition()); onItemClickListener.onItemClicked(mpSession); } } ``` --- # RecyclerView - onClick - Fragment / Activity ```java public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { // ... mAdapter = new MyAdapter(myData); mAdapter.setOnItemClickListener(this::myFunctionName); } ``` --- # RecyclerView - Exemple [SampleRecylcerView.zip](examples/SampleRecylcerView.zip) --- # RecycerView - Bibliografia - Guia - https://guides.codepath.com/android/using-the-recyclerview - Documnetació oficial - https://developer.android.com/guide/topics/ui/layout/recyclerview --- # Tests a RecyclerView ```gradle androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0' ``` - scrollTo() - Scrolls to the matched View. - scrollToHolder() - Scrolls to the matched View Holder. - scrollToPosition() - Scrolls to a specific position. - actionOnHolderItem() - Performs a View Action on a matched View Holder. - actionOnItem() - Performs a View Action on a matched View. - actionOnItemAtPosition() - Performs a ViewAction on a view at a specific position. --- # Tests a RecyclerView ```java onView(withId(R.id.myRecyclerView)) .perform(actionOnItemAtPosition(0,click())); ``` --- # Exericicis - Acaba el projecte