Урок Kotlin в Android Studio: SwipeRefreshLayout обновление

Когда пользователь листает ленту или список сообщений, ему удобно обновить содержимое, просто потянув экран вниз. Этот жест называется pull-to-refresh, и в Android для него существует готовый компонент — SwipeRefreshLayout. В этом занятии для Android Studio мы на языке Kotlin разберём, как обернуть список в такой контейнер и настроить обновление данных. Материал построен так, чтобы даже новичок смог добавить знакомый жест в своё приложение за несколько минут.


Знакомство со SwipeRefreshLayout

SwipeRefreshLayout — это контейнер из библиотеки AndroidX, который добавляет своему единственному дочернему элементу возможность реагировать на жест смахивания вниз. При свайпе появляется анимированный индикатор, а когда данные обновлены, он исчезает. Компонент работает с любым прокручиваемым содержимым: RecyclerView, ListView, ScrollView и их наследниками.

Главное, что нужно запомнить: setOnRefreshListener задаёт действие при жесте, а isRefreshing = false прячет индикатор, когда работа завершена. Этих двух методов достаточно для большинства сценариев.


Подключаем библиотеку

SwipeRefreshLayout требует отдельной зависимости, хотя и входит в семейство AndroidX. Откройте build.gradle.kts уровня модуля app и добавьте строку:

dependencies {
    implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
}

После синхронизации Gradle компонент станет доступен в палитре разметки.


Размещение в XML

В файле activity_main.xml замените корневой элемент на SwipeRefreshLayout, а внутри оставьте RecyclerView. Важно, чтобы список был единственным прямым потомком контейнера.

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipeRefresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

Программная настройка в Activity

В MainActivity.kt получим ссылки на SwipeRefreshLayout и RecyclerView, настроим адаптер (возьмём простой список строк), а затем установим слушатель на жест. При свайпе вниз будем имитировать загрузку нового элемента: добавим строку в начало списка и через задержку скроем индикатор.

class MainActivity : AppCompatActivity() {
    private val items = mutableListOf("Первый", "Второй", "Третий")
    private lateinit var adapter: ArrayAdapter<String>

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

        val swipeRefresh = findViewById<SwipeRefreshLayout>(R.id.swipeRefresh)
        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)

        adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, items)
        recyclerView.adapter = adapter

        swipeRefresh.setOnRefreshListener {
            // имитация обновления данных
            Handler(Looper.getMainLooper()).postDelayed({
                items.add(0, "Новый элемент ${items.size + 1}")
                adapter.notifyItemInserted(0)
                swipeRefresh.isRefreshing = false
            }, 2000) // задержка 2 секунды
        }
    }
}

Handler с задержкой здесь просто для демонстрации. В реальном проекте на этом месте будет запрос к серверу или базе данных, после которого вы вызовете isRefreshing = false.


Современный вариант с корутиной и ViewBinding

Использование корутин и ViewBinding делает код чище. Принцип тот же, но вместо Handler мы применяем lifecycleScope.launch и delay.

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    // ... настройка RecyclerView ...

    binding.swipeRefresh.setOnRefreshListener {
        lifecycleScope.launch {
            delay(1500) // имитация загрузки
            items.add(0, "Свежая запись")
            adapter.notifyItemInserted(0)
            binding.swipeRefresh.isRefreshing = false
        }
    }
}

Цветовое оформление индикатора

Чтобы вращающийся круг вписывался в дизайн, измените его цвета через setColorSchemeResources. Вызовите этот метод сразу после получения ссылки на SwipeRefreshLayout.

swipeRefresh.setColorSchemeResources(
    android.R.color.holo_blue_bright,
    android.R.color.holo_green_light,
    android.R.color.holo_orange_light
)

Несколько замечаний для начинающих

  • Всегда отключайте индикатор после обновления. Если забыть установить isRefreshing = false, кружок будет вращаться бесконечно, и пользователь решит, что приложение зависло.
  • Не используйте SwipeRefreshLayout для начальной загрузки. Для отображения прогресса при первом входе на экран лучше подойдёт ProgressBar или Shimmer-анимация.
  • Проверяйте, не идёт ли уже обновление. Повторный свайп во время выполнения фоновой задачи может вызвать дублирование запросов.

Коротко о главном

Сегодняшний урок в Android Studio на языке Kotlin показал, как оживить список с помощью SwipeRefreshLayout. Вы обернули RecyclerView в контейнер, настроили обработку жеста и научились скрывать индикатор после завершения работы. Теперь в вашем приложении появился стандартный pull-to-refresh, к которому привыкли пользователи. Попробуйте реализовать настоящее обновление данных с сервера — так вы закрепите навык и сделаете интерфейс ещё удобнее.