Lekcja 8. Kontrolki III — ProgressBar, ActivityIndicator, CollectionView, ListView
ŚredniPo co się tego uczymy?
Ta lekcja kończy przegląd kontrolek MAUI: dwie kontrolki informujące o trwającej operacji (ProgressBar, ActivityIndicator) i dwie kontrolki list — CollectionView (nowoczesna, zalecana) i ListView (starsza, wciąż spotykana). Pełne, praktyczne użycie list z bindowaniem danych poznasz w osobnej, dedykowanej lekcji dalej w tym dziale — tu poznajesz same kontrolki i ich właściwości.
Teoria
ProgressBar — pasek postępu
| Właściwość | Opis |
|---|---|
Progress |
Wartość od 0.0 do 1.0 — aktualny stan postępu. |
ProgressColor |
Kolor paska — może nieść znaczenie (zielony = OK, czerwony = błąd). |
Metoda ProgressTo() wywołana w kodzie C# animuje płynną zmianę wartości zamiast skoku — daje ładniejszy efekt wizualny.
ActivityIndicator — animowany spinner
| Właściwość | Opis |
|---|---|
IsRunning |
Włącza animację "kręcącego się kółka" — informacja "coś się dzieje". |
IsVisible |
Pokazuje/ukrywa spinner — zwykle łączony z IsRunning. |
Color |
Kolor spinnera — spójność z resztą aplikacji. |
ProgressBar używaj, gdy ZNASZ dokładny postęp operacji (np. wgrano 3 z 10 plików); ActivityIndicator, gdy NIE wiesz, ile potrwa operacja (np. czekanie na odpowiedź serwera).
CollectionView — nowoczesna lista/siatka elementów
| Właściwość | Opis |
|---|---|
ItemsSource |
Źródło danych — najczęściej kolekcja obiektów podpięta z kodu C#. |
ItemTemplate |
Wygląd pojedynczego elementu listy — pełna kontrola nad kartą/wierszem. |
ItemsLayout |
VerticalList, HorizontalList albo siatka (GridItemsLayout). |
SelectionMode |
None/Single/Multiple — dopasowanie sposobu wyboru elementów. |
EmptyView |
Co pokazać, gdy lista jest pusta — ważne dla dobrego doświadczenia użytkownika. |
ListView — starsza kontrolka listy
Poprzedniczka CollectionView. W NOWYCH projektach zawsze wybieraj CollectionView (jest wydajniejszy i bardziej elastyczny) — ListView możesz spotkać w starszych zadaniach czy materiałach, więc warto rozpoznawać jego podstawowe właściwości: ItemsSource, ItemTemplate, SelectedItem, SeparatorVisibility/SeparatorColor (linie między wierszami), HasUnevenRows (różna wysokość wierszy).
Schemat
ProgressBar vs ActivityIndicator: ProgressBar -> ZNAM dokladny postep (np. wyslano 6 z 10 zdjec) ActivityIndicator -> NIE WIEM ile potrwa (np. czekam na serwer) CollectionView (nowa) vs ListView (stara): Nowe projekty -> zawsze CollectionView Stare zadania/materialy -> mozesz spotkac ListView
Przykład z życia
Podczas wysyłania zdjęcia w komunikatorze widzisz pasek postępu wypełniający się procentowo (ProgressBar) — bo aplikacja zna dokładny rozmiar pliku. Natomiast po naciśnięciu "Wyślij wiadomość" na chwilę pojawia się kręcące kółko (ActivityIndicator) — bo aplikacja nie wie z góry, ile serwer będzie odpowiadał.
PostepPage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="KontrolkiApp3.PostepPage">
<VerticalStackLayout Padding="20" Spacing="16">
<Label Text="Wysyłanie pliku:" FontAttributes="Bold" />
<ProgressBar x:Name="PasekPostepu" Progress="0" />
<Button Text="Rozpocznij wysyłanie" Clicked="RozpocznijWysylanie_Clicked" />
<BoxView HeightRequest="1" Color="LightGray" />
<Label Text="Ładowanie danych z serwera:" FontAttributes="Bold" />
<ActivityIndicator x:Name="Spinner" IsRunning="False" Color="RoyalBlue" />
<Button Text="Symuluj pobieranie" Clicked="SymulujPobieranie_Clicked" />
</VerticalStackLayout>
</ContentPage>
PostepPage.xaml.cs
namespace KontrolkiApp3;
public partial class PostepPage : ContentPage
{
public PostepPage()
{
InitializeComponent();
}
private async void RozpocznijWysylanie_Clicked(object sender, EventArgs e)
{
// ProgressTo animuje plynne przejscie od aktualnej wartosci do 1.0
// w ciagu 2000 milisekund (2 sekundy)
await PasekPostepu.ProgressTo(1.0, 2000, Easing.Linear);
}
private async void SymulujPobieranie_Clicked(object sender, EventArgs e)
{
Spinner.IsRunning = true;
// Symulacja oczekiwania na odpowiedz serwera (bez blokowania UI)
await Task.Delay(2000);
Spinner.IsRunning = false;
await DisplayAlert("Gotowe", "Dane zostały pobrane.", "OK");
}
}
Komentarz i wyjaśnienie kodu
PasekPostepu.ProgressTo(1.0, 2000, Easing.Linear) to metoda ANIMUJĄCA — zamiast skokowo ustawić Progress = 1.0, płynnie zwiększa wartość przez 2000 milisekund, dając efekt realistycznego "wypełniania się" paska. To metoda asynchroniczna (zwraca Task), dlatego wywołanie poprzedzamy await.
W drugiej metodzie włączamy Spinner.IsRunning = true, czekamy sztucznie 2 sekundy przez await Task.Delay(2000) (w prawdziwej aplikacji byłoby to np. await httpClient.GetAsync(...) — poznasz w lekcji o REST API), a na końcu wyłączamy spinner i pokazujemy komunikat. Użycie await Task.Delay zamiast Thread.Sleep jest kluczowe — dzięki temu interfejs NIE zamarza podczas oczekiwania.
Ćwiczenie samodzielne
Utwórz stronę z powyższym kodem. Sprawdź, czy pasek postępu płynnie się wypełnia po kliknięciu pierwszego przycisku, a spinner kręci się przez około 2 sekundy po kliknięciu drugiego, po czym pokazuje się komunikat.
Zadania do pracy własnej
Zmień czas trwania animacji ProgressTo z 2000 na 5000 milisekund i zaobserwuj różnicę.
Dodaj drugi ProgressBar i przycisk 'Zresetuj', który natychmiast (bez animacji) ustawia oba paski z powrotem na 0.
Zbuduj symulację pobierania listy plików: ActivityIndicator uruchamia się na starcie, po 'pobraniu' (Task.Delay) wyłącza się i pokazuje CollectionView z zaszytą na sztywno listą 5 nazw plików (string). Jeśli lista byłaby pusta, CollectionView powinien pokazać EmptyView z tekstem 'Brak plików do wyświetlenia'.
Typowe błędy
Użycie Thread.Sleep zamiast Task.Delay — Thread.Sleep blokuje wątek interfejsu, aplikacja "zamarza" na czas oczekiwania.
Zapominanie o wyłączeniu ActivityIndicator po zakończeniu operacji — spinner kręcący się w nieskończoność sugeruje użytkownikowi, że coś się zawiesiło.
Używanie ListView w nowym projekcie bez wyraźnego powodu — CollectionView jest wydajniejszy i bardziej elastyczny; ListView wybieraj tylko, gdy pracujesz ze starszym, istniejącym kodem.
Brak EmptyView w CollectionView — gdy lista jest pusta (np. brak wyników wyszukiwania), pusty ekran bez żadnego komunikatu wygląda jak błąd aplikacji.
Nawiązanie do egzaminu zawodowego
To dopełnienie realizacji INF.04.6.2 pełnym zestawem kontrolek UI wymaganych w podstawie programowej. ProgressBar i ActivityIndicator są niezbędne przy operacjach sieciowych (REST API, GPS) omawianych w dalszych lekcjach, a CollectionView to podstawa każdej listy danych w aplikacji mobilnej.