Pull-to-Refresh: mga batayan, RefreshControl at UIRefreshControl

May-akda: IT Sectr Nai-publish: 2026-02-27 Oras ng pagbabasa: 8 min
Pull-to-Refresh — isang pattern ng mobile interface kung saan hinihila ng user ang listahan pababa gamit ang daliri, na nag-uumpisa ng pagkarga ng sariwang data. Ang kilos ay sinamahan ng isang visual na indicator — umiikot na spinner o animated na icon — na nawawala pagkatapos makumpleto ang pagkarga. Ayon sa UX analysis ng Apple HIG, ang Pull-to-Refresh ay naging karaniwang mekanismo ng pag-update ng nilalaman sa mga news feed, social network, at email client mula nang ipatupad ito sa Tweetie (2008) at kasunod na standardisasyon ng Apple at Google.

Mga Pangunahing Punto

  • Pull-to-Refresh — kilos ng paghila ng listahan pababa para i-update ang data, sinamahan ng visual na indicator ng pagkarga.
  • Sa iOS ginagamit ang UIRefreshControl (iOS 6+), idinadagdag sa UITableViewController o UIScrollView sa pamamagitan ng property na refreshControl.
  • Sa Android ginagamit ang SwipeRefreshLayout (mula sa Support Library) — isang ViewGroup-wrapper para sa RecyclerView o NestedScrollView.
  • Parehong API ay sumusuporta sa pag-customize ng mga kulay, indicator, at callback sa pamamagitan ng listener (iOS: UIRefreshControl.target-action, Android: setOnRefreshListener).
  • Awtomatikong nabablock ang Pull-to-Refresh kapag ang listahan ay wala sa tuktok na posisyon — ang conflict sa pag-scroll ay hindi kasama sa arkitektura.

Ano ang Pull-to-Refresh?

Pull-to-Refresh — isang pattern ng interface ng gumagamit kung saan hinihila ng user (pull down) ang isang listahan o lugar na pwedeng i-scroll pababa para i-update ang nilalaman. Biswal, ang kilos ay sinamahan ng isang indicator ng pagkarga (spinner) na lumilitaw sa tuktok ng screen at nawawala pagkatapos matanggap ang data. Ang pattern ay pinasikat ng Tweetie app para sa iPhone (2008) at kalaunan ay na-standardize ng Apple (iOS 6 — UIRefreshControl) at Google (Android Support Library — SwipeRefreshLayout).

Sa teknikal na pananaw, ang Pull-to-Refresh ay kombinasyon ng panning (pagsubaybay sa paggalaw ng daliri) at trigger kapag naabot ang threshold. Hinihila ng user ang listahan pababa, nilalampasan ang resistensya (resistive overscroll), at pagkatapos lumampas sa threshold (~80px sa iOS, ~64dp sa Android) magsisimula ang animation ng indicator at asynchronous na pagkarga. Kung bitawan ng user ang daliri bago ang threshold — babalik ang listahan sa orihinal na posisyon nang walang pag-update.

Ayon sa Material Design Guidelines, ang Pull-to-Refresh ay hindi dapat gamitin para sa nabigasyon o pagpapalit ng tab — ang tanging layunin nito ay pag-update ng data. Sa IT Sectr inilalapat namin ang Pull-to-Refresh sa mga news feed, listahan ng order, at chat, kung saan ang pagiging bago ng data ay kritikal para sa karanasan ng user.

Pull-to-Refresh sa iOS: UIRefreshControl

UIRefreshControl — ang karaniwang control element ng iOS para sa Pull-to-Refresh, available mula noong iOS 6. Ang UIRefreshControl ay idinadagdag sa UITableViewController sa pamamagitan ng property na refreshControl (iOS 10+) o bilang subview ng table sa mas lumang bersyon. Naglalaman ito ng built-in na spinner na may nako-configure na kulay (tintColor), attribute na title, at attributed string na may label (halimbawa, “Nag-a-update...”).

