Reputation: 1158
Using information found on the net, I created a PlatformEffect for iOS that can be assigned to any element. It adjusts the view to take into account an iPhone notch, if present.
My problem is, I am unable to reference the platform effect in my XAML.
Theortically, given the code at the bottom of this message, I should be able to use the following to apply the effect:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Enterprise.View.Features.Authentication.LoginView"
xmlns:effect="clr-namespace:Enterprise.iOS.Effects">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentView BackgroundColor="Green">
<ContentView.Effects>
<effect:SafeAreaPaddingEffect />
</ContentView.Effects>
<Label Text="Hello, from XamarinHelp.com" />
</ContentView>
</Grid>
</ContentPage>
However, the effect
reference cannot be resolved in the ContentPage declaration. I'm probably doing something wrong, but I'm not sure what it is. I have not found anything via searches that answer my question.
Any thoughts? Here is the PlatformEffect file (located under an Effects folder in the iOS solution):
using Enterprise.iOS.Effects;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ResolutionGroupName("Enterprise.iOS")]
[assembly: ExportEffect(typeof(SafeAreaPaddingEffect), nameof(SafeAreaPaddingEffect))]
namespace Enterprise.iOS.Effects
{
public class SafeAreaPaddingEffect : PlatformEffect
{
Thickness _padding;
protected override void OnAttached()
{
if (Element is Layout element)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
_padding = element.Padding;
var insets =
UIApplication.SharedApplication.Windows[0].SafeAreaInsets; // Can't use KeyWindow this early
if (insets.Top > 0) // We have a notch
{
element.Padding = new Thickness(_padding.Left + insets.Left, _padding.Top + insets.Top,
_padding.Right + insets.Right, _padding.Bottom);
return;
}
}
// Uses a default Padding of 20. Could use an property to modify if you wanted.
element.Padding = new Thickness(_padding.Left, _padding.Top + 20, _padding.Right, _padding.Bottom);
}
}
protected override void OnDetached()
{
if (Element is Layout element)
{
element.Padding = _padding;
}
}
}
}
Upvotes: 0
Views: 308
Reputation: 1158
I was able to fix this by assigning the effect in the code behind. So the relevant XAML not looks like the following
<ContentView BackgroundColor="Green">
<Label x:Name="HelloLabel" Text="Hello, from XamarinHelp.com" />
</ContentView>
and in my code behind, I added the followin immediately after initializing the component
HelloLabel.Effects.Add(Effect.Resolve("Enterprise.iOS.Effects.SafeAreaPaddingEffect"));
Upvotes: 0
Reputation: 2995
To implement an effect for usage in a XAML Xamarin Forms project the following classes might be defined:
MyEffects.EffectIds
(namespace MyEffects
, class name EffectIds
) located in a Xamarin Forms or a Netstandard project (e.g. MyProject
) to define the identifier of the Effect.
MyEffects.MyEffect
(namespace MyEffects
, class name MyEffect
) located in a Xamarin Forms project or a Netstandard project (e.g. MyProject
) to define the Xamarin Forms effect.
MyEffects.iOS.MyEffect
(namespace MyEffects.iOS
, class name MyEffect
) located in an iOS project to implement the iOS effect.
Sample MyEffects.EffectIds
:
using Xamarin.Forms;
[assembly: ResolutionGroupName(MyEffects.EffectIds.GroupName)]
namespace MyEffects
{
public class EffectIds
{
public const string GroupName = "MyEffects";
public static string MyEffect => typeof(MyEffect).FullName;
//another effect not defined here
public static string MyOtherEffect => typeof(MyOtherEffect).FullName;
...
Sample MyEffects.MyEffect
:
using Xamarin.Forms;
namespace MyEffects
{
public class MyEffect : RoutingEffect
{
public MyEffect() : base(EffectIds.MyEffect) { }
}
}
Sample MyEffects.iOS.MyEffect
:
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using PlatformEffects = MyEffects.iOS;
using RoutingEffects = MyEffects;
[assembly: ExportEffect(typeof(PlatformEffects.MyEffect), nameof(RoutingEffects.MyEffect))]
namespace MyEffects.iOS
{
public class MyEffect : PlatformEffect
{
protected override void OnAttached()
{
...
Sample usage in XAML:
<ContentPage
xmlns:effects="clr-namespace:MyEffects;assembly=MyProject"
...
<Entry ... >
<Entry.Effects>
<effects:MyEffect />
</Entry.Effects>
</Entry>
Upvotes: 1