RecyclerView
En el archivo de Module:app añadiremos los siguientes complementos
//Complementos de vista RecyclerView y CardView
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
Después en ellos archivos de interfaz agregaremos el código para utilizar el RecyclerView
Ruta del Archivo de Interfaz
<android.support.v7.widget.RecyclerView
android:id="@+id/recytler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" Código para el RecyclerView
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"/>
Posteriormente crearemos un archivo de interfaz para cada Item del RecyclerView
Ruta del Archivo de Interfaz del Item
Código de interfaz del Item
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="wrap_content">
<ImageView
android:layout_width="50dp"
android:layout_height="43dp"
tools:src="@tools:sample/backgrounds/scenic[0]"
android:id="@+id/imageView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView android:layout_width="277dp"
android:layout_height="39dp"
android:text="Item"
android:textSize="25sp"
android:textStyle="bold"
android:id="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageView"
android:layout_marginStart="32dp"
android:layout_marginLeft="32dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="16dp"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintVertical_bias="1.0"/>
</android.support.constraint.ConstraintLayout>
Ahora programaremos el backend, para ello crearemos un Package con el nombre de Adapters, como se muestra a
continuación.
Y creamos la siguiente clase, recordando que el lenguaje utilizado es Kotlin
Código de la clase
//es una clase que extiende de RecyclerView.Adapter
class AdapterRecycler(var item: List<String>): RecyclerView.Adapter<AdapterRecycler.ViewHolder>() {
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): AdapterRecycler.ViewHolder {
// se infla la interfaz de usuario
var view: View = LayoutInflater.from(p0.context).inflate(R.layout.item_recycler,p0,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
// retorno del tamaño de lista
return item.size
}
override fun onBindViewHolder(p0: AdapterRecycler.ViewHolder, position: Int) {
p0.texview.text = item[position]
p0.img.setImageResource(R.drawable.ic_launcher_background)
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
// Declaracion de Vita
var texview: TextView = itemView.findViewById(R.id.title)
var img: ImageView = itemView.findViewById(R.id.imageView)
}
}
Código de la clase principal, así es como se utiliza el RecyclerView y el Adapter
class MainActivity : AppCompatActivity() {
//Variable Recycler con iniciacion tardia
private lateinit var recyclerView: RecyclerView
private var datos: MutableList<String> = mutableListOf<String>()
private var datos1: ArrayList<Student> = ArrayList<Student>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Cast de recytler
recyclerView = findViewById(R.id.recytler)
// se establece que el RecyclerView será en forma lineal ósea una lista
recyclerView.layoutManager = LinearLayoutManager(this)
//Cuando no cambia su altura o ancho del recycler
recyclerView.setHasFixedSize(true)
//sincronizamos el recycler con el adaptador pasando la informacion
recyclerView.adapter = AdapterRecycler(getDatos())
// Metodo que llena una lista y la retorna
fun getDatos(): MutableList<String>{
datos.add("Eric")
datos.add("Karla")
datos.add("Karen")
datos.add("Didier")
datos.add("Maru")
datos.add("Pedro")
datos.add("Marco")
datos.add("David")
datos.add("Jamon")
datos.add("Canela")
datos.add("David")
datos.add("Ulises")
datos.add("Hugo")
datos.add("Josue")
datos.add("Angel")
datos.add("Jafet")
datos.add("Martha")
datos.add("Lizbeth")
return datos;
}
}
Resultado del RecyclerView
RecyclerView con swipe
Para esto crearemos una nueva clase que extienda de ItemTouchHelper.SimpleCallback y que reciba
como parámetros el contexto y el RecyclerView.
Código de la case
// la clase recibe 2 parametros, y extiende de ItemTouchHelper.SimpleCallball y se le indica que
tendrá un movimiento a la izquierda
class SwipeToDeleteCallback(var recyclerView: RecyclerView,var context: Context):
ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.LEFT) {
// método que se ejecuta cuando se realiza el deslizamiento, en este caso añadimos el método
RemoveAt a la clase AdapterRecyler para eliminar el ítem.
override fun onSwiped(p0: RecyclerView.ViewHolder, p1: Int) {
val adapter = recyclerView.adapter as AdapterRecycler
adapter.RemoveAt(p0.adapterPosition)
}
override fun onMove(p0: RecyclerView, p1: RecyclerView.ViewHolder, p2: RecyclerView.ViewHolder):
Boolean {
// No queremos que los elementos se muevan hacia arriba / abajo
return false;
}
// Método donde se dibuja el fondo y el icono ajustando posiciones.
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder:
RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
val itemView = viewHolder.itemView
val itemHeight = itemView.bottom - itemView.top
val isCanceled = dX == 0f && !isCurrentlyActive
if (isCanceled) {
clearCanvas(c, itemView.right + dX, itemView.top.toFloat(), itemView.right.toFloat(),
itemView.bottom.toFloat())
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
return
}
// Draw the red delete background
background.color = backgroundColor
background.setBounds(itemView.right + dX.toInt(), itemView.top, itemView.right,
itemView.bottom)
background.draw(c)
// Calculate position of delete icon
val deleteIconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
val deleteIconMargin = (itemHeight - intrinsicHeight) / 2
val deleteIconLeft = itemView.right - deleteIconMargin - intrinsicWidth
val deleteIconRight = itemView.right - deleteIconMargin
val deleteIconBottom = deleteIconTop + intrinsicHeight
// Draw the delete icon
deleteIcon!!.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom)
deleteIcon.draw(c)
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
// Método para limpiar el canvas
private fun clearCanvas(c: Canvas?, left: Float, top: Float, right: Float, bottom: Float) {
c?.drawRect(left, top, right, bottom, clearPaint)
}
Método RemoveAt de la clase AdapterRecycler
fun RemoveAt(position: Int){
item.removeAt(position)
notifyItemRemoved(position)
}
Para aplicarlo en la clase principal añadiremos las siguientes líneas de código
val swipeHandler = SwipeToDeleteCallback(recyclerView,this)
val itemTouchHelper = ItemTouchHelper(swipeHandler)
itemTouchHelper.attachToRecyclerView(recyclerView)
RESULTADO
RecyclerSwipeAdapter
Para poder utilizarlo agregaremos la siguiente dependencia en Module:App
implementation 'com.daimajia.swipelayout:library:1.2.0@aar'
En el Package de Adapter crearemos una nueva clase llamada
SwipeRecyclerViewAdapter esta clase tiene la funcionalidad del
RecyclerAdapter y ItemTouchHelper.
Para ello procederemos creando un archivo de interfaz usando un SwipeLayout
en el siguiente directorio.
Código de la vista
<?xml version="1.0" encoding="utf-8"?>
<com.daimajia.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:swipe="http://schemas.android.com/apk/res-auto"
swipe:leftEdgeSwipeOffset="0dp"
swipe:rightEdgeSwipeOffset="0dp"
android:id="@+id/swipe">
<!-- Botones del lado derecho dentro de un layout llamado bottom_wrapper-->
<LinearLayout
android:id="@+id/bottom_wrapper"
android:layout_width="185dp"
android:layout_height="54dp"
android:weightSum="2"
android:paddingTop="3dp">
<TextView
android:id="@+id/tvEdit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#0076a5"
android:gravity="center"
android:text="Edit"
android:textColor="#fff" />
<TextView
android:id="@+id/tvDelete"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#0076a5"
android:gravity="center"
android:text="Delete"
android:textColor="#fff" />
</LinearLayout>
<!-- Botones del lado izquierdo dentro de un layout llamado bottom_wrapper1-->
<LinearLayout
android:id="@+id/bottom_wrapper1"
android:layout_width="80dp"
android:layout_height="54dp"
android:weightSum="1"
android:paddingTop="3dp">
<ImageButton
android:id="@+id/btnLocation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FF0000"
android:gravity="center"
android:src="@drawable/ic_delete_sweep"/>
</LinearLayout>
<!-- Elemento de Item de RecyclerView-->
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="60dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardUseCompatPadding="true">
<!-- Indicador de estado -->
<View
android:id="@+id/indicator_appointment_status"
android:layout_width="8dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="#E0E0E0" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:paddingBottom="8dp"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
android:text="7 Octubre 2017" />
<View
android:id="@+id/vertical_separator"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_toEndOf="@+id/tvName"
android:layout_toRightOf="@+id/tvName"
android:background="#E0E0E0" />
<TextView
android:id="@+id/tvEmailId"
style="@style/Base.TextAppearance.AppCompat.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_toEndOf="@+id/vertical_separator"
android:layout_toRightOf="@+id/vertical_separator"
android:text="Consulta Medicina General" />
<TextView
android:id="@+id/text_medical_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tvEmailId"
android:layout_alignStart="@+id/tvEmailId"
android:layout_below="@+id/tvEmailId"
android:ellipsize="end"
android:maxLines="1"
android:text="Clínica Central" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</com.daimajia.swipe.SwipeLayout>
Código de la clase
class SwipeRecyclerViewAdapter(var mContext: Context,var studentList: ArrayList<Student>):
RecyclerSwipeAdapter<SwipeRecyclerViewAdapter.SimpleViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder {
// Se Infla la interfaz del cada item
val view =
LayoutInflater.from(parent.context).inflate(com.example.recyclerview.R.layout.swipe_layout,parent,f
alse)
return SimpleViewHolder(view)
}
override fun onBindViewHolder(viewHolder: SimpleViewHolder, position: Int) {
// se realiza la logica de negocio
val item = studentList[position]
// setText
viewHolder.tvName.setText(item.name + " - Row Position " + position)
viewHolder.tvEmailId.setText(item.emailId)
// Se Establece el modo de arrastre (PullOut or LayDown)
viewHolder.swipeLayout.showMode = SwipeLayout.ShowMode.PullOut
// Drag From Left (Arrastrar desde la izquierda)
//se establce el layout que apareceza en la izquierda;
viewHolder.swipeLayout.addDrag(SwipeLayout.DragEdge.Left,
viewHolder.swipeLayout.findViewById(R.id.bottom_wrapper1))
// Drag From Right (Arrastrar desde la derecha)
// Se Establece el layout que aparecera en la Derecha
viewHolder.swipeLayout.addDrag(SwipeLayout.DragEdge.Right,
viewHolder.swipeLayout.findViewById(R.id.bottom_wrapper))
// Handling different events when swiping (Manejo de diferentes eventos al deslizar)
viewHolder.swipeLayout.addSwipeListener(object : SwipeLayout.SwipeListener {
override fun onClose(layout: SwipeLayout) {
//when the SurfaceView totally cover the BottomView.
}
override fun onUpdate(layout: SwipeLayout, leftOffset: Int, topOffset: Int) {
//you are swiping.
}
override fun onStartOpen(layout: SwipeLayout) {
}
override fun onOpen(layout: SwipeLayout) {
//when the BottomView totally show.
}
override fun onStartClose(layout: SwipeLayout) {
}
override fun onHandRelease(layout: SwipeLayout, xvel: Float, yvel: Float) {
//when user's hand released.
}
})
//Listener para el Touch del Item
viewHolder.swipeLayout.surfaceView.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
Toast.makeText(mContext, " onClick : " + item.name + " \n" + item.emailId,
Toast.LENGTH_SHORT)
.show()
}
})
//Listener para elTouch del Boton Delete Izquierda
viewHolder.btnLocation.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
Toast.makeText(
v.getContext(),
"Clicked on Map " + viewHolder.tvName.text.toString(),
Toast.LENGTH_SHORT
).show()
}
})
//Listener para el boton Edit
viewHolder.tvEdit.setOnClickListener(object : View.OnClickListener {
override fun onClick(view: View) {
Toast.makeText(
view.getContext(),
"Clicked on Edit " + viewHolder.tvName.text.toString(),
Toast.LENGTH_SHORT
).show()
}
})
//Listener para el boton delete Derecho
viewHolder.tvDelete.setOnClickListener(object : View.OnClickListener {
override fun onClick(view: View) {
mItemManger.removeShownLayouts(viewHolder.swipeLayout)
studentList.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, studentList.size)
mItemManger.closeAllItems()
Toast.makeText(view.getContext(), "Deleted " + viewHolder.tvName.text.toString(),
Toast.LENGTH_SHORT)
.show()
}
})
// mItemManger is member in RecyclerSwipeAdapter Class
mItemManger.bindView(viewHolder.itemView, position)
}
override fun getItemCount(): Int {
return studentList.size
}
override fun getSwipeLayoutResourceId(position: Int): Int {
return R.id.swipe
}
// ViewHolder Class
class SimpleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
lateinit var swipeLayout: SwipeLayout
internal var tvName: TextView
internal var tvEmailId: TextView
internal var tvDelete: TextView
internal var tvEdit: TextView
internal var btnLocation: ImageButton
init {
swipeLayout = itemView.findViewById(R.id.swipe)
tvName = itemView.findViewById(R.id.tvName)
tvEmailId = itemView.findViewById(R.id.tvEmailId)
tvDelete = itemView.findViewById(R.id.tvDelete)
tvEdit = itemView.findViewById(R.id.tvEdit)
btnLocation = itemView.findViewById(R.id.btnLocation)
}
}
}
para utilizarlo serían las siguientes líneas de código en la clase
principal
recyclerView = findViewById(R.id.recytler)
recyclerView.layoutManager = LinearLayoutManager(this)
//Cuando no cambia su altura o ancho del recycler
recyclerView.setHasFixedSize(true)
//sincronizamos el recycler con el adaptador pasando la informacion
recyclerView.adapter = AdapterRecycler(getDatos())
// Creating Adapter object
ecyclerView.adapter = SwipeRecyclerViewAdapter(applicationContext, getDatos1())
RESULTADO