Əsas məqamlar
Pull-to-Refresh — istifadəçinin məzmunu yeniləmək üçün siyahını və ya sürüşdürülən sahəni aşağı çəkdiyi istifadəçi interfeysi nümunəsidir. Vizual olaraq jest ekranın yuxarı hissəsində görünən və məlumat alındıqdan sonra yox olan yükləmə göstəricisi (spinner) ilə müşayiət olunur. Bu nümunə iPhone üçün Tweetie tətbiqi (2008) tərəfindən populyarlaşdırılıb və sonradan Apple (iOS 6 — UIRefreshControl) və Google (Android Support Library — SwipeRefreshLayout) tərəfindən standartlaşdırılıb.
Texniki baxımdan Pull-to-Refresh panlama (barmaq yerdəyişməsini izləmə) və həddə çatdıqda trigger-in kombinasiyasıdır. İstifadəçi siyahını aşağı çəkir, müqaviməti (rezistiv overscroll) aşır və həddi keçdikdən sonra (~80px iOS-da, ~64dp Android-də) göstərici animasiyası və asinxron yükləmə başlayır. İstifadəçi barmağını həddən əvvəl buraxarsa — siyahı yeniləmədən ilkin vəziyyətə qayıdır.
Material Design Guidelines-ə görə, Pull-to-Refresh istifadə edilməməlidir naviqasiya və ya tab dəyişdirmək üçün — onun yeganə məqsədi məlumat yeniləməkdir. IT Sectr-də biz Pull-to-Refresh-i xəbər lentlərində, sifariş siyahılarında və çatlarda tətbiq edirik, burada məlumatların təzəliyi istifadəçi təcrübəsi üçün vacibdir.
UIRefreshControl — iOS 6-dan etibarən mövcud olan Pull-to-Refresh üçün standart iOS idarəetmə elementidir. UIRefreshControl UITableViewController-ə refreshControl xüsusiyyəti (iOS 10+) və ya daha köhnə versiyalarda cədvəlin subview-i kimi əlavə edilir. O, konfiqurasiya oluna bilən rəng (tintColor), title atributu və etiketli atributlaşdırılmış sətir (məsələn, “Yenilənir...”) olan daxili spinner ehtiva edir.
UIRefreshControl target-action mexanizmi ilə işləyir: jest aktivləşdirildikdə göstərilən metod (məsələn, refresh(_:)) çağırılır. Metod daxilində asinxron məlumat yükləmə aparılır. Tamamlandıqdan sonra endRefreshing() çağırılır, göstəricini animasiya ilə gizlədir. UIRefreshControl jest həssaslığını avtomatik idarə edir — yalnız cədvəlin yuxarı vəziyyətində (contentOffset.y <= 0) işə düşür.
tintColor xüsusiyyəti spinner-in rəngini təyin edir. title atributları tamamlandıqdan sonra “2 dəqiqə əvvəl yeniləndi” mətnini göstərməyə imkan verir. iOS 10-dan başlayaraq, UIRefreshControl UIActivityIndicatorView və ya davamlı fərdi görünüşlər vasitəsilə fərdi animasiyaları dəstəkləyir. IT Sectr-də biz tintColor-ı brendə uyğunlaşdırır və attributedTitle vasitəsilə son yeniləmə vaxtını göstəririk — bu istifadəçilərin məlumatlara inamını artırır.
SwipeRefreshLayout — Android Support Library-dən (androidx.swiperefreshlayout) ViewGroup, sürüşdürülən məzmunu (RecyclerView, NestedScrollView, ListView) əhatə edən və Pull-to-Refresh funksionallığı əlavə edən. UIRefreshControl-dən fərqli olaraq (idarəetmə elementi, konteyner deyil), SwipeRefreshLayout uşağın toxunma hadisələrini tutan və həddi aşdıqda yeniləmə göstəricisini işə salan konteynerdir.
SwipeRefreshLayout setColorSchemeColors() ilə rəng konfiqurasiyası olan Material Design dairəvi gedişat göstəricisindən istifadə edir. setOnRefreshListener metodu asinxron yükləmənin aparıldığı onRefresh() geri çağırışını təyin edir. Tamamlandıqdan sonra göstəricini gizlətmək üçün setRefreshing(false) çağırılır. Vacib: setRefreshing(true) onRefresh()-i təkrar çağırır — buna görə proqram vasitəsilə yeniləməni başlatmaq üçün flag və ya post-metodundan istifadə edin.
setProgressBackgroundColorSchemeResource xüsusiyyəti göstəricinin fonunu dəyişir. setSize(SwipeRefreshLayout.LARGE) — spinner ölçüsü. XML layout-da SwipeRefreshLayout RecyclerView-i əhatə edir: swipe_refresh_layout → recycler_view. Google I/O 2024-ə görə, SwipeRefreshLayout məzmun lentləri olan Android tətbiqlərinin 85%-də istifadə olunur. IT Sectr-də biz asinxron yüklənən siyahıları olan bütün ekranları SwipeRefreshLayout ilə əhatə edirik — bu Android-in bütün versiyalarında vahid UX təmin edir.
Android 12-dən (Material You) başlayaraq, Google material-1.6.0+ kitabxanasından (Compose üçün androidx.compose.material3.pulltorefresh) yeni Material Pull-to-Refresh istifadə etməyi tövsiyə edir. Yeni API spring-animasiyası və divar kağızı əsasında adaptiv rəng dəstəyi olan animasiyalı göstəricidən istifadə edir. SwipeRefreshLayout Android 12-dən aşağı versiyalar üçün uyğun qalır.
Pull-to-Refresh — tətbiqi asan nümunədir, lakin UX-i azaldan bir neçə ümumi səhv ehtiva edir. Onları və qarşısını alma yollarını nəzərdən keçirək.
IT Sectr-də biz test serverinin loglarında təkrarlanan sorğuları aşkar etdikdən sonra hər layihədə isRefreshing yoxlamasını əlavə etdik — məlum oldu ki, sürətli barmaqları olan istifadəçilər yeniləməni ardıcıl 3 dəfəyə qədər işə salırdılar.
UITableViewController-ə fərdi spinner rəngi və attributed title ilə Pull-to-Refresh əlavə edir. Məlumat yükləndikdən sonra göstərici gizlənir.
import UIKit
class FeedTableViewController: UITableViewController {
private var items: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.refreshControl = UIRefreshControl()
refreshControl?.tintColor = .systemBlue
refreshControl?.attributedTitle = NSAttributedString(
string: “Yeniləmək üçön çəkin”
)
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()
}
}
}
tableView.refreshControl xüsusiyyəti (iOS 10+) UIRefreshControl-ü təyin edir. .valueChanged hadisəsi ilə addTarget jest aktivləşdirildikdə işə düşür. endRefreshing() məcburidir — onsuz göstərici sonsuz fırlanacaq. Asinxron yükləmə DispatchQueue.main.asyncAfter ilə simulyasiya olunur — real layihədə URLSession və ya async/await olardı.
RecyclerView-i fərdi göstərici rəngləri ilə SwipeRefreshLayout-da əhatə edir. onRefresh yükləməni başladır və tamamlandıqdan sonra göstəricini gizlədir.
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
}
}
setColorSchemeColors Material Design fırlanan göstəricisinin rənglərini təyin edir. isRefreshing = false mütləq finally-də çağrılır ki, yükləmə xətası zamanı belə göstərici gizlənsin. ViewModelScope.launch fragment-in həyat dövründə korutini icra edir — fragment məhv olduqda korutin avtomatik ləğv olunur, yaddaş sızmasının qarşısını alır.
Müasir SwiftUI List və ya ScrollView-ə avtomatik Pull-to-Refresh əlavə edən .refreshable modifikatorunu təqdim edir.
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()
}
}
}
.refreshable modifikatoru Pull-to-Refresh zamanı icra olunan async-closure qəbul edir. SwiftUI avtomatik olaraq yeniləmə göstəricisini göstərir və gizlədir, vəziyyət yarışını idarə edir (cari yükləmə tamamlanana qədər təkrar yükləməni başlatmır) və animasiyanı platformaya uyğunlaşdırır. iOS 15+ üçün bu, SwiftUI-də Pull-to-Refresh-in preferred üsuludur.
Tez-tez verilən suallar
Bəli, SwiftUI iOS 15-dən etibarən List və ya ScrollView üçün .refreshable modifikatorunu təqdim edir. Closure daxilində məlumat yükləmənin async-kodu icra olunur. SwiftUI avtomatik yeniləmə göstəricisini idarə edir və cari yükləmə tamamlanana qədər təkrar başlatmaları bloklayır — bu yeni layihələr üçün standart recommended yanaşmadır.
isRefreshing flag-ından istifadə edin: yükləmə başlanğıcında true, tamamlandıqdan sonra false təyin edin. iOS-da UIRefreshControl endRefreshing() çağrılana qədər təkrar çağırışı avtomatik bloklayır. Android-də onRefresh()-in əvvəlində SwipeRefreshLayout.isRefreshing yoxlayın: true olarsa — return. Bu, bir jest üçün bir sorğu təmin edir.
UIRefreshControl və SwipeRefreshLayout yalnız siyahının yuxarı vəziyyətində (contentOffset == 0) işə düşür. Arxitektura konflikti istisna edir: siyahı hətta 1px sürüşdürüldükdə belə Pull-to-Refresh jesti aktivləşmir. Konflikt yaranarsa — Android-də nestedScrollingEnabled və ya toxunuşları tutan fərdi GestureRecognizer-ləri yoxlayın.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun