Reputation: 1052
So I made an interface with reference to an SVG file where coordinates of views are copied from.
For instance, the whole SVG image is 250x800, so I set the width and height of the AbsoluteLayout
to be the same. The individual control sizes are also copied to the layout bounds, each are 250x200 in this example. Corner radius properties, font sizes, border radius properties are also copied, but for the sake of brevity, the use is not shown here.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="AndroidSquare.MainPage">
<AbsoluteLayout WidthRequest="250" HeightRequest="800" HorizontalOptions="Center" VerticalOptions="Center">
<BoxView Color="Red" AbsoluteLayout.LayoutBounds="0, 0,250,200"/>
<BoxView Color="Yellow" AbsoluteLayout.LayoutBounds="0,200,250,200"/>
<BoxView Color="Green" AbsoluteLayout.LayoutBounds="0,400,250,200"/>
<BoxView Color="Blue" AbsoluteLayout.LayoutBounds="0,600,250,200"/>
</AbsoluteLayout>
</ContentPage>
Running it in the Android Emulator provided with Visual Studio 16.1.4 (Nexus 5X, Android 9.0, x86):
As you can see, the view is too large. The following piece of code scales it back.
public MainPage()
{
InitializeComponent();
ScalePage(this);
}
static void ScalePage(ContentPage page) {
void Scale(object _, EventArgs __) {
var contentMeasure = page.Content.Measure(double.PositiveInfinity, double.PositiveInfinity, MeasureFlags.IncludeMargins);
var contentWidth = contentMeasure.Request.Width;
var contentHeight = contentMeasure.Request.Height;
var contentWidthOnScreen = page.Content.Width;
var contentHeightOnScreen = page.Content.Height;
var displayInfo = Xamarin.Essentials.DeviceDisplay.MainDisplayInfo;
var (appWidth, appHeight) =
Device.RuntimePlatform == Device.UWP ?
// Sadly, Xamarin.Essentials.DeviceDisplay.MainDisplayInfo returns the size of the whole monitor, not the app window size
(page.Width, page.Height) :
// Sadly, page.Width and page.Height are both -1. on start up with Android which are uninitialized values.
(displayInfo.Width / displayInfo.Density, displayInfo.Height / displayInfo.Density);
var scaleW = appWidth / contentWidth;
var scaleH = appHeight / contentHeight;
var scale = Math.Min(scaleW, scaleH);
page.Scale = scale;
// Move page back to screen
// Scale is applied to translation as well
if (scale < 1) {
page.TranslationX = (contentWidthOnScreen - contentWidth) / 2 * scale * scale;
page.TranslationY = (contentHeightOnScreen - contentHeight) / 2 * scale * scale;
}
}
page.Appearing += Scale;
page.SizeChanged += Scale;
}
It now looks like this:
How to make the bottom blue box show itself in its entirety? This seems like a problem specifically for Android, because on UWP it looks like this:
Referencing Android View Disappearing When Go Outside Of Parent, I have tried a platform effect that sets all parents and children to not clip children out of bounds:
[assembly: Xamarin.Forms.ResolutionGroupName("My")]
[assembly: Xamarin.Forms.ExportEffect(typeof(AndroidSquare.Droid.AndroidVisibleOutOfBoundsChildrenEffect), "Effect")]
namespace AndroidSquare.Droid
{
class AndroidVisibleOutOfBoundsChildrenEffect : Xamarin.Forms.Platform.Android.PlatformEffect
{
protected override void OnAttached()
{
void NoClip(Android.Views.ViewGroup v)
{
v.SetClipChildren(false);
v.SetClipToPadding(false);
}
void NoClipChildren(Android.Views.ViewGroup v)
{
NoClip(v);
for (var i = 0; i < v.ChildCount; i++)
if (v.GetChildAt(i) is Android.Views.ViewGroup child)
NoClipChildren(child);
}
void NoClipParent(Android.Views.ViewGroup v)
{
NoClip(v);
if (v.Parent is Android.Views.ViewGroup parent) NoClipParent(parent);
}
// Control is null, effect is used on ContentPage
NoClipChildren(Container);
NoClipParent(Container);
}
protected override void OnDetached() { }
}
}
public MainPage()
{
InitializeComponent();
ScalePage(this);
Effects.Add(Effect.Resolve("My.Effect"));
}
Breakpoints set inside the effect are hit as expected, however, the output still looks like the second screenshot. How to make the Android version look the same as UWP? I have been stuck on this issue for days.
Upvotes: 1
Views: 767
Reputation: 10346
How to make the bottom blue box show itself in its entirety? This seems like a problem specifically for Android
If you scale your page as the code, because the screen width and height don'e change, so you just scale the AbsoluteLayout.
When I don't use the code to scale, I also don't see the entire bule boxview, so you just add Scrollview to display all boxviews.
<ScrollView>
<AbsoluteLayout
HeightRequest="800"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="250">
<BoxView AbsoluteLayout.LayoutBounds="0, 0,250,200" Color="Red" />
<BoxView AbsoluteLayout.LayoutBounds="0,200,250,200" Color="Yellow" />
<BoxView AbsoluteLayout.LayoutBounds="0,400,250,200" Color="Green" />
<BoxView AbsoluteLayout.LayoutBounds="0,600,250,200" Color="Blue" />
</AbsoluteLayout>
</ScrollView>
Upvotes: 1