2022. 7. 20. 00:00ㆍMAUI
플라이아웃 탐색은 메뉴 항목 창이 장치 화면의 측면에서 미끄러지듯 나타나는 탐색 유형이다.
일반적으로 "햄버거" 메뉴 또는 세 개의 수평선이 서로 겹쳐진 아이콘을 탭하면 호출된다.
플라이아웃 메뉴는 Header, FlyoutItems, MenuItems 및 바닥글의 여러 부분으로 구성된다.
기본 페이지 역할을 하는 AppShell 에 호스팅 되어야 한다.
<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Xaminals.Controls"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<FlyoutItem Title="Cats"
Icon="cat.png">
<Tab>
<ShellContent ContentTemplate="{DataTemplate views:CatsPage}" />
</Tab>
</FlyoutItem>
<FlyoutItem Title="Dogs"
Icon="dog.png">
<Tab>
<ShellContent ContentTemplate="{DataTemplate views:DogsPage}" />
</Tab>
</FlyoutItem>
</Shell>
예제)
Xaml\FlyoutNavigation 을 기본 위치로 하여 작성
Pages\MainPage.xaml
<?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="MauiApp1.Xaml.FlyoutNavigation.Pages.MainPage"
Title="MainPage"
BackgroundColor="Black">
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="textColor">White</Color>
<Color x:Key="boxColor">#44FFFFFF</Color>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource textColor}" />
<Setter Property="HorizontalOptions" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<Grid RowSpacing="10" ColumnSpacing="5" Padding="5" >
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Image Source="starfield.png" Aspect="AspectFill" Grid.RowSpan="4" Grid.ColumnSpan="4" />
<StackLayout Grid.Row="0" Grid.ColumnSpan="4">
<Label x:Name="lblDate" FontAttributes="Bold" />
<Label x:Name="lblMoonPhaseIcon" FontSize="96" />
<Label x:Name="lblMoonPhaseText" FontAttributes="Bold" />
</StackLayout>
<Label x:Name="lblPhaseIcon1" Grid.Column="0" Grid.Row="1" FontSize="48" />
<Label x:Name="lblPhaseIcon2" Grid.Column="1" Grid.Row="1" FontSize="48" />
<Label x:Name="lblPhaseIcon3" Grid.Column="2" Grid.Row="1" FontSize="48" />
<Label x:Name="lblPhaseIcon4" Grid.Column="3" Grid.Row="1" FontSize="48" />
<Label x:Name="lblPhaseText1" Grid.Column="0" Grid.Row="2" FontAttributes="Bold" FontSize="Medium" />
<Label x:Name="lblPhaseText2" Grid.Column="1" Grid.Row="2" FontAttributes="Bold" FontSize="Medium" />
<Label x:Name="lblPhaseText3" Grid.Column="2" Grid.Row="2" FontAttributes="Bold" FontSize="Medium" />
<Label x:Name="lblPhaseText4" Grid.Column="3" Grid.Row="2" FontAttributes="Bold" FontSize="Medium" />
</Grid>
</ContentPage>
Pages\MainPage.xaml.cs
using MauiApp1.Xaml.FlyoutNavigation.Data;
namespace MauiApp1.Xaml.FlyoutNavigation.Pages;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
InitializeUI();
}
void InitializeUI()
{
var phase = MoonPhaseCalculator.GetPhase(DateTime.Now);
lblDate.Text = DateTime.Today.ToString("D");
lblMoonPhaseIcon.Text = moonPhaseEmojis[phase];
lblMoonPhaseText.Text = phase.ToString();
SetMoonPhaseLabels(lblPhaseIcon1, lblPhaseText1, 1);
SetMoonPhaseLabels(lblPhaseIcon2, lblPhaseText2, 2);
SetMoonPhaseLabels(lblPhaseIcon3, lblPhaseText3, 3);
SetMoonPhaseLabels(lblPhaseIcon4, lblPhaseText4, 4);
}
void SetMoonPhaseLabels(Label lblIcon, Label lblText, int dayOffset)
{
var phase = MoonPhaseCalculator.GetPhase(DateTime.Now.AddDays(dayOffset));
lblIcon.Text = moonPhaseEmojis[phase];
lblText.Text = DateTime.Now.AddDays(dayOffset).DayOfWeek.ToString();
}
static Dictionary<MoonPhaseCalculator.Phase, string> moonPhaseEmojis = new Dictionary<MoonPhaseCalculator.Phase, string>
{
{ MoonPhaseCalculator.Phase.New, "🌑" },
{ MoonPhaseCalculator.Phase.WaxingCrescent, "🌒" },
{ MoonPhaseCalculator.Phase.FirstQuarter, "🌓" },
{ MoonPhaseCalculator.Phase.WaxingGibbous, "🌔" },
{ MoonPhaseCalculator.Phase.Full, "🌕" },
{ MoonPhaseCalculator.Phase.WaningGibbous, "🌖" },
{ MoonPhaseCalculator.Phase.LastQuarter, "🌗" },
{ MoonPhaseCalculator.Phase.WaningCrescent, "🌘" },
};
}
Pages\AboutPage.xaml
<?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="MauiApp1.Xaml.FlyoutNavigation.Pages.AboutPage"
Title="AboutPage">
<StackLayout Padding="10" Spacing="5">
<Label Text="Version 1.0.0" />
<Label Text="Sunrise/Sunset data provided by: https://sunrise-sunset.org/api" />
<Label Text="Icons from Font Awesome" />
</StackLayout>
</ContentPage>
Pages\AboutPage.xaml.cs
namespace MauiApp1.Xaml.FlyoutNavigation.Pages;
public partial class AboutPage : ContentPage
{
public AboutPage()
{
InitializeComponent();
}
}
Pages\SunrisePage.xaml
<?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="MauiApp1.Xaml.FlyoutNavigation.Pages.SunrisePage"
Title="SunrisePage">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Padding="10">
<Label x:Name="lblDate" WidthRequest="200" HorizontalTextAlignment="Center" FontAttributes="Bold" />
<ActivityIndicator x:Name="activityWaiting" IsRunning="False" Color="Orange" />
<Grid RowSpacing="10" ColumnSpacing="5" Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="🌅" FontSize="72" Grid.Column="0" />
<Label Text="☀️" FontSize="72" Grid.Column="1" />
<Label Text="🌇" FontSize="72" Grid.Column="2" />
<Label Text="Sunrise" FontAttributes="Bold" Grid.Column="0" Grid.Row="1" />
<Label Text="Daylight" FontAttributes="Bold" Grid.Column="1" Grid.Row="1" />
<Label Text="Sunset" FontAttributes="Bold" Grid.Column="2" Grid.Row="1" />
<Label x:Name="lblSunrise" WidthRequest="100" FontAttributes="None" Grid.Column="0" Grid.Row="2" HorizontalTextAlignment="Center" />
<Label x:Name="lblDaylight" WidthRequest="150" FontAttributes="None" Grid.Column="1" Grid.Row="2" HorizontalTextAlignment="Center" />
<Label x:Name="lblSunset" WidthRequest="100" FontAttributes="None" Grid.Column="2" Grid.Row="2" HorizontalTextAlignment="Center" />
</Grid>
</StackLayout>
</ContentPage>
Pages\SunrisePage.xaml.cs
using MauiApp1.Xaml.FlyoutNavigation.Data;
namespace MauiApp1.Xaml.FlyoutNavigation.Pages;
public partial class SunrisePage : ContentPage
{
ILatLongService LatLongService { get; set; }
public SunrisePage()
{
InitializeComponent();
LatLongService = new LatLongService();
}
protected override async void OnAppearing()
{
base.OnAppearing();
activityWaiting.IsRunning = true;
var sunriseSunsetData = await GetSunriseSunsetData();
InitializeUI(sunriseSunsetData.Item1, sunriseSunsetData.Item2, sunriseSunsetData.Item3);
activityWaiting.IsRunning = false;
}
async Task<(DateTime, DateTime, TimeSpan)> GetSunriseSunsetData()
{
var latLongData = await LatLongService.GetLatLong();
var sunData = await new SunriseService().GetSunriseSunsetTimes(latLongData.Latitude, latLongData.Longitude);
var riseTime = sunData.Sunrise.ToLocalTime();
var setTime = sunData.Sunset.ToLocalTime();
var span = setTime.TimeOfDay - riseTime.TimeOfDay;
return (riseTime, setTime, span);
}
void InitializeUI(DateTime riseTime, DateTime setTime, TimeSpan span)
{
lblDate.Text = DateTime.Today.ToString("D");
lblSunrise.Text = riseTime.ToString("h:mm tt");
lblDaylight.Text = $"{span.Hours} hours, {span.Minutes} minutes";
lblSunset.Text = setTime.ToString("h:mm tt");
}
}
Data\ILatLongService.cs
namespace MauiApp1.Xaml.FlyoutNavigation.Data;
public interface ILatLongService
{
Task<(double Latitude, double Longitude)> GetLatLong();
}
Data\LatLongService.cs
namespace MauiApp1.Xaml.FlyoutNavigation.Data;
public class LatLongService : ILatLongService
{
public async Task<(double Latitude, double Longitude)> GetLatLong()
{
var latLoc = 0.0;
var longLoc = 0.0;
var status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
if (status == PermissionStatus.Granted)
{
var request = new GeolocationRequest(GeolocationAccuracy.Default, TimeSpan.FromSeconds(10));
var location = await Geolocation.GetLocationAsync(request);
latLoc = location.Latitude;
longLoc = location.Longitude;
}
return (latLoc, longLoc);
}
}
Data\MoonPhaseCalculator.cs
namespace MauiApp1.Xaml.FlyoutNavigation.Data;
public static class MoonPhaseCalculator
{
public enum Phase
{
New,
WaxingCrescent,
FirstQuarter,
WaxingGibbous,
Full,
WaningGibbous,
LastQuarter,
WaningCrescent,
}
static double synodicLength = 29.530588853; //length in days of a complete moon cycle
static DateTime referenceNewMoonDate = new DateTime(2017, 11, 18);
public static Phase GetPhase(DateTime date)
{
return GetPhase(GetAge(date));
}
static double GetAge(DateTime date)
{
double days = (date - referenceNewMoonDate).TotalDays;
return days % synodicLength;
}
static Phase GetPhase(double age)
{
if (age < 1) return Phase.New;
if (age < 7) return Phase.WaxingCrescent;
if (age < 8) return Phase.FirstQuarter;
if (age < 14) return Phase.WaxingGibbous;
if (age < 15) return Phase.Full;
if (age < 22) return Phase.WaningGibbous;
if (age < 23) return Phase.LastQuarter;
if (age < 29) return Phase.WaningCrescent;
return Phase.New;
}
}
Data\SunriseService.cs
using System.Text.Json;
namespace MauiApp1.Xaml.FlyoutNavigation.Data;
public class SunriseService
{
const string SunriseSunsetServiceUrl = "https://api.sunrise-sunset.org";
public async Task<(DateTime Sunrise, DateTime Sunset)> GetSunriseSunsetTimes(double latitude, double longitude)
{
var query = $"{SunriseSunsetServiceUrl}/json?lat={latitude}&lng={longitude}&date=today";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
var json = await client.GetStringAsync(query);
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var data = JsonSerializer.Deserialize<SunriseSunsetData>(json, options);
return (DateTime.Parse(data.Results.Sunrise), DateTime.Parse(data.Results.Sunset));
}
class SunriseSunsetData
{
#pragma warning disable 0649
// Field is only set via JSON deserialization, so disable warning that the field is never set.
//public SunriseSunsetResults Results;
public SunriseSunsetResults Results { get; set; }
#pragma warning restore 0649
}
class SunriseSunsetResults
{
#pragma warning disable 0649
// Fields are only set via JSON deserialization, so disable warning that the fields are never set.
public string Sunrise { get; set; }
public string Sunset { get; set; }
#pragma warning restore 0649
}
}
Assets 은 다음을 참조하고
Resources/Images 아래에 저장하자
AppShell.xaml page 를 열고
위와 같은 코드가 있다면 삭제 하자
그리고 다음을 추가하자
<Shell.FlyoutHeader>
<Grid HeightRequest="100" BackgroundColor="DarkSlateBlue">
<Image Source="moon.png" />
</Grid>
</Shell.FlyoutHeader>
<FlyoutItem Title="Moon Phase" Icon="moon.png">
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate localFlyoutNavigation:MainPage}"
Route="MainPage" />
</FlyoutItem>
<FlyoutItem Title="Sunrise" Icon="sun.png">
<ShellContent
ContentTemplate="{DataTemplate localFlyoutNavigation:SunrisePage}"
Route="SunrisePage" />
</FlyoutItem>
<FlyoutItem Title="About" Icon="question.png">
<ShellContent
ContentTemplate="{DataTemplate localFlyoutNavigation:AboutPage}"
Route="AboutPage" />
</FlyoutItem>
<Shell
...
FlyoutIcon="moon.png">
실행시 Sunrise 화면으로 이동시에 android 같은 경우 access permission 이 필요하다는 오류가 나올수 있다.
Platforms/Android/MainApplication.cs 에 using 밑에 다음을 추가하자
[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessBackgroundLocation)]
실행화면
왼쪽 상단 MainPage 옆에 달 아이콘 클릭시
관련영상
'MAUI' 카테고리의 다른 글
.NET MAUI - XAML stack navigation (0) | 2022.07.22 |
---|---|
NET MAUI - XAML tab navigation (0) | 2022.07.21 |
NET MAUI - XAML 애플리케이션 전체 리소스 생성 및 사용 (0) | 2022.07.19 |
NET MAUI - XAML 스타일을 사용하여 일관된 UI 만들기 (0) | 2022.07.18 |
.NET MAUI - XAML 동적 리소스 사용 및 업데이트 (0) | 2022.07.15 |