Procházet zdrojové kódy

add safe area demo

Emmanuel Hansen před 2 roky
rodič
revize
d203c1b386
28 změnil soubory, kde provedl 672 přidání a 5 odebrání
  1. 37 5
      Avalonia.sln
  2. binární
      samples/SafeAreaDemo.Android/Icon.png
  3. 11 0
      samples/SafeAreaDemo.Android/MainActivity.cs
  4. 5 0
      samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml
  5. 13 0
      samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml
  6. 4 0
      samples/SafeAreaDemo.Android/Resources/values/colors.xml
  7. 17 0
      samples/SafeAreaDemo.Android/Resources/values/styles.xml
  8. 24 0
      samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
  9. 30 0
      samples/SafeAreaDemo.Android/SplashActivity.cs
  10. 21 0
      samples/SafeAreaDemo.Desktop/Program.cs
  11. 24 0
      samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj
  12. 18 0
      samples/SafeAreaDemo.Desktop/app.manifest
  13. 17 0
      samples/SafeAreaDemo.iOS/AppDelegate.cs
  14. 5 0
      samples/SafeAreaDemo.iOS/Entitlements.plist
  15. 47 0
      samples/SafeAreaDemo.iOS/Info.plist
  16. 15 0
      samples/SafeAreaDemo.iOS/Main.cs
  17. 43 0
      samples/SafeAreaDemo.iOS/Resources/LaunchScreen.xib
  18. 18 0
      samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj
  19. 15 0
      samples/SafeAreaDemo/App.xaml
  20. 36 0
      samples/SafeAreaDemo/App.xaml.cs
  21. binární
      samples/SafeAreaDemo/Assets/avalonia-logo.ico
  22. 27 0
      samples/SafeAreaDemo/SafeAreaDemo.csproj
  23. 31 0
      samples/SafeAreaDemo/ViewLocator.cs
  24. 112 0
      samples/SafeAreaDemo/ViewModels/MainViewModel.cs
  25. 52 0
      samples/SafeAreaDemo/Views/MainView.xaml
  26. 25 0
      samples/SafeAreaDemo/Views/MainView.xaml.cs
  27. 12 0
      samples/SafeAreaDemo/Views/MainWindow.xaml
  28. 13 0
      samples/SafeAreaDemo/Views/MainWindow.xaml.cs

+ 37 - 5
Avalonia.sln

