Redes Sociais
 Telegram  YouTube
Como agrupar resultados na RecyclerView com Kotlin
8 de abril de 2020

Neste tutorial vou demonstrar como agrupar os resultados em uma RecyclerView na linguagem Kotlin utilizando assim um título para cada grupo.

Para este exemplo vou fazer um aplicativo que recebe o nome e o emprego e cria grupos de acordo com o emprego na RecyclerView.

O aplicativo vai ficar como a seguinte imagem.

Como agrupar resultados na RecyclerView com Kotlin
RecyclerView em grupos.

Primeiramente vamos criar um projeto vazio(Empty) para começar a programar.





Montando a base

A primeira coisa a ser feita logo após a criação do projeto é importar no gladle a biblioteca do RecyclerView e Material Design.

dependencies {
    ...
    // RecyclerView
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    // Material Design
    implementation 'com.google.android.material:material:1.2.0-alpha01'
}

Vamos então sincronizar nosso gradle clicando na parte superior direita em Sync Now como mostra na imagem a seguir para adicionar as bibliotecas ao nosso projeto.

Como agrupar resultados na RecyclerView com Kotlin
Sincronizando gradle.

Logo depois de ter adicionado o RecyclerView e Material Design ao gradle vamos fazer os arquivos xml referentes ao background que iremos utilizar.

Portanto são 3 arquivos background_item_bottom.xml, background_item_middle.xml e background_item_top.xml que serão criados na pasta drawable como descritos a seguir.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="@color/white"/>
            <corners android:bottomLeftRadius="5dp"
                android:bottomRightRadius="5dp"/>
        </shape>
    </item>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="@color/white"/>
        </shape>
    </item>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="@color/white"/>
            <corners android:topLeftRadius="5dp"
                    android:topRightRadius="5dp"/>
        </shape>
    </item>
</selector>

Logo após ter feito os arquivos que vamos usar em nosso background dos grupos vamos já deixar certo os arquivos strings.xml e colors.xml.

Segue o código dos dois arquivos citados.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#6200EE</color>
    <color name="colorPrimaryDark">#3700B3</color>
    <color name="colorAccent">#03DAC5</color>

    <color name="black">#000</color>
    <color name="blue">#17267B</color>
    <color name="gray">#d3d3d3</color>
    <color name="white">#FFF</color>
</resources>
<resources>
    <string name="app_name">RecyclerView Group</string>

    <string name="add_person">Adicionar Pessoa</string>
    <string name="name">Nome</string>
    <string name="job">Emprego</string>
    <string name="add">Adicionar</string>
    <string name="cancel">Cancelar</string>
    <string name="empty_name_or_job">Nome ou Emprego está vazio.</string>
</resources>

Com a nossa base do aplicativo pronta vamos agora criar uma nova activity vazia(Empty) com o nome de AddPersonActivity e seu respectivo layout xml.

E para terminar a base vamos adicionar 2(dois) packages com o nome de adapter e model.

Logo após ter criado os packages vamos criar um arquivo de model com o nome de Person dentro do package model com o seguinte código.

package br.com.uware.recyclerviewgroup.model

data class Person(
    var name: String = "",
    var job: String = ""
)




Layouts

Então vamos criar um arquivo de layout com o nome de content_person.xml com o seguinte código para ser usado em nossa RecyclerView.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:layout_marginStart="16dp"
    android:layout_marginEnd="16dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_weight="1">
        <TextView
            android:id="@+id/tvAdpJob"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/background_item_top"
            android:layout_marginTop="10dp"
            android:paddingStart="16dp"
            android:paddingTop="5dp"
            android:textSize="30dp"
            android:text="Job"
            android:textStyle="bold"
            android:textColor="@color/blue"/>
        <TextView
            android:id="@+id/tvAdpName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/background_item_middle"
            android:text="@string/name"
            android:paddingStart="32dp"
            android:paddingTop="5dp"
            android:paddingBottom="5dp"
            android:textColor="@color/black"/>
    </LinearLayout>
</LinearLayout>

Vamos então terminar de criar nossos arquivos de layouts activity_main.xml e activity_add_person.xml com os seguintes códigos.

<androidx.constraintlayout.widget.ConstraintLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/gray"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/btnInsert"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:text="@string/add"
        android:backgroundTint="@color/blue"
        android:textColor="@color/white"
        app:layout_constraintTop_toTopOf="parent"/>
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@+id/btnInsert"
        app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AddPersonActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_margin="16dp"
        app:layout_constraintTop_toTopOf="parent">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="20dp"
            android:text="@string/add_person"
            android:textSize="30dp"
            android:textStyle="bold"
            android:gravity="center"/>
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/name">
            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/etName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
        </com.google.android.material.textfield.TextInputLayout>
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/job">
            <com.google.android.material.textview.MaterialAutoCompleteTextView
                android:id="@+id/etJob"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
        </com.google.android.material.textfield.TextInputLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginTop="20dp">
            <Button
                android:id="@+id/btnAddPerson"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/add"
                android:layout_weight="1"/>
            <Button
                android:id="@+id/btnCancelPerson"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/cancel"
                android:layout_weight="1"/>
        </LinearLayout>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Já estamos com nossos arquivos de layout prontos, então vamos começar a montar os nossos códigos para que tudo funcione.





Códigos de como agrupar resultados na RecyclerView com Kotlin

Agora chegou a hora de ver como agrupar resultados na RecyclerView com Kotlin e para isso vamos começar criando um arquivo de classe no package adapter com o nome de PersonListAdapter.

Então este arquivo PersonListAdapter.kt vai conter como vai ser feito para que ele mostre o título apenas no primeiro item da lista com o seguinte código.

package br.com.uware.recyclerviewgroup.adapter

