
Здравствуйте дорогие хабрчане. Это статья основана на статье, написанной в 2017 году на Java. А статью которую вы читаете, уже на Kotlin.
Каждый раз, когда мы думаем о создании RecyclerView, нас пугает объем кода, который должен войти в адаптер. Кроме того, если у этого адаптера много ViewHolder-ов, то спаси нас Бог!
Конечно, все мы знакомы с шаблонным кодом RecyclerView.Adapter. Но писать один и тот же код снова и снова — пустая трата времени.
Наверняка должен быть лучший способ?
Поздоровайтесь с FastAdapter!
Пуленепробиваемая, быстрая и простая в использовании библиотека адаптеров, которая сводит время разработки к минимуму… — Майк Пенз
FastAdapter создан Майком Пензом. Разработчик популярных библиотек, таких как MaterialDrawer и AboutLibraries.
FastAdapter сокращает время, затрачиваемое на код адаптера. Более того, он предлагает множество функций, поэтому никоим образом не ограничивает ваше приложение. Благодаря множеству предлагаемых функций подумайте о замене «обычных» адаптеров RecyclerView на FastAdapter.
Приступим к работе
Для начала использования FastAdapter-а, нужно добавить в build.gradle следующие зависимости:
Проверьте подключена ли зависимость:
implementation "androidx.appcompat:appcompat:${androidX}" implementation "com.mikepenz:fastadapter:${latestFastAdapter" implementation "androidx.recyclerview:recyclerview:1.2.1"
Для использования ViewBinding-а
implementation "com.mikepenz:fastadapter-extensions-binding:5.5.1" implementation "com.mikepenz:fastadapter-extensions-diff:5.5.1"
Не забудьте, что должен быть подключен ViewBinding
Создаем data class
Допустим, мы создаем приложение прогноза погоды. Поэтому я называю свой класс Weather.
data class Weather( val temperature: Double, val humidity: Int, var windSpeed: Double, val pressure: Double )
Создаем xml файл weather_item.xml
<?xml version="1.0" encoding="utf-8"?> <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/rowLayout" android:layout_width="wrap_content" android:layout_height="114dp" android:layout_gravity="center" android:layout_margin="6dp" app:cardCornerRadius="16dp" app:cardElevation="0dp"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/temperatureTextView" android:layout_width="wrap_content" android:layout_height="24dp" android:layout_gravity="center" android:layout_marginStart="8dp" android:layout_marginTop="12dp" android:layout_marginEnd="8dp" /> <TextView android:id="@+id/humidityTextView" android:layout_width="wrap_content" android:layout_height="24dp" android:layout_gravity="center" android:layout_marginStart="8dp" android:layout_marginTop="12dp" android:layout_marginEnd="8dp" /> <TextView android:id="@+id/windSpeedTextView" android:layout_width="wrap_content" android:layout_height="24dp" android:layout_gravity="center" android:layout_marginStart="8dp" android:layout_marginTop="12dp" android:layout_marginEnd="8dp" /> <TextView android:id="@+id/pressureTextView" android:layout_width="wrap_content" android:layout_height="24dp" android:layout_gravity="center" android:layout_marginStart="8dp" android:layout_marginTop="12dp" android:layout_marginEnd="8dp" /> </LinearLayout> </com.google.android.material.card.MaterialCardView>
Внедряем адаптер
Cоздаем класс, который реализуетAbstractBindingItem
-
type()— возвращает уникальный id (вашего родительского макета) -
bindView()— метод onBindViewHolder() RecyclerView
class WeatherItem(val weather: Weather) :
AbstractBindingItem<WeatherItemBinding>() {
Реализовываем identifier таким образом, чтобы у каждого элемента было своё уникальное значение
override var identifier: Long get() = weather.hashCode().toLong() set(value) {} override val type: Int get() = R.id.weatherRecyclerView override fun createBinding( inflater: LayoutInflater, parent: ViewGroup? ): WeatherItemBinding { return WeatherItemBinding.inflate(inflater, parent, false) } override fun bindView(binding: WeatherItemBinding, payloads: List<Any>) { binding.temperatureTextView.text = weather.temperature.toString() binding.humidityTextView.text = weather.humidity.toString() binding.pressureTextView.text = weather.pressure.toString() binding.windSpeedTextView.text = weather.windSpeed.toString() } override fun unbindView(binding: WeatherItemBinding) { binding.temperatureTextView.text = null binding.humidityTextView.text = null binding.pressureTextView.text = null binding.windSpeedTextView.text = null } }
Прикрепляем FastAdapter к нашему RecyclerView
binding.weatherRecyclerView.setLayoutManager( LinearLayoutManager( this, LinearLayoutManager.VERTICAL, false ) ) val weatherItemAdapter = ItemAdapter<WeatherItem>() val weatherFastAdapter = FastAdapter.with(weatherItemAdapter) binding.weatherRecyclerView.adapter = weatherFastAdapter val weatherList = weatherForecastForNextDays
map используем для конвертации списка погоды в AbstractBindingItem
FastAdapterDiffUtil[weatherItemAdapter] =
weatherList.map(::WeatherItem)
FastAdapterDiffUtil предназначен для обновления списка. Он заменяет элементы внутри адаптера новым набором элементов. Одним предложением — меняет не весь список, а лишь те item-ы которые поменялись.
Это все, что нам нужно сделать! Если мы запустим наше приложение сейчас, мы получим RecyclerView, заполненный списком.
Поэтому вместо того, чтобы рассматривать то, что мы только что сделали. Давайте рассмотрим, что мы НЕ делали для нашего адаптера:
-
класс
RecyclerView.Adapter -
inflateitem-а -
getItemCount()
А теперь рассмотрим некоторые популярные функции RecyclerView реализованные с помощью FastAdapter:
-
Click Listener
weatherFastAdapter .onClickListener = { view, adapter, item, position -> // обработка клика false } -
Фильтрация данных с помощью поиска
Если наше приложение использует SearchView, и мы хотим отфильтровать данные нашего адаптера, то
FastAdapterможет это сделать.weatherItemAdapter.filter("yourSearchTerm") weatherItemAdapter.itemFilter.filterPredicate = { item: WeatherItem, constraint: CharSequence? -> item.weather.temperature.toString().contains(constraint.toString(), ignoreCase = true) } -
Drag & Drop
Начните с создания экземпляра
SimpleSwipeDrawerDragCallback(любезно предоставленногоFastAdapter-ом). Затем используйте его для инициализацииItemTouchHelper-а. Наконец, прикрепитеItemTouchHelper к RecyclerView.
touchCallback = SimpleSwipeDrawerDragCallback( this, ItemTouchHelper.LEFT ) .withNotifyAllDrops(true) .withSwipeLeft(80) .withSensitivity(10f) .withSurfaceThreshold(0.3f) touchHelper = ItemTouchHelper(touchCallback) touchHelper.attachToRecyclerView(binding.cityListRecyclerview)
Внедрите интерфейс ItemTouchCallback. Он реализует метод itemTouchOnMove(). Добавьте к нему следующий код:
override fun itemTouchOnMove(oldPosition: Int, newPosition: Int): Boolean { DragDropUtil.onMove( cityWeatherItemFastAdapter.itemAdapter, oldPosition, newPosition ) viewModel.changingOrderList(oldPosition, newPosition) return true }
Итоги
Магия RecyclerView заключается в его адаптере. FastAdapter знает это и упрощает его. Это больше, чем просто удобная библиотека. Если вы выполняете много манипуляций с адаптером, то наличие FastAdapter-а в вашем арсенале абсолютно необходимо!
ссылка на оригинал статьи https://habr.com/ru/post/599851/
Добавить комментарий