Aplikacje mobilne · Responsywność
Dostosowanie do platformy i rozmiaru ekranu
Ten sam kod MAUI działa na telefonie, tablecie, Androidzie, iOS i Windows, ale „działa” nie znaczy „wygląda dobrze”. Poznasz trzy poziomy dostosowania: OnPlatform, DeviceInfo i układ zależny od szerokości okna.
- około 60 minut
- .NET MAUI · OnPlatform · DeviceInfo · VisualStateManager
- INF.04.6.2
Po tej lekcji: ustawić różne wartości dla różnych platform, odczytać informacje o urządzeniu i zmienić układ strony za pomocą AdaptiveTrigger i zdarzenia SizeChanged.
Jeden ekran działający w pionie i na szeroko
Przeciągnij krawędź okna: jeśli tekst znika, sama zmiana rozmiaru czcionki nie wystarczy. Ułożymy te same panele pod sobą albo obok siebie.
Najpierw uruchomisz mały ekran. Potem połączysz go z kodem i sprawdzisz konkretne wyniki. Dodatki wykonuj dopiero, gdy wersja podstawowa działa. Quiz i oceniane zadania pozostają w biurku po zalogowaniu.
Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji
1 · Sprawdź w działaniu
Zmieniaj urządzenie i szerokość okna
Przesuwaj suwak szerokości. Około 700 px układ przełącza się z jednej kolumny na dwie. Wybierz „Tablet z Androidem”: system to nadal Android, ale układ jest szeroki. Włącz też trzeci stan i rozciągnij okno powyżej 1000 px.
Najpierw przewidź, potem sprawdź: Przesuń szerokość w modelu przez próg700. Wskaż osobno zmianę kolumn Grid i zmianę miejsca panelu. To są dwa uzupełniające działania.
O układzie decyduje rzeczywista szerokość, a nie nazwa systemu. OnPlatform służy do drobnych różnic wartości (np. margines pod notchem iPhone’a). Model pomaga zobaczyć mechanizm; właściwą aplikację uruchomisz z plików poniżej.
1. Przygotuj miejsce pracy
Co dodajesz, a co podmieniasz?
Stronę dodaj przez Projekt → Dodaj → Nowy element → .NET MAUI ContentPage (XAML). Powstaje para .xaml i .xaml.cs. Dla ContentView wybierz szablon ContentView; dla modeli i serwisów zwykłą klasę. Jeśli plik już istnieje, podmień wskazaną zawartość — nie twórz drugiej klasy o tej samej nazwie.
| Plik | Rola w ćwiczeniu |
|---|---|
| MainPage.xaml | Wygląd strony lub kontrolki |
| MainPage.xaml.cs | Logika i obsługa danych |
Zanim uruchomisz: trzy połączenia
x:Class="ResponsywnaMauiApp.NazwaStrony" w XAML musi zgadzać się z namespace ResponsywnaMauiApp i nazwą klasy C#. InitializeComponent() tworzy kontrolki opisane w XAML.
x:Name="PoleImie" daje kodowi C# dostęp przez PoleImie.Text. Z kolei Clicked="Zapisz_Clicked" wskazuje metodę o tej nazwie w pliku .xaml.cs. Sam napis przycisku w Text niczego nie podpina.
Gdy dodajesz XAML z obsługą zdarzeń, od razu uzupełnij też odpowiadający C#. Uruchamiaj dopiero po skończeniu oznaczonej pary plików; brakujący handler nie jest błędem środowiska.
2. Uruchom sam wygląd — jeszcze bez logiki
W świeżym projekcie zastąp MainPage.xaml poniższym ekranem. W MainPage.xaml.cs zachowaj konstruktor z InitializeComponent(); usuń szablonowy licznik i OnCounterClicked, bo nie ma ich już w XAML. Na tym etapie App i AppShell pozostają z szablonu. To pełny, tymczasowy XAML — później świadomie go podmienisz, nie dokleisz do drugiego ContentPage.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsywnaMauiApp.MainPage">
<VerticalStackLayout Padding="24" Spacing="14">
<Label Text="Jeden ekran, różne rozmiary" FontSize="24" />
<Border Padding="20" Stroke="#4EE0B5">
<Label Text="Panel informacji" />
</Border>
<Border Padding="20" Stroke="#8F7BFF">
<Label Text="Panel treści" />
</Border>
</VerticalStackLayout>
</ContentPage>
- Pierwsza próba Uruchom. Zobaczysz kontrolki, ale przyciski bez Clicked jeszcze nic nie robią. Sprawdź rozmiar i kolejność elementów. Zatrzymaj aplikację przed następnym etapem.
Poczta na telefonie i na tablecie
Jedna lista czy lista i szczegóły obok siebie?
Aplikacja pocztowa na telefonie pokazuje listę wiadomości na całym ekranie, a szczegóły na osobnym. Na tablecie jest dość miejsca, by pokazać oba panele jednocześnie. Ta sama aplikacja zmienia więc układ siatki między „jedna kolumna” a „dwie kolumny”, i to dokładnie robi przykład z lekcji.
Kluczowa zasada: nie zakładaj, że „Android” to telefon. Są tablety z Androidem, iPady z iOS, a okno aplikacji na Windows może mieć dowolną szerokość.
2 · Od prostego do elastycznego
Co kiedy stosować
| Poziom | Narzędzie | Do czego |
|---|---|---|
| 1 | OnPlatform w XAML | Różne wartości tej samej właściwości dla platform (marginesy, rozmiary). |
| 2 | DeviceInfo.Current | Informacje o urządzeniu w kodzie: Platform, Idiom, Model, VersionString, DeviceType. |
| 3a | VisualStateManager + AdaptiveTrigger | Deklaratywna zmiana układu po przekroczeniu progu szerokości (MinWindowWidth). |
| 3b | Zdarzenie SizeChanged | Układ zmieniany z kodu, gdy logika jest zbyt złożona dla triggerów. |
3. Wskaż stronę startową ćwiczenia
Po dodaniu docelowych stron podmień App.xaml.cs na poniższy. App.xaml zostaje z szablonu. Od tej chwili startuje MainPage, a nie wcześniejszy tymczasowy MainPage z AppShell. Uzupełnij jej pliki w kolejnych etapach, zanim ponownie uruchomisz projekt.
namespace ResponsywnaMauiApp;
public partial class App : Application
{
public App() => InitializeComponent();
protected override Window CreateWindow(IActivationState? activationState)
=> new Window(new NavigationPage(new MainPage()));
}
CreateWindowTworzy okno aplikacji. NavigationPage jest kontenerem zwykłych stron i daje przycisk powrotu; nie łączymy go z Shell.new MainPage()Tworzy instancję docelowej strony. Aby testować drugi niezależny przykład, zatrzymaj program, zmień tylko ten typ i uruchom ponownie.
4. Połącz wygląd z działaniem
Teraz zbuduj docelowy przykład. Pełne pliki poniżej zastępują swoje wcześniejsze wersje. Przeczytaj opis nad kodem i objaśnienia pod nim; potem sprawdź przepływ danych, nie tylko brak czerwonych podkreśleń.
Gdy przykład ma kilka plików zależnych od siebie, najpierw dodaj wszystkie wskazane typy, a potem uruchom całość. Ustaw breakpoint w obsłudze głównego przycisku i prześledź jedną próbę.
Budowa krok po kroku
MainPage.xaml
Najpierw sprawdź strukturę Grid, potem VisualStateGroup. Stan Telefon ma jedną kolumnę, Tablet dwie. OnPlatform wybiera odstęp według systemu, nie szerokości.
Margines zależny od platformy i siatka zmieniająca definicje kolumn oraz wierszy po przekroczeniu 700 px.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsywnaMauiApp.MainPage"
Title="Responsywny ekran">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="Android" Value="18" />
<On Platform="iOS" Value="18,50,18,18" />
<On Platform="WinUI" Value="30" />
</OnPlatform>
</ContentPage.Padding>
<Grid x:Name="GlownyGrid" RowDefinitions="Auto,*" ColumnDefinitions="*"
RowSpacing="16" ColumnSpacing="16">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="SzerokoscEkranu">
<VisualState Name="Telefon">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="ColumnDefinitions" Value="*" />
<Setter Property="RowDefinitions" Value="Auto,*" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Tablet">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="700" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="ColumnDefinitions" Value="280,*" />
<Setter Property="RowDefinitions" Value="*" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Padding="18" Stroke="#808080">
<VerticalStackLayout>
<Label Text="Urządzenie" FontAttributes="Bold" />
<Label x:Name="UrzadzenieLabel" />
</VerticalStackLayout>
</Border>
<Border x:Name="TrescPanel" Grid.Row="1" Padding="18" Stroke="#808080">
<VerticalStackLayout>
<Label Text="Treść aplikacji" FontSize="24" FontAttributes="Bold" />
<Label Text="Na telefonie panel jest pod informacjami. Na szerokim ekranie znajduje się obok." />
</VerticalStackLayout>
</Border>
</Grid>
</ContentPage>
<OnPlatform x:TypeArguments="Thickness">Wartość zależna od systemu. iOS dostaje większy margines górny (50) z powodu notcha i paska statusu.VisualStateGroupiVisualStateStan wizualny to nazwany zestaw ustawień. W grupie aktywny jest jeden naraz.AdaptiveTrigger MinWindowWidth="700"Stan „Tablet” włącza się, gdy okno ma co najmniej 700 jednostek szerokości.Setter Property="ColumnDefinitions"Telefon: jedna kolumna i dwa wiersze. Tablet: kolumny280,*i jeden wiersz.
Budowa krok po kroku
MainPage.xaml.cs
SizeChanged przestawia panel do właściwego wiersza i kolumny. Nie zastępuje definicji siatki z XAML. Oba progi700 muszą być takie same.
Odczyt danych o urządzeniu oraz przestawienie panelu treści po zmianie rozmiaru.
using Microsoft.Maui.Devices;
namespace ResponsywnaMauiApp;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
SizeChanged += OnSizeChanged;
PokazInformacje();
}
private void PokazInformacje()
{
UrzadzenieLabel.Text =
$"Platforma: {DeviceInfo.Current.Platform}\n" +
$"Typ: {DeviceInfo.Current.Idiom}\n" +
$"Model: {DeviceInfo.Current.Model}\n" +
$"System: {DeviceInfo.Current.VersionString}\n" +
$"Emulator: {DeviceInfo.Current.DeviceType == DeviceType.Virtual}";
}
private void OnSizeChanged(object? sender, EventArgs e)
{
bool szerokiEkran = Width >= 700;
Grid.SetRow(TrescPanel, szerokiEkran ? 0 : 1);
Grid.SetColumn(TrescPanel, szerokiEkran ? 1 : 0);
}
}
DeviceInfo.Current.IdiomTyp urządzenia:Phone,TabletlubDesktop.DeviceType == DeviceType.VirtualOdróżnia emulator od prawdziwego urządzenia. Przydatne, bo GPS i aparat działają tam inaczej.\nw interpolacji Znak nowej linii. Bez ukośnika zobaczysz literę „n” sklejoną z tekstem.SizeChanged += OnSizeChangedZdarzenie strony zgłaszane przy każdej zmianie rozmiaru.Grid.SetRow/Grid.SetColumnUstawiają pozycję elementu w siatce z kodu.- Dwa mechanizmy naraz W tym przykładzie działają niezależnie. W realnym projekcie wybierz jeden na dany fragment, aby nie ustawiały tej samej właściwości sprzecznie.
5. Odbiór: czy naprawdę działa?
Wykonaj próby w swojej aplikacji, nie tylko w modelu na stronie. Zaznaczaj dopiero po sprawdzeniu wyniku. Funkcje urządzenia wymagają testu na właściwej platformie.
5 · Czego unikać
Trzy błędy z responsywnością
Platforma = typ urządzenia
if (DeviceInfo.Platform == DevicePlatform.Android) UkladTelefonu();Tablet z Androidem dostaje układ telefonu.
bool szerokiEkran = Width >= 700;Decyduje rzeczywista szerokość okna.
Test na jednym rozmiarze
// sprawdzone tylko na jednym emulatorze telefonuNa szerszym ekranie układ się „łamie” i nikt tego nie zauważa.
// test: wąski telefon, tablet i okno Windows o zmiennej szerokościSprawdzaj oba końce spektrum.
if zamiast OnPlatform
if (DeviceInfo.Platform == DevicePlatform.iOS) Padding = new Thickness(18, 50, 18, 18);Działa, ale to zbędna komplikacja dla prostej różnicy wartości.
<On Platform="iOS" Value="18,50,18,18" />Deklaratywny OnPlatform jest czytelniejszy.
Ćwiczenie z pomocą · samodzielna praca
6. Mała zmiana, którą zrobisz samodzielnie
Zmień próg układu na800 i sprawdź obie strony granicy.
Zmień próg układu na800 i sprawdź obie strony granicy. Dotychczasowe działanie ma pozostać poprawne.
? Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź
Zmień MinWindowWidth stanu Tablet.
Krok 2 — pokaż podpowiedź
Zmień również warunek Width >= 700 w C#, bo przestawia on panel.
Krok 3 — pokaż podpowiedź
Porównaj799 i800; pozostawienie dwóch różnych progów rozjedzie układ.
Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.
6 · Sprawdź się
Które narzędzie?
Cztery sytuacje.
Podsumowanie
Co warto zapamiętać
OnPlatformzmienia wartości zależnie od systemu, dobrze sprawdza się przy marginesach.DeviceInfo.Currentzwraca platformę, typ urządzenia (Idiom), model i informację o emulatorze.- O układzie decyduje szerokość okna:
VisualStateManager+AdaptiveTriggeralboSizeChanged. - Nie zakładaj, że Android to telefon. Testuj wąski i szeroki ekran.
Dalej na swoim koncie
Rozgrzewki, quiz i zadania są w biurku ucznia.
Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.
Zaloguj się →