import android.content.Context
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.RecyclerView
import br.com.uware.recyclerviewgroup.R
import br.com.uware.recyclerviewgroup.model.Person
import kotlinx.android.synthetic.main.content_person.view.*

class PersonListAdapter (personList: ArrayList<Person>, internal var ctx: Context): RecyclerView.Adapter<PersonListAdapter.ViewHolder>(){

    internal var personList: ArrayList<Person> = ArrayList<Person>()
    init {
        this.personList = personList
    }

    inner class ViewHolder(view: View): RecyclerView.ViewHolder(view){
        var name = view.tvAdpName
        var job = view.tvAdpJob
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(ctx).inflate(R.layout.content_person, parent, false)
        return ViewHolder(view)
    }

    override fun getItemCount(): Int {
        return personList.size
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val person = personList[position]
        if(position > 0) {
            val pastPerson = personList[position - 1]
            if (person.job != pastPerson.job){
                holder.job.visibility = View.VISIBLE
            }
            else{
                holder.job.visibility = View.GONE
            }
        }
        if(position < itemCount - 1){
            val nextPerson = personList[position + 1]
            if(person.job != nextPerson.job){
                holder.name.background = ctx.getDrawable(R.drawable.background_item_bottom)
            }
        }
        if(position == itemCount-1){
            holder.name.background = ctx.getDrawable(R.drawable.background_item_bottom)
        }

        holder.job.text = person.job
        holder.name.text = "- "+person.name

    }
}

Assim que tivermos nosso arquivo da RecyclerView pronto apenas precisamos montar o arquivo que irá adicionar as pessoas, então vamos editar o arquivo AddPersonActivity e deixar com o seguinte código para que adicione as pessoas a lista.

package br.com.uware.recyclerviewgroup

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_add_person.*

class AddPersonActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_person)

        var listAdapter = intent.getStringArrayListExtra("adapter").toList()
        val adapter = ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, listAdapter)
        etJob.setAdapter(adapter)

        btnAddPerson.setOnClickListener {
            if(etName.text.toString() == "" || etJob.text.toString() == ""){
                Toast.makeText(this,getString(R.string.empty_name_or_job),Toast.LENGTH_SHORT).show()
            }
            else {
                val resultIntent = this.intent
                resultIntent.putExtra("name", etName.text.toString())
                resultIntent.putExtra("job", etJob.text.toString())
                setResult(Activity.RESULT_OK,resultIntent)
                finish()
            }
        }
        btnCancelPerson.setOnClickListener {
            finish()
        }
    }
}

Agora por fim só precisamos editar nossa MainActivity para que ela possa montar nossa RecyclerView e chamar a adição de pessoas na lista.

Vamos então deixar a MainActivity com o seguinte código para que isso aconteça.

package br.com.uware.recyclerviewgroup

import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import br.com.uware.recyclerviewgroup.adapter.PersonListAdapter
import br.com.uware.recyclerviewgroup.model.Person
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    // Iniciando array das pessoas
    var personList = ArrayList<Person>()

    // Iniciando a RecyclerView
    var listAdapter: PersonListAdapter? = null
    var linearLayoutManager: LinearLayoutManager? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btnInsert.setOnClickListener {
            val intent = Intent(this, AddPersonActivity::class.java)
            val adapter = autocompleteAdapter(personList)
            intent.putExtra("adapter", adapter)
            startActivityForResult(intent,1)
        }
    }

    override fun onResume() {
        super.onResume()
        initView()
    }

    // Setando recyclerview
    private fun initView(){
        orderPerson()
        listAdapter = PersonListAdapter(personList, this)
        linearLayoutManager = LinearLayoutManager(this)
        recyclerview.layoutManager = linearLayoutManager
        recyclerview.adapter = listAdapter
    }
    // Ordenando pessoas
    private fun orderPerson(){
        // Caso queira ordenar os nomes descomente as próximas linhas
        /*personList.sortBy {
            it.name
        }*/
        personList.sortBy {
            it.job
        }
    }
    // Setando list para autocomplete
    private fun autocompleteAdapter(pl: ArrayList<Person>): ArrayList<String>{
        val resp = ArrayList<String>()
        for(x in 1..pl.size){
            if(!resp.contains(pl[x-1].job)){
                resp.add(pl[x-1].job)
            }
        }
        return resp
    }

    // Recebendo resultados da AddPersonActivity
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if(requestCode == 1 && resultCode == Activity.RESULT_OK){
            val person: Person = Person()
            person.name = data!!.getStringExtra("name")
            person.job = data!!.getStringExtra("job")
            personList.add(person)
        }
    }
}

Então agora é só compilar e executar o projeto para ver como tudo esta funcionando.

Enfim espero poder ter ajudado com mais este tutorial sobre como agrupar resultados na RecyclerView com Kotlin e que você consiga agrupar seus resultados.

Visite e siga nosso canal no YouTube para ajudar no crescimento do site.





Autor: Rodrigo Leutz

Desenvolvedor Web e Android ( Kotlin e Java )


Pegar endereço com CEP usando coroutines e retrofit em Kotlin

Nesse tutorial vou mostrar como fazer um aplicativo em MVVM para pegar endereço com CEP usando coroutines e retrofit em[...]

4 de novembro de 2020

Converter Binário para Inteiro e Inteiro para Binário em Kotlin

Nesse tutorial vamos portanto ver como converter número binário para inteiro e também inteiro para binário em Kotlin no Android[...]

29 de outubro de 2020

Problema com Kotlin e synthetic no Android Studio

Notei que tem algumas pessoas com problemas com kotlin e synthetic no Android Studio então escrevi esta dica para solução desse[...]

27 de outubro de 2020