Ang UIRefreshControl ay gumagana sa pamamagitan ng target-action mechanism: kapag na-activate ang kilos, tinatawag ang tinukoy na method (halimbawa, refresh(_:)). Sa loob ng method, isinasagawa ang asynchronous na pagkarga ng data. Pagkatapos makumpleto, tinatawag ang endRefreshing(), na nagtatago ng indicator na may animation. Awtomatikong pinamamahalaan ng UIRefreshControl ang sensitivity ng kilos — naa-activate lamang ito sa tuktok na posisyon ng table (contentOffset.y <= 0).

Ang property na tintColor ay nagtatakda ng kulay ng spinner. Ang mga attribute na title ay nagpapahintulot na magpakita ng tekstong “Na-update 2 minuto ang nakalipas” pagkatapos makumpleto. Mula iOS 10, sinusuportahan ng UIRefreshControl ang custom na animation sa pamamagitan ng UIActivityIndicatorView o persistent custom views. Sa IT Sectr inaayos namin ang tintColor sa brand at ipinapakita ang oras ng huling pag-update sa pamamagitan ng attributedTitle — pinapataas nito ang tiwala ng user sa data.

Pull-to-Refresh sa Android: SwipeRefreshLayout

SwipeRefreshLayout — isang ViewGroup mula sa Android Support Library (androidx.swiperefreshlayout) na bumabalot ng nai-scroll na nilalaman (RecyclerView, NestedScrollView, ListView) at nagdaragdag ng functionality ng Pull-to-Refresh. Hindi tulad ng UIRefreshControl (na isang control, hindi container), ang SwipeRefreshLayout ay isang container na humaharang sa touch events ng anak at nag-a-activate ng update indicator kapag lumampas sa threshold.

Ang SwipeRefreshLayout ay gumagamit ng circular progress indicator ng Material Design na may configuration ng kulay sa pamamagitan ng setColorSchemeColors(). Ang method na setOnRefreshListener ay nagtatakda ng callback na onRefresh(), kung saan isinasagawa ang asynchronous na pagkarga. Pagkatapos makumpleto, tinatawag ang setRefreshing(false) para itago ang indicator. Mahalaga: ang setRefreshing(true) ay tumatawag muli ng onRefresh() — kaya para sa programmatic na pagsisimula ng pag-update, gumamit ng flag o post method.

Ang property na setProgressBackgroundColorSchemeResource ay nagbabago ng background ng indicator. setSize(SwipeRefreshLayout.LARGE) — laki ng spinner. Sa XML layout, bumabalot ang SwipeRefreshLayout ng RecyclerView: swipe_refresh_layout → recycler_view. Ayon sa Google I/O 2024, ang SwipeRefreshLayout ay ginagamit sa 85% ng Android apps na may content feed. Sa IT Sectr binabalot namin ang lahat ng screen na may asynchronously loaded na listahan sa SwipeRefreshLayout — nagbibigay ito ng pare-parehong UX sa lahat ng bersyon ng Android.

Material Pull-to-Refresh (Android 12+)

Mula Android 12 (Material You), inirerekomenda ng Google ang paggamit ng bagong Material Pull-to-Refresh mula sa library na material-1.6.0+ (androidx.compose.material3.pulltorefresh para sa Compose). Ang bagong API ay gumagamit ng animated na indicator na may suporta para sa spring animation at adaptive na kulay batay sa wallpaper. Ang SwipeRefreshLayout ay nananatiling compatible para sa mga bersyon na mas mababa sa Android 12.

Pinakamahuhusay na kasanayan at karaniwang pagkakamali

