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.