Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

SwipeRefreshLayout

Пример на Kotlin
Устаревший пример для Java

В марте 2014 года был представлен новый компонент android.support.v4.widget.SwipeRefreshLayout, который входил в состав библиотеки Support Library v4. Сейчас это отдельная библиотека в составе AndroidX.

Компонент позволяет отказаться от сторонних библиотек и собственных велосипедов для реализации шаблона "Pull to Refresh", когда пользователь сдвигает экран, чтобы обновить данные. Подобное поведение можно увидеть в клиентах для Твиттера, чтобы получить новую порцию твитов, не дожидаясь, когда список сообщений обновится самостоятельно.

Пример на Kotlin

В марте 2020 года обзавелась стабильной версией.


implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"

Подготовим макет.


<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/textView"
            android:text="Hello Kitty"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:gravity="center"/>
    </ScrollView>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

В методах setColorSchemeColors() или setColorSchemeResources() следует указать используемые цвета.

Компонент достаточно интересный с занимательной анимацией. Вначале анимация представляла собой цветные полоски под заголовком программы. Позже анимацию заменили в стиле Material Design, теперь это маленький кружочек, внутри которого крутятся цветные линии (или чёрная линия, если не использовать метод setColorSchemeResources() со цветами).


package ru.alexanderklimov.swipe

import android.os.Bundle
import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*

class MainActivity : AppCompatActivity() {

    private lateinit var random: Random
    private lateinit var handler: Handler
    private lateinit var runnable: Runnable

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        random = Random()
        handler = Handler()

        swipeRefreshLayout.setOnRefreshListener {
            // Initialize a new Runnable
            runnable = Runnable {
                // Update the text view text with a random number
                textView.text = "Котика пора кормить. Его не кормили уже ${1 + random.nextInt(10)} минут"

                // Hide swipe to refresh icon animation
                swipeRefreshLayout.isRefreshing = false
            }

            // Execute the task after specified time
            handler.postDelayed(
                runnable, 3000.toLong()
            )
        }

        swipeRefreshLayout.setColorSchemeResources(
            android.R.color.holo_blue_bright,
            android.R.color.holo_green_light,
            android.R.color.holo_orange_light,
            android.R.color.holo_red_light
        )
    }
}

Запустите пример и потяните экран сверх вниз, чтобы увидеть эффект обновления данных.

Устаревший пример для Java

Обернём компоненты родительским элементом SwipeRefreshLayout. На панели инструментов данного компонента нет, поэтому придётся писать код вручную.


<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
        <TextView
            android:id="@+id/textViewCat"
            android:text="Hello Kitty"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:gravity="center"/>
    </ScrollView>
 
</android.support.v4.widget.SwipeRefreshLayout>

Код:


package ru.alexanderklimov.swipe;

import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import java.util.Random;

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {

    private SwipeRefreshLayout mSwipeRefreshLayout;
    private TextView mCatTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mCatTextView = findViewById(R.id.textViewCat);

        mSwipeRefreshLayout = findViewById(R.id.swipe_container);
        mSwipeRefreshLayout.setOnRefreshListener(this);

        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
                android.R.color.holo_green_light,
                android.R.color.holo_orange_light,
                android.R.color.holo_red_light);

        // Альтернативный способ
        //  mSwipeRefreshLayout.setColorSchemeColors(
        //  Color.RED, Color.GREEN, Color.BLUE, Color.CYAN);
    }

    @Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                // Отменяем анимацию обновления
                mSwipeRefreshLayout.setRefreshing(false);
                Random random = new Random();
                mCatTextView.setText("Котика пора кормить. Его не кормили уже "
                        + (1 + random.nextInt(10)) + " мин.");
            }
        }, 4000);
    }
}

В примере реализуется интерфейс OnRefreshListener с методом onRefresh(), в котором следует обновить поступающие данные. В нашем случае просто генерируются случайные числа.

При первом появлении библиотеки использовался метод setColorScheme(), который объявлен устаревшим. Вместо него появились два новых метода setColorSchemeColors() и setColorSchemeResources(). Принцип остался тот же, вам нужно указать четыре цвета по константам Color.XXX или из ресурсов. Вы можете не использовать вызов метода с цветными линиями, тогда будет выводиться только чёрная линия по умолчанию.

Компонент достаточно интересный с занимательной анимацией. Вначале анимация представляла собой цветные полоски под заголовком программы, как представлено на видео.

Позже анимацию заменили в стиле Material Design, теперь это маленький кружочек, внутри которого крутятся цветные линии (или чёрная линия, если не использовать метод setColorSchemeResources() со цветами).

Обновляем список

По такому же принципу обновляем данные в списке.


<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</android.support.v4.widget.SwipeRefreshLayout>

При каждой попытке обновить список будет добавляться текущая дата и время.


import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


public class MainActivity extends AppCompatActivity {

    private SwipeRefreshLayout mSwipeRefreshLayout;
    private ListView mListView;

    private List<String> mList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
		
        setContentView(R.layout.activity_main);

        mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                String currentDateTime = DateFormat.getDateTimeInstance().format(new Date());
                mList.add(currentDateTime);
                mListView.invalidateViews();
                mSwipeRefreshLayout.setRefreshing(false);
            }
        });

        mListView = findViewById(R.id.listView);

        mList = new ArrayList<>();
        ListAdapter mAdapter = new ArrayAdapter<>(
                this, android.R.layout.simple_list_item_1, mList);
        mListView.setAdapter(mAdapter);
    }
}

Не забывайте, что обновление может занимать длительное время и использовать сеть для получения данных. Поэтому следует позаботиться о выполнении в другом потоке.

Дополнительное чтение

Обновляем страницу в WebView

vaigunth/card-printer: Pull down to refresh - card printer

Cleveroad/FireworkyPullToRefresh: Let's try to refresh your data with our library! - интересный эффект обновления.

Реклама