Pull-to-Refresh — isang pattern na madaling ipatupad, ngunit naglalaman ng ilang karaniwang pagkakamali na nagpapababa ng UX. Suriin natin ang mga ito at mga paraan ng pag-iwas.

  • Dobleng pag-update — maaaring hilahin ng user ang listahan nang maraming beses bago matapos ang pagkarga. Solusyon: itakda ang flag na isRefreshing sa simula at suriin ito sa onRefresh(). Sa iOS, ang endRefreshing() ay tinatawag lamang pagkatapos makumpleto; ang pag-block ng kilos sa UIRefreshControl ay built-in.
  • Kakulangan ng feedback — ang indicator ng pagkarga ay dapat lumitaw pagkatapos lampasan ng user ang threshold. Huwag ipakita ang indicator kaagad sa pagpindot — ito ay nakakalito. Ginagawa ito ng iOS at Android nang awtomatiko.
  • Pagbalewala sa oras ng pag-update — kung ang data ay na-update sa loob ng 200 ms, ang indicator ay dapat ipakita nang hindi bababa sa 500 ms upang mapansin ng user ang pag-update. Ang UIRefreshControl ay may pinakamababang oras ng animation; sa Android gumamit ng Handler.postDelayed para sa pinakamababang oras ng pagpapakita.
  • Conflict sa keyboard — sa bukas na keyboard, ang Pull-to-Refresh ay maaaring aksidenteng ma-trigger. Itago ang keyboard sa simula ng kilos sa pamamagitan ng view.endEditing(true) sa iOS at InputMethodManager.hideSoftInputFromWindow() sa Android.
  • Paggamit hindi para sa pag-update — huwag gamitin ang Pull-to-Refresh para sa nabigasyon (pagpapalit ng tab, pagbalik). Lumalabag ito sa HIG ng parehong platform at nakakalito sa mga user.

Sa IT Sectr nagdagdag kami ng pagsusuri ng isRefreshing sa bawat proyekto pagkatapos matuklasan ang mga duplicate na kahilingan sa log ng test server — lumabas na ang mga user na may mabilis na daliri ay nagti-trigger ng pag-update nang hanggang 3 beses nang magkakasunod.

Mga halimbawa ng code sa Swift at Kotlin

Halimbawa 1: UIRefreshControl sa iOS (Swift)

Nagdaragdag ng Pull-to-Refresh sa UITableViewController na may custom na kulay ng spinner at attributed title. Pagkatapos ma-load ang data, ang indicator ay itatago.

swift
import UIKit

class FeedTableViewController: UITableViewController {

    private var items: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.refreshControl = UIRefreshControl()
        refreshControl?.tintColor = .systemBlue
        refreshControl?.attributedTitle = NSAttributedString(
            string: “Hilahin para i-update”
        )
        refreshControl?.addTarget(
            self,
            action: #selector(refreshData),
            for: .valueChanged
        )
    }

    @objc private func refreshData() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
            self.items = FeedService().fetchLatest()
            self.tableView.reloadData()
            self.refreshControl?.endRefreshing()
        }
    }
}

Ang property na tableView.refreshControl (iOS 10+) ay nagtatakda ng UIRefreshControl. Ang addTarget na may kaganapang .valueChanged ay nagti-trigger kapag na-activate ang kilos. Ang endRefreshing() ay sapilitan — kung wala ito, ang indicator ay iikot nang walang hanggan. Ang asynchronous na pagkarga ay ginagaya sa pamamagitan ng DispatchQueue.main.asyncAfter — sa totoong proyekto ito ay magiging URLSession o async/await.

Halimbawa 2: SwipeRefreshLayout sa Android (Kotlin)

Bumabalot ng RecyclerView sa SwipeRefreshLayout na may custom na kulay ng indicator. Ang onRefresh ay nag-uumpisa ng pagkarga at itinatago ang indicator pagkatapos makumpleto.

kotlin
class FeedFragment : Fragment() {

    private var _binding: FragmentFeedBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentFeedBinding.inflate(inflater, container, false)