@@ -244,13 +244,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepe
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepeater.UnitTests", "tests\Avalonia.Controls.ItemsRepeater.UnitTests\Avalonia.Controls.ItemsRepeater.UnitTests.csproj", "{F4E36AA8-814E-4704-BC07-291F70F45193}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Desktop", "samples\SafeAreaDemo.Desktop\SafeAreaDemo.Desktop.csproj", "{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.iOS", "samples\SafeAreaDemo.iOS\SafeAreaDemo.iOS.csproj", "{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -595,6 +603,26 @@ Global
 		{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Deploy.0 = Release|Any CPU
+		{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Deploy.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -661,10 +689,14 @@ Global
 		{75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
+		{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
 		{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
-		{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+		{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+		{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+		{4CDAD037-34A2-4CCF-A03A-C6C7B988A572} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+		{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

binární
samples/SafeAreaDemo.Android/Icon.png


+ 11 - 0
samples/SafeAreaDemo.Android/MainActivity.cs

@@ -0,0 +1,11 @@
+using Android.App;
+using Android.Content.PM;
+using Avalonia.Android;
+
+namespace SafeAreaDemo.Android
+{
+    [Activity(Label = "SafeAreaDemo.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
+    public class MainActivity : AvaloniaMainActivity
+    {
+    }
+}

+ 5 - 0
samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
+	<uses-permission android:name="android.permission.INTERNET" />
+	<application android:label="SafeAreaDemo" android:icon="@drawable/Icon" />
+</manifest>

+ 13 - 0
samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+  <item>
+    <color android:color="@color/splash_background"/>
+  </item>
+
+  <item android:drawable="@drawable/icon"
+        android:width="120dp"
+        android:height="120dp"
+        android:gravity="center" />
+
+</layer-list>

+ 4 - 0
samples/SafeAreaDemo.Android/Resources/values/colors.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <color name="splash_background">#FFFFFF</color>
+</resources>

+ 17 - 0
samples/SafeAreaDemo.Android/Resources/values/styles.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<resources>
+
+  <style name="MyTheme">
+  </style>
+
+  <style name="MyTheme.NoActionBar" parent="@style/Theme.AppCompat.NoActionBar">
+    <item name="android:windowActionBar">false</item>
+    <item name="android:windowNoTitle">true</item>
+  </style>
+
+  <style name="MyTheme.Splash" parent ="MyTheme.NoActionBar">
+    <item name="android:windowBackground">@drawable/splash_screen</item>
+    <item name="android:windowContentOverlay">@null</item>
+  </style>
+
+</resources>

+ 24 - 0
samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj

@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net7.0-android</TargetFramework>
+    <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
+    <Nullable>enable</Nullable>
+    <ApplicationId>com.avalonia.safeareademo</ApplicationId>
+    <ApplicationVersion>1</ApplicationVersion>
+    <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
+    <AndroidPackageFormat>apk</AndroidPackageFormat>
+    <AndroidEnableProfiledAot>False</AndroidEnableProfiledAot>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <AndroidResource Include="Icon.png">
+      <Link>Resources\drawable\Icon.png</Link>
+    </AndroidResource>
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />
+    <ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" />
+  </ItemGroup>
+</Project>

+ 30 - 0
samples/SafeAreaDemo.Android/SplashActivity.cs

@@ -0,0 +1,30 @@
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Avalonia;
+using Avalonia.Android;
+using Application = Android.App.Application;
+
+namespace SafeAreaDemo.Android
+{
+    [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
+    public class SplashActivity : AvaloniaSplashActivity<App>
+    {
+        protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
+        {
+            return base.CustomizeAppBuilder(builder);
+        }
+
+        protected override void OnCreate(Bundle? savedInstanceState)
+        {
+            base.OnCreate(savedInstanceState);
+        }
+
+        protected override void OnResume()
+        {
+            base.OnResume();
+
+            StartActivity(new Intent(Application.Context, typeof(MainActivity)));
+        }
+    }
+}

+ 21 - 0
samples/SafeAreaDemo.Desktop/Program.cs

@@ -0,0 +1,21 @@
+using Avalonia;
+using System;
+
+namespace SafeAreaDemo.Desktop
+{
+    internal class Program
+    {
+        // Initialization code. Don't use any Avalonia, third-party APIs or any
+        // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+        // yet and stuff might break.
+        [STAThread]
+        public static void Main(string[] args) => BuildAvaloniaApp()
+            .StartWithClassicDesktopLifetime(args);
+
+        // Avalonia configuration, don't remove; also used by visual designer.
+        public static AppBuilder BuildAvaloniaApp()
+            => AppBuilder.Configure<App>()
+                .UsePlatformDetect()
+                .LogToTrace();
+    }
+}

+ 24 - 0
samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj

@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <!--If you are willing to use Windows/MacOS native APIs you will need to create 3 projects.
+    One for Windows with net7.0-windows TFM, one for MacOS with net7.0-macos and one with net7.0 TFM for Linux.-->
+    <TargetFramework>net7.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <BuiltInComInteropSupport>true</BuiltInComInteropSupport>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <ApplicationManifest>app.manifest</ApplicationManifest>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
+    <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
+    <ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />
+  </ItemGroup>
+  <Import Project="..\..\build\SampleApp.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
+</Project>

+ 18 - 0
samples/SafeAreaDemo.Desktop/app.manifest

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+  <!-- This manifest is used on Windows only.
+       Don't remove it as it might cause problems with window transparency and embeded controls.
+       For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
+  <assemblyIdentity version="1.0.0.0" name="SafeAreaDemo.Desktop"/>
+
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- A list of the Windows versions that this application has been tested on
+           and is designed to work with. Uncomment the appropriate elements
+           and Windows will automatically select the most compatible environment. -->
+
+      <!-- Windows 10 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
+    </application>
+  </compatibility>
+</assembly>

+ 17 - 0
samples/SafeAreaDemo.iOS/AppDelegate.cs

@@ -0,0 +1,17 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.iOS;
+using Avalonia.Media;
+using Foundation;
+using UIKit;
+
+namespace SafeAreaDemo.iOS
+{
+    // The UIApplicationDelegate for the application. This class is responsible for launching the 
+    // User Interface of the application, as well as listening (and optionally responding) to 
+    // application events from iOS.
+    [Register("AppDelegate")]
+    public partial class AppDelegate : AvaloniaAppDelegate<App>
+    {
+    }
+}

+ 5 - 0
samples/SafeAreaDemo.iOS/Entitlements.plist

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict/>
+</plist>

+ 47 - 0
samples/SafeAreaDemo.iOS/Info.plist

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDisplayName</key>
+	<string>SafeAreaDemo</string>
+	<key>CFBundleIdentifier</key>
+	<string>companyName.SafeAreaDemo</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>MinimumOSVersion</key>
+	<string>10.0</string>
+	<key>UIDeviceFamily</key>
+	<array>
+		<integer>1</integer>
+		<integer>2</integer>
+	</array>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UIStatusBarHidden</key>
+	<true/>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<false/>
+</dict>
+</plist>

+ 15 - 0
samples/SafeAreaDemo.iOS/Main.cs

@@ -0,0 +1,15 @@
+using UIKit;
+
+namespace SafeAreaDemo.iOS
+{
+    public class Application
+    {
+        // This is the main entry point of the application.
+        static void Main(string[] args)
+        {
+            // if you want to use a different Application Delegate class from "AppDelegate"
+            // you can specify it here.
+            UIApplication.Main(args, null, typeof(AppDelegate));
+        }
+    }
+}

+ 43 - 0
samples/SafeAreaDemo.iOS/Resources/LaunchScreen.xib

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
+	<dependencies>
+		<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207" />
+		<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1" />
+	</dependencies>
+	<objects>
+		<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" />
+		<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder" />
+		<view contentMode="scaleToFill" id="iN0-l3-epB">
+			<rect key="frame" x="0.0" y="0.0" width="480" height="480" />
+			<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" />
+			<subviews>
+				<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="  Copyright (c) 2022 " textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines"
+					minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
+					<rect key="frame" x="20" y="439" width="441" height="21" />
+					<fontDescription key="fontDescription" type="system" pointSize="17" />
+					<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
+					<nil key="highlightedColor" />
+				</label>
+				<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SafeAreaDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines"
+					minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
+					<rect key="frame" x="20" y="140" width="441" height="43" />
+					<fontDescription key="fontDescription" type="boldSystem" pointSize="36" />
+					<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
+					<nil key="highlightedColor" />
+				</label>
+			</subviews>
+			<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite" />
+			<constraints>
+				<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC" />
+				<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk" />
+				<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l" />
+				<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0" />
+				<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9" />
+				<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g" />
+			</constraints>
+			<nil key="simulatedStatusBarMetrics" />
+			<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics" />
+			<point key="canvasLocation" x="548" y="455" />
+		</view>
+	</objects>
+</document>

+ 18 - 0
samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj

@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net7.0-ios</TargetFramework>
+    <SupportedOSPlatformVersion>10.0</SupportedOSPlatformVersion>
+    <ProvisioningType>manual</ProvisioningType>
+    <Nullable>enable</Nullable>
+    <RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
+    
+    <!-- These properties need to be set in order to run on a real iDevice -->
+    <!--<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>-->
+    <!--<CodesignKey></CodesignKey>-->
+  </PropertyGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\SafeAreaDemo\SafeAreaDemo.csproj" />
+    <ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" />
+  </ItemGroup>
+</Project>

+ 15 - 0
samples/SafeAreaDemo/App.xaml

@@ -0,0 +1,15 @@
+<Application xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:local="using:SafeAreaDemo"
+             x:Class="SafeAreaDemo.App"
+             RequestedThemeVariant="Default">
+             <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
+
+    <Application.DataTemplates>
+        <local:ViewLocator/>
+    </Application.DataTemplates>
+
+    <Application.Styles>
+        <FluentTheme />
+    </Application.Styles>
+</Application>

+ 36 - 0
samples/SafeAreaDemo/App.xaml.cs

@@ -0,0 +1,36 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using SafeAreaDemo.ViewModels;
+using SafeAreaDemo.Views;
+
+namespace SafeAreaDemo
+{
+    public partial class App : Application
+    {
+        public override void Initialize()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+        public override void OnFrameworkInitializationCompleted()
+        {
+            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+            {
+                desktop.MainWindow = new MainWindow
+                {
+                    DataContext = new MainViewModel()
+                };
+            }
+            else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
+            {
+                singleViewPlatform.MainView = new MainView
+                {
+                    DataContext = new MainViewModel()
+                };
+            }
+
+            base.OnFrameworkInitializationCompleted();
+        }
+    }
+}

binární
samples/SafeAreaDemo/Assets/avalonia-logo.ico


+ 27 - 0
samples/SafeAreaDemo/SafeAreaDemo.csproj

@@ -0,0 +1,27 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <LangVersion>latest</LangVersion>
+    <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
+  </PropertyGroup>
+
+  
+  <ItemGroup>
+    <Compile Update="**\*.xaml.cs">
+      <DependentUpon>%(Filename)</DependentUpon>
+    </Compile>
+    <AvaloniaResource Include="**\*.xaml">
+      <SubType>Designer</SubType>
+    </AvaloniaResource>
+    <AvaloniaResource Include="Assets\**" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
+    <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
+  </ItemGroup>
+
+  <Import Project="..\..\build\BuildTargets.targets" />
+</Project>

+ 31 - 0
samples/SafeAreaDemo/ViewLocator.cs

@@ -0,0 +1,31 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Controls.Templates;
+using MiniMvvm;
+
+namespace SafeAreaDemo
+{
+    public class ViewLocator : IDataTemplate
+    {
+        public Control Build(object data)
+        {
+            if (data is null)
+                return null;
+
+            var name = data.GetType().FullName!.Replace("ViewModel", "View");
+            var type = Type.GetType(name);
+
+            if (type != null)
+            {
+                return (Control)Activator.CreateInstance(type)!;
+            }
+
+            return new TextBlock { Text = name };
+        }
+
+        public bool Match(object? data)
+        {
+            return data is ViewModelBase;
+        }
+    }
+}

+ 112 - 0
samples/SafeAreaDemo/ViewModels/MainViewModel.cs

@@ -0,0 +1,112 @@
+using Avalonia;
+using Avalonia.Controls.Platform;
+using MiniMvvm;
+
+namespace SafeAreaDemo.ViewModels
+{
+    public class MainViewModel : ViewModelBase
+    {
+        private bool _useSafeArea = true;
+        private bool _fullscreen;
+        private IInsetsManager? _insetsManager;
+        private bool _hideSystemBars;
+
+        public Thickness SafeAreaPadding
+        {
+            get
+            {
+                return _insetsManager?.SafeAreaPadding ?? default;
+            }
+        }
+
+        public Thickness ViewPadding
+        {
+            get
+            {
+                return _useSafeArea ? SafeAreaPadding : default;
+            }
+        }
+
+        public bool UseSafeArea
+        {
+            get => _useSafeArea;
+            set
+            {
+                _useSafeArea = value;
+
+                this.RaisePropertyChanged();
+
+                RaiseSafeAreaChanged();
+            }
+        }
+
+        public bool Fullscreen
+        {
+            get => _fullscreen;
+            set
+            {
+                _fullscreen = value;
+
+                if (_insetsManager != null)
+                {
+                    _insetsManager.DisplayEdgeToEdge = value;
+                }
+
+                this.RaisePropertyChanged();
+
+                RaiseSafeAreaChanged();
+            }
+        }
+
+        public bool HideSystemBars
+        {
+            get => _hideSystemBars;
+            set
+            {
+                _hideSystemBars = value;
+
+                if (_insetsManager != null)
+                {
+                    _insetsManager.IsSystemBarVisible = !value;
+                }
+
+                this.RaisePropertyChanged();
+
+                RaiseSafeAreaChanged();
+            }
+        }
+
+        internal IInsetsManager? InsetsManager
+        {
+            get => _insetsManager; 
+            set
+            {
+                if (_insetsManager != null)
+                {
+                    _insetsManager.SafeAreaChanged -= InsetsManager_SafeAreaChanged;
+                }
+
+                _insetsManager = value;
+
+                if (_insetsManager != null)
+                {
+                    _insetsManager.SafeAreaChanged += InsetsManager_SafeAreaChanged;
+
+                    _insetsManager.DisplayEdgeToEdge = _fullscreen;
+                    _insetsManager.IsSystemBarVisible = !_hideSystemBars;
+                }
+            }
+        }
+
+        private void InsetsManager_SafeAreaChanged(object? sender, SafeAreaChangedArgs e)
+        {
+            RaiseSafeAreaChanged();
+        }
+
+        private void RaiseSafeAreaChanged()
+        {
+            this.RaisePropertyChanged(nameof(SafeAreaPadding));
+            this.RaisePropertyChanged(nameof(ViewPadding));
+        }
+    }
+}

+ 52 - 0
samples/SafeAreaDemo/Views/MainView.xaml

@@ -0,0 +1,52 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:SafeAreaDemo.ViewModels"
+             mc:Ignorable="d"
+             d:DesignWidth="800"
+             d:DesignHeight="450"
+             x:Class="SafeAreaDemo.Views.MainView"
+             x:DataType="vm:MainViewModel">
+    <Grid HorizontalAlignment="Stretch"
+          VerticalAlignment="Stretch">
+        <Border BorderBrush="Red"
+                Margin="{Binding ViewPadding}"
+                BorderThickness="1">
+            <Grid>
+            <Label Margin="5"
+                   Foreground="Red"
+                   HorizontalAlignment="Stretch"
+                   HorizontalContentAlignment="Right">View Bounds</Label>
+            <Label Margin="5"
+                   Foreground="Red"
+                   VerticalAlignment="Bottom"
+                   HorizontalContentAlignment="Right">View Bounds</Label>                
+            </Grid>
+        </Border>
+        <Border BorderBrush="LimeGreen"
+                Margin="{Binding SafeAreaPadding}"
+                BorderThickness="1">
+            <DockPanel>
+                <Label Margin="5"
+                       Foreground="LimeGreen"
+                       DockPanel.Dock="Bottom"
+                       HorizontalAlignment="Stretch"
+                       HorizontalContentAlignment="Left" >Safe Area</Label>
+                <Grid DockPanel.Dock="Bottom"
+                      HorizontalAlignment="Stretch"
+                      VerticalAlignment="Stretch">
+                    <StackPanel Orientation="Vertical"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center">
+                        <Label HorizontalAlignment="Left">Options:</Label>
+                        <CheckBox IsChecked="{Binding Fullscreen}">Fullscreen</CheckBox>
+                        <CheckBox IsChecked="{Binding UseSafeArea}">Use Safe Area</CheckBox>
+                        <CheckBox IsChecked="{Binding HideSystemBars}">Hide System Bars</CheckBox>
+                        <TextBox Width="200" Watermark="Tap to Show Keyboard"/>
+                    </StackPanel>
+                </Grid>
+            </DockPanel>
+        </Border>
+    </Grid>
+</UserControl>

+ 25 - 0
samples/SafeAreaDemo/Views/MainView.xaml.cs

@@ -0,0 +1,25 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using SafeAreaDemo.ViewModels;
+
+namespace SafeAreaDemo.Views
+{
+    public partial class MainView : UserControl
+    {
+        public MainView()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+        protected override void OnLoaded()
+        {
+            base.OnLoaded();
+
+            var insetsManager = TopLevel.GetTopLevel(this)?.InsetsManager;
+            if (insetsManager != null && DataContext is MainViewModel viewModel)
+            {
+                viewModel.InsetsManager = insetsManager;
+            }
+        }
+    }
+}

+ 12 - 0
samples/SafeAreaDemo/Views/MainWindow.xaml

@@ -0,0 +1,12 @@
+<Window xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:vm="using:SafeAreaDemo.ViewModels"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:views="clr-namespace:SafeAreaDemo.Views"
+        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+        x:Class="SafeAreaDemo.Views.MainWindow"
+        Icon="/Assets/avalonia-logo.ico"
+        Title="SafeAreaDemo">
+        <views:MainView />
+</Window>

+ 13 - 0
samples/SafeAreaDemo/Views/MainWindow.xaml.cs

@@ -0,0 +1,13 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace SafeAreaDemo.Views
+{
+    public partial class MainWindow : Window
+    {
+        public MainWindow()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}