Ejemplo: Notes app
Creación de una aplicación de notas usando Room y MVVM
The Notes App – Prerequisites & XML Design
– Packages
1. adapters: NoteAdapter
2. db: NoteDao & NoteDatabase.
3. model: Note.
4. repository: NoteRepository.
5. viewmodel: MainActivity, NoteViewModel & NoteViewModelFactory
6. fragments: AddNoteFragment, EditNoteFragment & HomeFragment
– Resources
1. drawable: add, delete, done, search, emptybkg image & pink_border.xml
2. font: poppins
3. layout: activity_main, fragment_add_note, fragment_edit_note, fragment_home, note_layout.xml
4. menu: home_menu, menu_add_note, menu_edit_note.xml
5. navigation: nav_graph
6. values: colors, strings, themes.xml
7. gradle: project gradle & module gradle
Crear los fragments para añadir y editar notas
fragment_add_note.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".NewNoteFragment" android:padding="12dp"> <TextView android:id="@+id/addNoteHeading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginTop="16dp" android:text="Add Note." android:textColor="@color/red" android:textSize="24sp" android:textStyle="bold" /> <EditText android:id="@+id/addNoteTitle" android:layout_width="match_parent" android:layout_height="60dp" android:hint="Enter the title" android:padding="12dp" android:textSize="20sp" android:layout_below="@id/addNoteHeading" android:background="@drawable/pink_border" android:layout_marginTop="16dp" android:maxLines="1" /> <EditText android:id="@+id/addNoteDesc" android:layout_width="match_parent" android:layout_height="match_parent" android:hint="Enter the description" android:gravity="top" android:padding="12dp" android:textSize="18sp" android:background="@drawable/pink_border" android:layout_below="@id/addNoteTitle" android:layout_marginTop="12dp" /> </RelativeLayout> </layout>
AddNoteFragment
class AddNoteFragment : Fragment(R.layout.fragment_add_note), MenuProvider { private var addNoteBinding: FragmentAddNoteBinding? = null private val binding get() = addNoteBinding!! private lateinit var notesViewModel: NoteViewModel private lateinit var addNoteView: View override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment addNoteBinding = FragmentAddNoteBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val menuHost: MenuHost = requireActivity() menuHost.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) notesViewModel = (activity as MainActivity).noteViewModel addNoteView = view } private fun saveNote(view: View){ val noteTitle = binding.addNoteTitle.text.toString().trim() val noteDesc = binding.addNoteDesc.text.toString().trim() if (noteTitle.isNotEmpty()){ val note = Note(0, noteTitle, noteDesc) notesViewModel.addNote(note) Toast.makeText(addNoteView.context, "Note Saved", Toast.LENGTH_SHORT).show() view.findNavController().popBackStack(R.id.homeFragment, false) } else { Toast.makeText(addNoteView.context, "Please enter note title", Toast.LENGTH_SHORT).show() } } override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menu.clear() menuInflater.inflate(R.menu.menu_add_note, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when(menuItem.itemId){ R.id.saveMenu -> { saveNote(addNoteView) true } else -> false } } override fun onDestroy() { super.onDestroy() addNoteBinding = null } }
fragment_edit_note
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="12dp" tools:context=".UpdateNoteFragment"> <TextView android:id="@+id/editNoteHeading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginTop="16dp" android:text="Edit Note." android:textStyle="bold" android:textColor="@color/red" android:textSize="24sp" /> <EditText android:id="@+id/editNoteTitle" android:layout_width="match_parent" android:layout_height="60dp" android:hint="Enter the title" android:padding="12dp" android:textSize="20sp" android:layout_below="@id/editNoteHeading" android:background="@drawable/pink_border" android:layout_marginTop="16dp" android:maxLines="1" /> <EditText android:id="@+id/editNoteDesc" android:layout_width="match_parent" android:layout_height="match_parent" android:hint="Enter the description" android:gravity="top" android:padding="12dp" android:textSize="18sp" android:background="@drawable/pink_border" android:layout_below="@id/editNoteTitle" android:layout_marginTop="12dp" /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/editNoteFab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="20dp" android:layout_marginBottom="20dp" android:clickable="true" android:backgroundTint="@color/pink" android:tintMode="@color/white" android:src="@drawable/baseline_done_24" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:contentDescription="editFab" /> </RelativeLayout> </layout>
EditNoteFragment
class EditNoteFragment : Fragment(R.layout.fragment_edit_note), MenuProvider { private var editNoteBinding: FragmentEditNoteBinding? = null private val binding get() = editNoteBinding!! private lateinit var notesViewModel: NoteViewModel private lateinit var currentNote: Note private val args: EditNoteFragmentArgs by navArgs() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment editNoteBinding = FragmentEditNoteBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val menuHost: MenuHost = requireActivity() menuHost.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) notesViewModel = (activity as MainActivity).noteViewModel currentNote = args.note!! binding.editNoteTitle.setText(currentNote.noteTitle) binding.editNoteDesc.setText(currentNote.noteDesc) binding.editNoteFab.setOnClickListener { val noteTitle = binding.editNoteTitle.text.toString().trim() val noteDesc = binding.editNoteDesc.text.toString().trim() if (noteTitle.isNotEmpty()){ val note = Note(currentNote.id, noteTitle, noteDesc) notesViewModel.updateNote(note) view.findNavController().popBackStack(R.id.homeFragment, false) } else { Toast.makeText(context, " Please enter note title", Toast.LENGTH_SHORT).show() } } } private fun deleteNote(){ AlertDialog.Builder(activity).apply { setTitle("Delete Note") setMessage("Do you want to delete this note?") setPositiveButton("Delete"){_,_ -> notesViewModel.deleteNote(currentNote) Toast.makeText(context, " Note Deleted", Toast.LENGTH_SHORT).show() view?.findNavController()?.popBackStack(R.id.homeFragment, false) } setNegativeButton("Cancel", null) }.create().show() } override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menu.clear() menuInflater.inflate(R.menu.menu_edit_note, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when(menuItem.itemId){ R.id.deleteMenu -> { deleteNote() true } else -> false } } override fun onDestroy() { super.onDestroy() editNoteBinding = null } }
Crear la navegación entre fragments
Navigation graph
NavHost
NavController
otra forma de crear la navegación
añadir el contenedor de fragments en el activity_main
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.fragment.app.FragmentContainerView android:id="@+id/fragmentContainerView" android:name="androidx.navigation.fragment.NavHostFragment" tools:layout="@layout/fragment_home" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="1dp" android:layout_marginTop="1dp" android:layout_marginEnd="1dp" android:layout_marginBottom="1dp" app:defaultNavHost="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/nav_graph" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
añadir los 3 fragments y la comunicación entre ellos
tools:layout="@layout/fragment_home" tools:layout="@layout/fragment_add_note" tools:layout="@layout/fragment_edit_note"
navigation/nav_graph.xml
<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" app:startDestination="@id/homeFragment"> <fragment android:id="@+id/homeFragment" android:name="com.example.notesapp.fragments.HomeFragment" android:label="HomeFragment" tools:layout="@layout/fragment_home"> <action android:id="@+id/action_homeFragment_to_addNoteFragment" app:destination="@id/addNoteFragment" /> <action android:id="@+id/action_homeFragment_to_editNoteFragment" app:destination="@id/editNoteFragment" /> </fragment> <fragment android:id="@+id/addNoteFragment" android:name="com.example.notesapp.fragments.AddNoteFragment" android:label="AddNoteFragment" tools:layout="@layout/fragment_add_note"> <action android:id="@+id/action_addNoteFragment_to_homeFragment" app:destination="@id/homeFragment" /> </fragment> <fragment android:id="@+id/editNoteFragment" android:name="com.example.notesapp.fragments.EditNoteFragment" android:label="EditNoteFragment" tools:layout="@layout/fragment_edit_note"> <action android:id="@+id/action_editNoteFragment_to_homeFragment" app:destination="@id/homeFragment" /> <argument android:name="Note" app:argType="com.example.notesapp.model.Note" app:nullable="true" /> </fragment> </navigation>
modificar el listener del botón flotante en HomeFragment
binding.addNoteFab.setOnClickListener { it.findNavController().navigate(R.id.action_homeFragment_to_addNoteFragment) // Toast.makeText(context, "Add Button Clicked", Toast.LENGTH_SHORT).show() }
modificar el listener del click en un elemento de la lista en el adapter
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) { val currentNote = differ.currentList[position] holder.itemBinding.noteTitle.text = currentNote.noteTitle holder.itemBinding.noteDesc.text = currentNote.noteDesc holder.itemView.setOnClickListener { val direction = HomeFragmentDirections.actionHomeFragmentToEditNoteFragment(currentNote) it.findNavController().navigate(direction) } }
Tarea presencial de la unidad 3
Más información:
Deja una respuesta
Lo siento, debes estar conectado para publicar un comentario.