        binding.swipeRefreshLayout.setColorSchemeColors(
            resources.getColor(R.color.brand_blue, null),
            resources.getColor(R.color.brand_green, null)
        )
        binding.swipeRefreshLayout.setOnRefreshListener {
            loadData()
        }
        return binding.root
    }

    private fun loadData() {
        viewModelScope.launch {
            try {
                val result = repository.getLatestFeed()
                adapter.submitList(result)
            } finally {
                binding.swipeRefreshLayout.isRefreshing = false
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

Ang setColorSchemeColors ay nagtatakda ng mga kulay ng umiikot na Material Design indicator. Ang isRefreshing = false ay sapilitang tinatawag sa finally upang itago ang indicator kahit na may error sa pagkarga. Ang ViewModelScope.launch ay nagpapatakbo ng coroutine sa lifecycle ng fragment — kapag nawasak ang fragment, ang coroutine ay awtomatikong kinakansela, na pumipigil sa pagtagas ng memorya.

Halimbawa 3: SwiftUI .refreshable (iOS 15+)

Ang modernong SwiftUI ay nagbibigay ng modifier na .refreshable, na awtomatikong nagdaragdag ng Pull-to-Refresh sa List o ScrollView.

swift
import SwiftUI

struct FeedView: View {

    @State private var items: [String] = []

    var body: some View {
        List(items, id: \.self) { item in
            Text(item)
        }
        .refreshable {
            items = await FeedService().fetchLatestAsync()
        }
    }
}

Ang modifier na .refreshable ay tumatanggap ng async-closure na isinasagawa sa Pull-to-Refresh. Awtomatikong ipinapakita at itinatago ng SwiftUI ang update indicator, pinamamahalaan ang race condition (hindi nagsisimula ng reload hanggang sa matapos ang kasalukuyan) at iniaangkop ang animation sa platform. Para sa iOS 15+ ito ang preferred na paraan ng pagpapatupad ng Pull-to-Refresh sa SwiftUI.

Mga Madalas Itanong

Gumagana ba ang Pull-to-Refresh sa SwiftUI?

Oo, ang SwiftUI ay nagbibigay ng modifier na .refreshable para sa List o ScrollView, available mula noong iOS 15. Sa loob ng closure, isinasagawa ang async code ng pagkarga ng data. Awtomatikong pinamamahalaan ng SwiftUI ang update indicator at hinaharangan ang muling pag-trigger hanggang sa matapos ang kasalukuyang pagkarga — ito ang karaniwang recommended na diskarte para sa mga bagong proyekto.

Paano maiiwasan ang dobleng pag-update?

Gamitin ang flag na isRefreshing: itakda ang true sa simula ng pagkarga at false pagkatapos makumpleto. Sa iOS, awtomatikong hinaharangan ng UIRefreshControl ang muling pagtawag hanggang sa matawag ang endRefreshing(). Sa Android, suriin ang SwipeRefreshLayout.isRefreshing sa simula ng onRefresh(): kung true — return. Ginagarantiyahan nito ang isang kahilingan bawat kilos.

Nagko-conflict ba ang Pull-to-Refresh sa pag-scroll ng listahan?

Ang UIRefreshControl at SwipeRefreshLayout ay naa-activate lamang sa tuktok na posisyon ng listahan (contentOffset == 0). Hindi kasama ng arkitektura ang conflict: habang ang listahan ay naka-scroll kahit 1px, ang Pull-to-Refresh na kilos ay hindi maa-activate. Kung magkaroon ng conflict — suriin ang nestedScrollingEnabled sa Android o ang pagkakaroon ng custom na GestureRecognizer na humaharang sa pagpindot.

Buod

  • Pull-to-Refresh — pattern ng pag-update ng data sa pamamagitan ng paghila ng listahan pababa, na-standardize ng Apple at Google sa lahat ng mobile platform.
  • UIRefreshControl sa iOS — control na may target-action, tintColor, attributedTitle at sapilitang endRefreshing().
  • SwipeRefreshLayout sa Android — ViewGroup container na may setOnRefreshListener, setColorSchemeColors at isRefreshing.
  • Material Pull-to-Refresh (Android 12+) — bagong API na may spring animation, inirerekomenda para sa mga bagong proyekto.
  • SwiftUI .refreshable — declarative modifier na may async-closure, available mula noong iOS 15.
  • Ang flag na isRefreshing ay pumipigil sa dobleng pag-update — sapilitan sa parehong platform.
  • Ang Pull-to-Refresh ay hindi para sa nabigasyon — para lamang sa pag-update ng nilalaman ayon sa Material Design at Apple HIG.

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din