ΠΠ°Π½Π½Π°Ρ ΡΡΠ°ΡΡΡ Π±ΡΠ»Π° Π½Π°ΠΏΠΈΡΠ°Π½Π° coder-chekunkov Π΄Π»Ρ Π½Π°ΡΠΈΠ½Π°ΡΡΠΈΡ
Android-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ². Π’Π΅ΠΌΠ°: RecyclerView.
Π‘ΡΡΠ»ΠΊΠ° Π½Π° ΡΡΠ°ΡΡΡ Π½Π° Habr.
ΠΠ΄ΡΠ°Π²ΡΡΠ²ΡΠΉ, Π΄ΠΎΡΠΎΠ³ΠΎΠΉ ΡΠΈΡΠ°ΡΠ΅Π»Ρ. ΠΠ°ΠΆΠ΄ΡΠΉ Android-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΡΡΠ°Π»ΠΊΠΈΠ²Π°Π»ΡΡ Ρ Π·Π°Π΄Π°ΡΠ΅ΠΉ, Π² ΠΊΠΎΡΠΎΡΠΎΠΉ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°ΡΡ ΠΊΠ°ΠΊΠΎΠΉ-ΡΠΎ ΡΠΏΠΈΡΠΎΠΊ, Π΄Π»Ρ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π΄Π°Π½Π½ΡΡ . ΠΠ°Π½Π½Π°Ρ ΡΡΠ°ΡΡΡ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ Π½ΠΎΠ²ΠΈΡΠΊΡ ΡΠ°Π·ΠΎΠ±ΡΠ°ΡΡΡΡ Ρ ΡΠ°ΠΊΠΈΠΌ ΠΎΡΠ΅Π½Ρ Π²Π°ΠΆΠ½ΡΠΌ ΠΈ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΡΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠΌ, ΠΊΠ°ΠΊ RecyclerView.
Π ΡΡΠ°ΡΡΠ΅ Π±ΡΠ΄Π΅Ρ ΡΠ°ΡΡΠΊΠ°Π·Π°Π½ΠΎ ΠΎ ΡΠΎΠΌ, ΠΏΠΎΡΠ΅ΠΌΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΈΠΌΠ΅Π½Π½ΠΎ RecyclerView, ΠΎΠΏΠΈΡΠ°Π½Ρ Π΅Π³ΠΎ ΠΎΡΠ½ΠΎΠ²Π½ΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ ΠΈ ΡΠ°ΠΊΠΆΠ΅ Π±ΡΠ΄Π΅Ρ ΡΠ°Π·ΠΎΠ±ΡΠ°Π½ Π±Π°Π·ΠΎΠ²ΡΠΉ, Π½Π΅ ΠΎΡΠ΅Π½Ρ ΡΠ»ΠΎΠΆΠ½ΡΠΉ ΠΏΡΠΈΠΌΠ΅Ρ.
Π‘ΡΠ°ΡΡΡ ΠΏΡΠ΅Π΄Π½Π°Π·Π½Π°ΡΠ΅Π½Π° Π΄Π»Ρ Π½ΠΎΠ²ΠΈΡΠΊΠΎΠ², ΠΊΠΎΡΠΎΡΡΠ΅ Ρ ΠΎΡΡΡ ΡΠ°Π·ΠΎΠ±ΡΠ°ΡΡΡΡ ΡΠΎ ΡΠΏΠΈΡΠΊΠ°ΠΌΠΈ Π² Android.
ΠΠ»Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΠΊΠ°ΠΊΠΎΠ³ΠΎ-ΡΠΎ ΠΏΡΠΎΠΊΡΡΡΠΈΠ²Π°Π΅ΠΌΠΎΠ³ΠΎ ΡΠΏΠΈΡΠΊΠ° Ρ Android ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ° ΡΡΡΠ΅ΡΡΠ²ΡΡΡ Π΄Π²Π° ΠΏΡΡΠΈ - ListView ΠΈ RecyclerView.
ΠΠ΅ΡΠ²ΡΠΉ Π²ΠΈΠ΄ΠΆΠ΅Ρ ΠΈΠ½ΡΡΠΈΡΠΈΠ²Π½ΠΎ ΠΏΠΎΠ½ΡΡΠ΅Π½ ΠΈ Π΄ΠΎΠ²ΠΎΠ»ΡΠ½ΠΎ ΠΏΡΠΎΡΡ. ΠΠΎ, ΠΊ ΡΠΎΠΆΠ°Π»Π΅Π½ΠΈΡ, ΠΈΠΌΠ΅Π΅Ρ ΠΌΠ½ΠΎΠ³ΠΎ Π½Π΅Π΄ΠΎΡΡΠ°ΡΠΊΠΎΠ², Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, ListView ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠΎΠ·Π΄Π°ΡΡ ΡΠΎΠ»ΡΠΊΠΎ Π²Π΅ΡΡΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ ΡΠΏΠΈΡΠΎΠΊ.
Π ΡΠ²ΠΎΡ ΠΆΠ΅ ΠΎΡΠ΅ΡΠ΅Π΄Ρ RecyclerView "ΠΈΠ· ΠΊΠΎΡΠΎΠ±ΠΊΠΈ" ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ Π³ΠΎΡΠ°Π·Π΄ΠΎ Π±ΠΎΠ»ΡΡΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ² Π΄Π»Ρ ΠΊΠ°ΡΡΠΎΠΌΠΈΠ·Π°ΡΠΈΠΈ ΠΈ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΡΠΏΠΈΡΠΊΠ°, ΡΠ΅ΠΌ ListView. ΠΡΠ»ΠΈ ΠΊΡΠ°ΡΠΊΠΎ Ρ Π°ΡΠ°ΠΊΡΠ΅ΡΠΈΠ·ΠΎΠ²Π°ΡΡ RecyclerView, ΡΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΊΠ°Π·Π°ΡΡ, ΡΡΠΎ ΡΡΠΎ ΡΠΏΠΈΡΠΎΠΊ Π½Π° ΡΡΠ΅ΡΠΎΠΈΠ΄Π°Ρ .
RecyclerView ΡΠ°Π±ΠΎΡΠ°Π΅Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ: Π½Π° ΡΠΊΡΠ°Π½Π΅ ΡΡΡΡΠΎΠΉΡΡΠ²Π° ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°ΡΡΡΡ Π²ΠΈΠ΄ΠΈΠΌΡΠ΅ ΡΠ»Π΅ΠΌΠ΅Π½ΡΡ ΡΠΏΠΈΡΠΊΠ°; ΠΏΡΠΈ ΠΏΡΠΎΠΊΡΡΡΠΊΠ΅ ΡΠΏΠΈΡΠΊΠ° Π²Π΅ΡΡ Π½ΠΈΠΉ ΡΠ»Π΅ΠΌΠ΅Π½Ρ ΡΡ ΠΎΠ΄ΠΈΡ Π·Π° ΠΏΡΠ΅Π΄Π΅Π»Ρ ΡΠΊΡΠ°Π½Π° ΠΈ ΠΎΡΠΈΡΠ°Π΅ΡΡΡ, Π° ΠΏΠΎΡΠ»Π΅ ΠΏΠΎΠΌΠ΅ΡΠ°Π΅ΡΡΡ Π²Π½ΠΈΠ· ΡΠΊΡΠ°Π½Π° ΠΈ Π·Π°ΠΏΠΎΠ»Π½ΡΠ΅ΡΡΡ Π½ΠΎΠ²ΡΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ.
ΠΠ»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΠΎΠΉ ΡΠ°Π±ΠΎΡΡ RecyckerView Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ:
RecyclerView
, ΠΊΠΎΡΠΎΡΡΠΉ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π² ΠΌΠ°ΠΊΠ΅Ρ Π½Π°ΡΠ΅Π³ΠΎ Activity;Adapter
, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ, ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ ΠΈ ΡΠ²ΡΠ·ΡΠ²Π°Π΅Ρ Π΄Π°Π½Π½ΡΠ΅ ΡΠΎ ΡΠΏΠΈΡΠΊΠΎΠΌ;ViewHolder
, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠ»ΡΠΆΠΈΡ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΡΠ΅ΡΡΡΡΠΎΠ² ΠΈ ΡΠ²Π»ΡΠ΅ΡΡΡ ΡΠ²ΠΎΠ΅ΠΎΠ±ΡΠ°Π·Π½ΡΠΌ ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠΎΠΌ Π΄Π»Ρ Π²ΡΠ΅Ρ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ², Π²Ρ ΠΎΠ΄ΡΡΠΈΡ Π² ΡΠΏΠΈΡΠΎΠΊ;ItemDecorator
, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΎΡΡΠΈΡΠΎΠ²Π°ΡΡ Π²Π΅ΡΡ Π΄Π΅ΠΊΠΎΡ;ItemAnimator
, ΠΊΠΎΡΠΎΡΡΠΉ ΠΎΡΠ²Π΅ΡΠ°Π΅Ρ Π·Π° Π°Π½ΠΈΠΌΠ°ΡΠΈΡ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΠΏΡΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ, ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ ΠΈ Π΄ΡΡΠ³ΠΈΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ;DiffUtil
, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠ»ΡΠΆΠΈΡ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΡΠΏΠΈΡΠΊΠ° ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ ΡΡΠ°Π½Π΄Π°ΡΡΠ½ΡΡ Π°Π½ΠΈΠΌΠ°ΡΠΈΠΉ.
Π ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ Π½Π΅ ΡΠ»ΠΎΠΆΠ½ΠΎΠ³ΠΎ ΠΏΡΠΈΠΌΠ΅ΡΠ°, ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΡΠΎ ΡΠΏΠΈΡΠΊΠΎΠΌ, Π² ΠΊΠΎΡΠΎΡΠΎΠΌ Π±ΡΠ΄ΡΡ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½Ρ Π΄Π°Π½Π½ΡΠ΅ ΠΎ Π»ΡΠ΄ΡΡ . ΠΠ°ΠΆΠ΄ΡΠΉ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ Π±ΡΠ΄Π΅Ρ ΠΈΠΌΠ΅ΡΡ ΠΈΠΌΡ, Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ, ΡΠΎΡΠΎΠ³ΡΠ°ΡΠΈΡ ΠΈ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ Π½Π°Π΄ Π½ΠΈΠΌ (ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ, ΡΠ΄Π°Π»ΠΈΡΡ, ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΡΠΈΡΡ Π²Π²Π΅ΡΡ /Π²Π½ΠΈΠ·, Π»Π°ΠΉΠΊΠ½ΡΡΡ).
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΈΠΌΠ΅ΡΠ° Π±ΡΠ΄Π΅Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½Π° Π½Π° ΡΠ·ΡΠΊΠ΅ Kotlin. Π’Π°ΠΊΠΆΠ΅ Π±ΡΠ΄ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Glide ΠΈ Faker, ΠΊΠΎΡΠΎΡΡΠ΅ Π½ΠΈΠΊΠ°ΠΊ Π½Π΅ ΠΎΡΠ½ΠΎΡΡΡΡΡ ΠΊ RecyclerView.
Π ΠΏΠ΅ΡΠ²ΡΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ ΡΠΊΠ°ΠΆΠ΅ΠΌ Π²ΡΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ, ΠΊΠΎΡΠΎΡΡΠ΅ Π±ΡΠ΄ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ, Π² ΡΠ°ΠΉΠ» ΡΠ±ΠΎΡΠΊΠΈ build.gradle
Π½Π°ΡΠ΅Π³ΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ:
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.github.javafaker:javafaker:1.0.2'
implementation 'com.github.bumptech.glide:glide:4.14.2'
ΠΡΠΈΠΌΠ΅ΡΠ°Π½ΠΈΠ΅: Π² ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡ Π²Π΅ΡΡΠΈΡΡ AndroidStudio Π½Π΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ°ΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΡ RecyclerView. ΠΠΎΡΡΡΠΏΠ΅Π½ Π² Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ΅ Material.
Π Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠΈΡΡ ViewBinding Π² ΡΠ°ΠΉΠ»Π΅ ΡΠ±ΠΎΡΠΊΠΈ build.gradle
Π½Π°ΡΠ΅Π³ΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ:
buildFeatures {
viewBinding = true
}
Π’Π°ΠΊΠΆΠ΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΊΠ°Π·Π°ΡΡ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π½Π° Π΄ΠΎΡΡΡΠΏ Π² ΠΠ½ΡΠ΅ΡΠ½Π΅Ρ Π² ΡΠ°ΠΉΠ»Π΅ AndroidManifest.xml
(Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΎΠΉ Glide):
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
ΠΠΎΡΠ»Π΅ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΌΠ°ΠΊΠ΅ΡΠ½ΡΠ΅ ΡΠ°ΠΉΠ»Ρ: ΠΏΠ΅ΡΠ²ΡΠΉ Π΄Π»Ρ ActivityMain, ΠΊΠΎΡΠΎΡΡΠΉ Ρ ΡΠ°Π½ΠΈΡ RecyclerView, Π²ΡΠΎΡΠΎΠΉ Π΄Π»Ρ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ° ΡΠΏΠΈΡΠΊΠ° (ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ).
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activityMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
item_person.xml
<?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="wrap_content"
android:background="?selectableItemBackground"
android:paddingStart="10dp"
android:paddingTop="5dp"
android:paddingEnd="10dp"
android:paddingBottom="5dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/ic_person"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/nameTextView"
style="@style/TextAppearance.AppCompat.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
app:layout_constraintStart_toEndOf="@id/imageView"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/companyTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
app:layout_constraintStart_toEndOf="@id/imageView"
app:layout_constraintTop_toBottomOf="@id/nameTextView" />
<ImageView
android:id="@+id/likedImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="15dp"
android:src="@drawable/ic_like"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/more"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_more"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
ΠΠΎΡΠ»Π΅ ΡΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ Π²ΡΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Π±ΡΠ»ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½Ρ, Π²ΡΠ΅ ΠΌΠ°ΠΊΠ΅ΡΡ ΡΠΎΠ·Π΄Π°Π½Ρ ΠΈ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½ΠΈΡ ΠΏΠΎΠ»ΡΡΠ΅Π½Ρ, Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°ΡΡ Π΄Π°Π½Π½ΡΠ΅ ΠΎ Π»ΡΠ΄ΡΡ (Π² Π½Π°ΡΡΠΎΡΡΠ΅ΠΌ, Π±ΠΎΠ΅Π²ΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅ ΡΡΠΈ Π΄Π°Π½Π½ΡΠ΅ Π±ΡΠ΄ΡΡ ΠΏΡΠΈΡ ΠΎΠ΄ΠΈΡΡ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, Ρ ΡΠ΅ΡΠ²Π΅ΡΠ°, Π½ΠΎ Π² Π½Π°ΡΠ΅ΠΌ ΡΠ»ΡΡΠ°Π΅ ΠΌΡ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΈΡ ΡΠ°ΠΌΠΎΡΡΠΎΡΡΠ΅Π»ΡΠ½ΠΎ). ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΊΠ»Π°ΡΡ PersonService ΠΈ data-class Person:
data class Person(
val id: Long, // Π£Π½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ
val name: String, // ΠΠΌΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°
val companyName: String, // ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½ΠΈΠΈ
val photo: String, // Π‘ΡΡΠ»ΠΊΠ° Π½Π° ΡΠΎΡΠΎ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°
val isLiked: Boolean // ΠΡΠ» Π»ΠΈ Π»Π°ΠΉΠΊΠ½ΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ
)
class PersonService {
private var persons = mutableListOf<Person>() // ΠΡΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΠΈ
init {
val faker = Faker.instance() // ΠΠ΅ΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΠ»ΡΡΠ°ΠΉΠ½ΡΡ
Π΄Π°Π½Π½ΡΡ
persons = (1..50).map {
Person(
id = it.toLong(),
name = faker.name().fullName(),
companyName = faker.company().name(),
photo = IMAGES[it % IMAGES.size],
isLiked = false
)
}.toMutableList()
}
companion object {
private val IMAGES = mutableListOf(
"https://images.unsplash.com/photo-1600267185393-e158a98703de?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0NjQ0&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1579710039144-85d6bdffddc9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0Njk1&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1488426862026-3ee34a7d66df?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0ODE0&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1620252655460-080dbec533ca?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0NzQ1&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1613679074971-91fc27180061?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0NzUz&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1485795959911-ea5ebf41b6ae?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0NzU4&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1545996124-0501ebae84d0?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0NzY1&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/flagged/photo-1568225061049-70fb3006b5be?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0Nzcy&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1567186937675-a5131c8a89ea?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0ODYx&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800",
"https://images.unsplash.com/photo-1546456073-92b9f0a8d413?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=600&ixid=MnwxfDB8MXxyYW5kb218fHx8fHx8fHwxNjI0MDE0ODY1&ixlib=rb-1.2.1&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=800"
)
}
}
Π ΠΊΠ»Π°ΡΡΠ΅ PersonService Ρ
ΡΠ°Π½ΠΈΡΡΡ Π»ΠΈΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΡ Π·Π°ΠΏΠΎΠ»Π½ΡΠ΅ΠΌ Π² init
(initializers blocks), ΠΈ Π»ΠΈΡΡ ΡΡΡΠ»ΠΎΠΊ Π½Π° ΡΠΎΡΠΎΠ³ΡΠ°ΡΠΈΠΈ.
ΠΠΎΡΠ»Π΅ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΊΠ»Π°ΡΡΠΎΠ² Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ ΠΊΠ»Π°ΡΡ PersonService ΡΠ΄Π΅Π»Π°ΡΡ Singleton
Π΄Π»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΠΎΠΉ ΡΠ°Π±ΠΎΡΡ. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΊΠ»Π°ΡΡ App, ΠΈ ΡΠΊΠ°ΠΆΠ΅ΠΌ Π² Π½Π΅ΠΌ ΡΠ»Π΅Π΄ΡΡΡΠ΅Π΅:
class App : Application() {
val personService = PersonService()
}
Π’Π΅ΠΏΠ΅ΡΡ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅ΠΌ Π°Π΄Π°ΠΏΡΠ΅Ρ PersonAdapter, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ Π½Π°ΡΠΈ Π΄Π°Π½Π½ΡΠ΅ ΠΈ ΡΠ²ΡΠ·ΡΠ²Π°ΡΡ ΠΈΡ ΡΠΎ ΡΠΏΠΈΡΠΊΠΎΠΌ.
ΠΠ°Π½Π½ΡΠΉ ΠΊΠ»Π°ΡΡ Π±ΡΠ΄Π΅Ρ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ RecyclerView.Adapter
, ΠΊΠΎΡΠΎΡΠΎΠΌΡ Π½ΡΠΆΠ΅Π½ ViewHolder. Π‘ΠΎΠΎΡΠ²Π΅ΡΡΡΠ²Π΅Π½Π½ΠΎ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°ΡΡ PersonViewHolder, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²ΡΠ²Π°ΡΡ RecyclerView.ViewHolder
ΠΈ ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ Π½Π°Ρ binding.
Π’Π°ΠΊΠΆΠ΅ PersonAdapter Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅ΡΡ Π΄Π°Π½Π½ΡΠ΅, Ρ ΠΊΠΎΡΠΎΡΡΠΌΠΈ Π΅ΠΌΡ ΠΏΡΠ΅Π΄ΡΡΠΎΠΈΡ ΡΠ°Π±ΠΎΡΠ°ΡΡ. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΡΡΡΠΎΠΉ ΡΠΏΠΈΡΠΎΠΊ ΠΈ ΠΏΠ΅ΡΠ΅ΠΏΠΈΡΠ΅ΠΌ Π΅Π³ΠΎ ΡΠ΅ΡΡΠ΅Ρ. Π ΠΈΡΠΎΠ³Π΅ ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ:
class PersonAdapter : RecyclerView.Adapter<PersonAdapter.PersonViewHolder>() {
var data: List<Person> = emptyList()
set(newValue) {
field = newValue
notifyDataSetChanged()
}
class PersonViewHolder(val binding: ItemPersonBinding) : RecyclerView.ViewHolder(binding.root)
}
ΠΠΎ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Π°Π΄Π°ΠΏΡΠ΅ΡΠ° Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΡ ΠΌΠΈΠ½ΠΈΠΌΡΠΌ ΡΡΠΈ ΠΌΠ΅ΡΠΎΠ΄Π° (AndroidStudio ΠΏΠΎΠ΄ΡΠΊΠ°ΠΆΠ΅Ρ Π½Π°ΠΌ).
ΠΠ΅ΡΠΎΠ΄ getItemCount
, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ Π²ΠΎΠ·Π²ΡΠ°ΡΠ°ΡΡ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² Π½Π°ΡΠ΅Π³ΠΎ ΡΠΏΠΈΡΠΊΠ° Ρ Π΄Π°Π½Π½ΡΠΌΠΈ;
ΠΠ΅ΡΠΎΠ΄ onCreateViewHolder
, Π² ΠΊΠΎΡΠΎΡΠΎΠΌ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΠΈΡΡ
ΠΎΠ΄ΠΈΡΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ViewHolder. ΠΠ°Π½Π½ΡΠΉ ΠΌΠ΅ΡΠΎΠ΄ ΠΏΡΠΈΠ½ΠΈΠΌΠ°Π΅Ρ Π² ΡΠ΅Π±Ρ parent ΠΈ viewType (ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π² ΡΠΎΠΌ ΡΠ»ΡΡΠ°Π΅, Π΅ΡΠ»ΠΈ Π² ΡΠΏΠΈΡΠΊΠ΅ Π±ΡΠ΄ΡΡ ΡΠ°Π·Π½ΡΠ΅ ΡΠΈΠΏΡ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΡΠΏΠΈΡΠΊΠ°);
ΠΠ΅ΡΠΎΠ΄ onBindViewHolder
, Π² ΠΊΠΎΡΠΎΡΠΎΠΌ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΠΈΡΡ
ΠΎΠ΄ΠΈΡΡ ΠΎΡΡΠΈΡΠΎΠ²ΠΊΠ° Π²ΡΠ΅Ρ
ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² Π² ΠΎΠ±ΡΠ΅ΠΊΡΠ΅ ΡΠΏΠΈΡΠΊΠ° (ΠΈΠΌΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°, ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΡ ΠΈ Ρ.Π΄.):
ΠΠΎΡΠ»Π΅ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² ΠΈ ΠΈΡ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ:
override fun getItemCount(): Int = data.size // ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² Π² ΡΠΏΠΈΡΠΊΠ΅ Π΄Π°Π½Π½ΡΡ
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PersonViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemPersonBinding.inflate(inflater, parent, false)
return PersonViewHolder(binding)
}
override fun onBindViewHolder(holder: PersonViewHolder, position: Int) {
val person = data[position] // ΠΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ° ΠΈΠ· ΡΠΏΠΈΡΠΊΠ° Π΄Π°Π½Π½ΡΡ
ΠΏΠΎ ΠΏΠΎΠ·ΠΈΡΠΈΠΈ
val context = holder.itemView.context
with(holder.binding) {
val color = if (person.isLiked) R.color.red else R.color.grey // Π¦Π²Π΅Ρ "ΡΠ΅ΡΠ΄ΡΠ°", Π΅ΡΠ»ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π±ΡΠ» Π»Π°ΠΉΠΊΠ½ΡΡ
nameTextView.text = person.name // ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΈΠΌΠ΅Π½ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ
companyTextView.text = person.companyName // ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ
likedImageView.setColorFilter( // ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΡΠ²Π΅ΡΠ° "ΡΠ΅ΡΠ΄ΡΠ°"
ContextCompat.getColor(context, color),
android.graphics.PorterDuff.Mode.SRC_IN
)
Glide.with(context).load(person.photo).circleCrop() // ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΡΠΎΡΠΎΠ³ΡΠ°ΡΠΈΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Glide
.error(R.drawable.ic_person)
.placeholder(R.drawable.ic_person).into(imageView)
}
}
ΠΠ° ΡΡΠΎΠΌ Π½Π°Ρ ΠΏΡΠΎΡΡΠΎΠΉ Π°Π΄Π°ΠΏΡΠ΅Ρ, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΡΡΠΎ Π²ΡΠ²ΠΎΠ΄ΠΈΡΡ Π³ΠΎΡΠΈΠ·ΠΎΠ½ΡΠ°Π»ΡΠ½ΡΠΉ ΡΠΏΠΈΡΠΎΠΊ Π³ΠΎΡΠΎΠ².
Π’Π΅ΠΏΠ΅ΡΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΠ²Π΅ΡΠΈΡΡ Π½Π° Π½Π°Ρ RecyclerView ΡΠΎΠ·Π΄Π°Π½Π½ΡΠΉ Π°Π΄Π°ΠΏΡΠ΅Ρ ΠΈ LayoutManager. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ Π² ΠΊΠ»Π°ΡΡΠ΅ MainActivity ΠΏΡΠΎΠΏΠΈΡΠ΅ΠΌ ΡΠ»Π΅Π΄ΡΡΡΠ΅Π΅:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var adapter: PersonAdapter // ΠΠ±ΡΠ΅ΠΊΡ Adapter
private val personService: PersonService // ΠΠ±ΡΠ΅ΠΊΡ PersonService
get() = (applicationContext as App).personService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val manager = LinearLayoutManager(this) // LayoutManager
adapter = PersonAdapter() // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
adapter.data = personService.getPersons() // ΠΠ°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½ΡΠΌΠΈ
binding.recyclerView.layoutManager = manager // ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ LayoutManager Π΄Π»Ρ RecyclerView
binding.recyclerView.adapter = adapter // ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ Π°Π΄Π°ΠΏΡΠ΅ΡΠ° Π΄Π»Ρ RecyclerView
}
}
ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ Π½Π°ΡΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° ΡΡΡΡΠΎΠΉΡΡΠ²Π΅ ΠΈ ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ ΡΠΏΠΈΡΠΎΠΊ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ!
ΠΠ° Π΄Π°Π½Π½ΠΎΠΌ ΡΡΠ°ΠΏΠ΅ Π½Π°ΡΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΡΠΎ Π²ΡΠ²ΠΎΠ΄ΠΈΡ Π΄Π°Π½Π½ΡΠ΅, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΡ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡΠΎΠΊΡΡΡΠΈΠ²Π°ΡΡ, Π½ΠΎ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΎΠ²Π°ΡΡ Ρ Π½ΠΈΠΌΠΈ Ρ Π½Π°Ρ Π½Π΅ ΠΏΠΎΠ»ΡΡΠΈΡΡΡ. ΠΡΠΏΡΠ°Π²ΠΈΠΌ ΡΡΠΎ.
Π ΠΊΠ»Π°ΡΡΠ΅ PersonService Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΡΡΠΈ ΠΌΠ΅ΡΠΎΠ΄Π°:
- likePerson - Π»Π°ΠΉΠΊΠ°Π΅ΠΌ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°;
- removePerson - ΡΠ΄Π°Π»ΡΠ΅ΠΌ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°;
- movePerson - ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ°Π΅ΠΌ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ° (ΠΏΡΠΈΠ½ΠΈΠΌΠ°Π΅Ρ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ° ΠΈ ΠΊΡΠ΄Π° Π½Π°Π΄ΠΎ ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΡΠΈΡΡ: "1" - Π²Π½ΠΈΠ·, "-1" - Π²Π²Π΅ΡΡ ).
fun likePerson(person: Person) {
val index = persons.indexOfFirst { it.id == person.id } // ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΠΈΠ½Π΄Π΅ΠΊΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ° Π² ΡΠΏΠΈΡΠΊΠ΅
if (index == -1) return // ΠΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌΡΡ, Π΅ΡΠ»ΠΈ Π½Π΅ Π½Π°Ρ
ΠΎΠ΄ΠΈΠΌ ΡΠ°ΠΊΠΎΠ³ΠΎ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°
persons = ArrayList(persons) // Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΠ²ΡΠΉ ΡΠΏΠΈΡΠΎΠΊ
persons[index] = persons[index].copy(isLiked = !persons[index].isLiked) // ΠΠ΅Π½ΡΠ΅ΠΌ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ "Π»Π°ΠΉΠΊΠ°" Π½Π° ΠΏΡΠΎΡΠΈΠ²ΠΎΠΏΠΎΠ»ΠΎΠΆΠ½ΠΎΠ΅
}
fun removePerson(person: Person) {
val index = persons.indexOfFirst { it.id == person.id } // ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΠΈΠ½Π΄Π΅ΠΊΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ° Π² ΡΠΏΠΈΡΠΊΠ΅
if (index == -1) return // ΠΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌΡΡ, Π΅ΡΠ»ΠΈ Π½Π΅ Π½Π°Ρ
ΠΎΠ΄ΠΈΠΌ ΡΠ°ΠΊΠΎΠ³ΠΎ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°
persons = ArrayList(persons) // Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΠ²ΡΠΉ ΡΠΏΠΈΡΠΎΠΊ
persons.removeAt(index) // Π£Π΄Π°Π»ΡΠ΅ΠΌ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°
}
fun movePerson(person: Person, moveBy: Int) {
val oldIndex = persons.indexOfFirst { it.id == person.id } // ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΠΈΠ½Π΄Π΅ΠΊΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ° Π² ΡΠΏΠΈΡΠΊΠ΅
if (oldIndex == -1) return // ΠΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌΡΡ, Π΅ΡΠ»ΠΈ Π½Π΅ Π½Π°Ρ
ΠΎΠ΄ΠΈΠΌ ΡΠ°ΠΊΠΎΠ³ΠΎ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°
val newIndex = oldIndex + moveBy // ΠΡΡΠΈΡΠ»ΡΠ΅ΠΌ Π½ΠΎΠ²ΡΠΉ ΠΈΠ½Π΄Π΅ΠΊΡ, Π½Π° ΠΊΠΎΡΠΎΡΠΎΠΌ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π½Π°Ρ
ΠΎΠ΄ΠΈΡΡΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ
persons = ArrayList(persons) // Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΠ²ΡΠΉ ΡΠΏΠΈΡΠΎΠΊ
Collections.swap(persons, oldIndex, newIndex) // ΠΠ΅Π½ΡΠ΅ΠΌ ΠΌΠ΅ΡΡΠ°ΠΌΠΈ Π»ΡΠ΄Π΅ΠΉ
}
ΠΠΎΡΠ»Π΅ ΡΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ Π±ΡΠ»ΠΈ ΡΠΎΠ·Π΄Π°Π½Ρ ΠΌΠ΅ΡΠΎΠ΄Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Ρ Π»ΡΠ΄ΡΠΌΠΈ, Π² ΠΊΠ»Π°ΡΡΠ΅ PersonService Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±ΡΡΠ²ΠΈΡΡ ΡΠ»ΡΡΠ°ΡΠ΅Π»Ρ:
typealias PersonListener = (persons: List<Person>) -> Unit
Π’Π°ΠΊ ΠΆΠ΅ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠΏΠΈΡΠΎΠΊ ΡΠ»ΡΡΠ°ΡΠ΅Π»Π΅ΠΉ, Π΄Π²Π° ΠΌΠ΅ΡΠΎΠ΄Π°, ΠΊΠΎΡΠΎΡΡΠ΅ Π±ΡΠ΄ΡΡ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ ΠΈ ΡΠ΄Π°Π»ΡΡΡ ΡΠ»ΡΡΠ°ΡΠ΅Π»Π΅ΠΉ, ΠΈ ΠΎΠ΄ΠΈΠ½, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ "ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°ΡΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ":
private var listeners = mutableListOf<PersonListener>() // ΠΡΠ΅ ΡΠ»ΡΡΠ°ΡΠ΅Π»ΠΈ
fun addListener(listener: PersonListener) {
listeners.add(listener)
listener.invoke(persons)
}
fun removeListener(listener: PersonListener) {
listeners.remove(listener)
listener.invoke(persons)
}
private fun notifyChanges() = listeners.forEach { it.invoke(persons) }
ΠΠ΅ΡΠΎΠ΄ notifyChanges Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΠΎ Π²ΡΠ·Π²Π°ΡΡ Π² ΠΌΠ΅ΡΠΎΠ΄Π°Ρ , Π² ΠΊΠΎΡΠΎΡΡΡ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡ ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡ Π΄Π°Π½Π½ΡΡ , ΡΠΎ Π΅ΡΡΡ Π² ΠΌΠ΅ΡΠΎΠ΄Π°Ρ likePerson, removePerson ΠΈ movePerson.
ΠΠ° ΡΡΠΎΠΌ Π½Π°Ρ ΡΠ΅ΡΠ²ΠΈΡ Π»ΡΠ΄Π΅ΠΉ ΠΏΠΎΠ»Π½ΠΎΡΡΡΡ Π³ΠΎΡΠΎΠ². ΠΠ΅ΡΠ΅ΠΉΠ΄Π΅ΠΌ Π² PersonAdapter, Π² ΠΊΠΎΡΠΎΡΠΎΠΌ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅ΠΌ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ ΡΠΎΠ±ΡΡΠΈΠΉ Π½Π°ΡΠΈΡ Π»ΡΠ΄Π΅ΠΉ. Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ PersonActionListener, Π² ΠΊΠΎΡΠΎΡΠΎΠΌ Π±ΡΠ΄Ρ ΡΠ΅ΡΡΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Π°:
- onPersonGetId - ΠΏΠΎΠ»ΡΡΠΈΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ Π²ΡΠ±ΡΠ°Π½Π½ΠΎΠ³ΠΎ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°;
- onPersonLike - ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ Π±ΡΠ» Π»Π°ΠΉΠΊΠ½ΡΡ;
- onPersonRemove - ΡΠ΄Π°Π»ΠΈΡΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°;
- onPersonMove - ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΡΠΈΡΡ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°.
interface PersonActionListener {
fun onPersonGetId(person: Person)
fun onPersonLike(person: Person)
fun onPersonRemove(person: Person)
fun onPersonMove(person: Person, moveBy: Int)
}
ΠΠ»Π°ΡΡ PersonAdapter Π²ΠΎ Π²Ρ ΠΎΠ΄Π½ΡΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ Π½Π°Ρ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ. Π’Π°ΠΊΠΆΠ΅ Π΄Π°Π½Π½ΡΠΉ ΠΊΠ»Π°ΡΡ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ OnClickListener. Π ΠΈΡΠΎΠ³Π΅ ΡΠΈΠ³Π½Π°ΡΡΡΠ° ΠΎΠ±ΡΡΠ²Π»Π΅Π½ΠΈΡ ΠΊΠ»Π°ΡΡΠ° PersonAdaper Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ:
class PersonAdapter(private val personActionListener: PersonActionListener) :
RecyclerView.Adapter<PersonAdapter.PersonViewHolder>(), View.OnClickListener {
Π’Π΅ΠΏΠ΅ΡΡ Π² ΠΊΠ»Π°ΡΡΠ΅ PersonAdapter Π² ΠΌΠ΅ΡΠΎΠ΄Π΅ onBindViewHolder ΠΊΠ»Π°Π΄ΡΠΌ Π² tag ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ view, Π½Π° ΠΊΠΎΡΠΎΡΡΡ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡΡ Π½Π°ΠΆΠ°ΡΠΈΠ΅, Π½ΡΠΆΠ½ΠΎΠ³ΠΎ ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°:
holder.itemView.tag = person
holder.binding.likedImageView.tag = person
holder.binding.more.tag = person
Π’Π΅ΠΏΠ΅ΡΡ Π² ΠΌΠ΅ΡΠΎΠ΄Π΅ onCreateViewHolder Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΡΠΎΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΠ»ΡΡΠ°ΡΠ΅Π»Π΅ΠΉ ΠΏΡΠΈ Π½Π°ΠΆΠ°ΡΠΈΠΈ. Π Π΄Π°Π½Π½ΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅ Π±ΡΠ΄Π΅Ρ ΡΠ»ΡΡΠ°ΡΠ΅Π»Ρ Π½Π° Π½Π°ΠΆΠ°ΡΠΈΠ΅ Π½Π° ΡΠ»Π΅ΠΌΠ΅Π½Ρ ΡΠΏΠΈΡΠΊΠ°, ΠΊΠ½ΠΎΠΏΠΊΡ more (ΡΡΠΈ ΡΠΎΡΠΊΠΈ) ΠΈ likedImageView (ΡΠ΅ΡΠ΄ΡΠ΅):
binding.root.setOnClickListener(this)
binding.more.setOnClickListener(this)
binding.likedImageView.setOnClickListener(this)
Π’Π΅ΠΏΠ΅ΡΡ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΌΠ΅ΡΠΎΠ΄ showPopupMenu, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ "ΡΠΈΡΠΎΠ²Π°ΡΡ" Π²ΡΠΏΠ°Π΄Π°ΡΡΠ΅Π΅ ΠΌΠ΅Π½Ρ Ρ Π΄ΠΎΡΡΡΠΏΠ½ΡΠΌΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠΌΠΈ, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ: ΡΠ΄Π°Π»ΠΈΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ, ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΡΠΈΡΡ Π²Π²Π΅ΡΡ , ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΡΠΈΡΡ Π²Π½ΠΈΠ·:
private fun showPopupMenu(view: View) {
val popupMenu = PopupMenu(view.context, view)
val person = view.tag as Person
val position = data.indexOfFirst { it.id == person.id }
popupMenu.menu.add(0, ID_MOVE_UP, Menu.NONE, "Up").apply {
isEnabled = position > 0
}
popupMenu.menu.add(0, ID_MOVE_DOWN, Menu.NONE, "Down").apply {
isEnabled = position < data.size - 1
}
popupMenu.menu.add(0, ID_REMOVE, Menu.NONE, "Remove")
popupMenu.setOnMenuItemClickListener {
when (it.itemId) {
ID_MOVE_UP -> personActionListener.onPersonMove(person, -1)
ID_MOVE_DOWN -> personActionListener.onPersonMove(person, 1)
ID_REMOVE -> personActionListener.onPersonRemove(person)
}
return@setOnMenuItemClickListener true
}
popupMenu.show()
}
companion object {
private const val ID_MOVE_UP = 1
private const val ID_MOVE_DOWN = 2
private const val ID_REMOVE = 3
}
Π ΠΌΠ΅ΡΠΎΠ΄Π΅ onClick ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π΅ΠΌ Π½Π°ΠΆΠ°ΡΠΈΡ Π½Π° ΡΠ»Π΅ΠΌΠ΅Π½ΡΡ ΡΠΏΠΈΡΠΊΠ°:
override fun onClick(view: View) {
val person: Person = view.tag as Person // ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ ΠΈΠ· ΡΡΠ³Π° ΡΠ΅Π»ΠΎΠ²Π΅ΠΊΠ°
when (view.id) {
R.id.more -> showPopupMenu(view)
R.id.likedImageView -> personActionListener.onPersonLike(person)
else -> personActionListener.onPersonGetId(person)
}
}
ΠΠ° ΡΡΠΎΠΌ Π½Π°Ρ Π°Π΄Π°ΠΏΡΠ΅Ρ Π³ΠΎΡΠΎΠ². Π’Π΅ΠΏΠ΅ΡΡ ΠΏΠ΅ΡΠ΅ΠΉΠ΄Π΅ΠΌ Π² MainActivity ΠΈ, ΠΏΡΠΈ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π½Π°ΡΠ΅Π³ΠΎ Π°Π΄Π°ΠΏΡΠ΅ΡΠ°, ΠΏΠ΅ΡΠ΅Π΄Π°Π΄ΠΈΠΌ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ°:
adapter = PersonAdapter(object : PersonActionListener { // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
override fun onPersonGetId(person: Person) =
Toast.makeText(this@MainActivity, "Persons ID: ${person.id}", Toast.LENGTH_SHORT).show()
override fun onPersonLike(person: Person) = personService.likePerson(person)
override fun onPersonRemove(person: Person) = personService.removePerson(person)
override fun onPersonMove(person: Person, moveBy: Int) = personService.movePerson(person, moveBy)
})
Π’Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΡΠ»ΡΡΠ°ΡΠ΅Π»Ρ Π² MainActivity, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΡΠ»ΡΡΠΈΠ²Π°ΡΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ, ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΡΡΠΈΠ΅ Π² PersonService:
private val listener: PersonListener = {adapter.data = it}
Π Π² ΠΌΠ΅ΡΠΎΠ΄Π΅ onCreate Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΡΡΠΎΠ³ΠΎ ΡΠ»ΡΡΠ°ΡΠ΅Π»Ρ:
personService.addListener(listener)
ΠΠ° ΡΡΠΎΠΌ Π½Π°ΡΠ° ΡΠ°Π±ΠΎΡΠ° Π²ΡΠΏΠΎΠ»Π½Π΅Π½Π°. ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ ΠΏΡΠΎΠ΅ΠΊΡ ΠΈ ΡΠΌΠΎΡΡΠΈΠΌ ΡΠ΅Π·ΡΠ»ΡΡΠ°Ρ:
ΠΡ ΡΠ°ΡΡΠΌΠΎΡΡΠ΅Π»ΠΈ ΠΎΡΠ½ΠΎΠ²Ρ RecyclerView. ΠΡΡΠ΅ΡΡΠ²Π΅Π½Π½ΠΎ ΡΡΠΎ Π΄Π°Π»Π΅ΠΊΠΎ Π½Π΅ Π²ΡΠ΅, ΡΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠ΄Π΅Π»Π°ΡΡ ΡΡΠΎΡ ΠΌΠΎΡΠ½ΡΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ. ΠΡΠ΅Π³Π΄Π° ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ DiffUtil, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΠΏΠΈΡΠΎΠΊ, ItemDecorator, Π΄Π»Ρ Π΄Π΅ΠΊΠΎΡΠ° Π½Π°ΡΠΈΡ
ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΠΈ Ρ.Π΄.
Π‘ΡΡΠ»ΠΊΠ° Π½Π° ΡΡΠ°ΡΡΡ Π½Π° Habr.
π Π― Π½Π°Π΄Π΅ΡΡΡ, ΡΡΠΎ Π΄Π°Π½Π½Π°Ρ ΡΠ°Π±ΠΎΡΠ° ΠΏΠΎΠΌΠΎΠ³Π»Π° ΠΠ°ΠΌ.
π§ ΠΡΠΈ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠΈ ΠΊΠ°ΠΊΠΈΡ
-Π»ΠΈΠ±ΠΎ Π²ΠΎΠΏΡΠΎΡΠΎΠ² ΠΈ ΠΏΡΠ΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠΉ - ΡΠ²ΡΠΆΠΈΡΠ΅ΡΡ ΡΠΎ ΠΌΠ½ΠΎΠΉ.
π€ Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ, ΡΡΠΎ Π·Π°ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠΎΠ²Π°Π»ΠΈΡΡ Π΄Π°Π½Π½ΠΎΠΉ ΡΠ°Π±ΠΎΡΠΎΠΉ.