--- /dev/null
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using NUnit.Framework;
+using Xamarin.UITest;
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest.Queries;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 7823, "[Bug] Frame corner radius.", PlatformAffected.Android)]
+#if UITEST
+ [Category(UITestCategories.Frame)]
+#endif
+ public class Issue7823 : TestContentPage
+ {
+ const string GetClipToOutline = "getClipToOutline";
+ const string GetClipChildren = "getClipChildren";
+ const string GetClipBounds = "getClipBounds";
+ const string SetClipBounds = "SetClipBounds";
+ const string SecondaryFrame = "Secondary Frame";
+ const string RootFrame = "Root Frame";
+ const string BoxView = "Box View";
+
+ protected override void Init()
+ {
+ var frameClippedToBouds = new Frame
+ {
+ AutomationId = SecondaryFrame,
+ CornerRadius = 10,
+ BackgroundColor = Color.Blue,
+ Padding = 0,
+ Content = new BoxView
+ {
+ AutomationId = BoxView,
+ BackgroundColor = Color.Green,
+ WidthRequest = 100,
+ HeightRequest = 100
+ }
+ };
+
+ Content = new StackLayout()
+ {
+ Children =
+ {
+ new ApiLabel(),
+ new Frame
+ {
+ AutomationId = RootFrame,
+ CornerRadius = 5,
+ BackgroundColor = Color.Red,
+ Padding = 10,
+ Content = frameClippedToBouds
+ },
+ new Button
+ {
+ AutomationId = SetClipBounds,
+ Text = "Manually set Frame.IsClippedToBounds = false",
+ Command = new Command(()=>
+ {
+ frameClippedToBouds.IsClippedToBounds = false;
+ frameClippedToBouds.CornerRadius = 11;
+ })
+ }
+ }
+ };
+ }
+
+#if UITEST && __ANDROID__
+ [Test]
+ [UiTest(typeof(Frame))]
+ public void Issue7823TestIsClippedIssue()
+ {
+ RunningApp.WaitForElement(RootFrame);
+ AssertIsClipped(true);
+ RunningApp.Tap(SetClipBounds);
+ AssertIsClipped(false);
+ }
+
+ void AssertIsClipped(bool expected)
+ {
+ if (RunningApp.IsApiHigherThan(21))
+ {
+ var cliptoOutlineValue = RunningApp.InvokeFromElement<bool>(SecondaryFrame, GetClipToOutline)[0];
+ Assert.AreEqual(expected, cliptoOutlineValue);
+ }
+ else if (RunningApp.IsApiHigherThan(19))
+ {
+ var clipBounds = RunningApp.InvokeFromElement<object>(SecondaryFrame, GetClipBounds)[0];
+ if (expected)
+ Assert.IsNotNull(clipBounds);
+ else
+ Assert.IsNull(clipBounds);
+ }
+ else
+ {
+ var clipChildrenValue = RunningApp.InvokeFromElement<bool>(SecondaryFrame, GetClipChildren)[0];
+ Assert.AreEqual(expected, clipChildrenValue);
+ }
+ }
+#endif
+ }
+}
<Compile Include="$(MSBuildThisFileDirectory)Issue7817.xaml.cs">
<SubType>Code</SubType>
</Compile>
+ <Compile Include="$(MSBuildThisFileDirectory)Issue7823.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7943.xaml.cs">
<SubType>Code</SubType>
</Compile>
return true;
}
+ public static TResult[] InvokeFromElement<TResult>(this IApp app, string element, string methodName) =>
+ app.Query(c => c.Marked(element).Invoke(methodName).Value<TResult>());
+
#if __IOS__
public static void SendAppToBackground(this IApp app, TimeSpan timeSpan)
{
_visualElementPackager.Dispose();
_visualElementPackager = null;
}
-
+
if (_backgroundDrawable != null)
{
_backgroundDrawable.Dispose();
UpdateClippedToBounds();
}
- void UpdateClippedToBounds() => this.SetClipToOutline(Element.IsClippedToBounds);
+ void UpdateClippedToBounds()
+ {
+ this.SetClipToOutline(Element.IsClippedToBounds, Element);
+ }
void UpdateBackgroundColor()
{
if (_disposed)
return;
-
+
Color bgColor = Element.BackgroundColor;
_backgroundDrawable.SetColor(bgColor.IsDefault ? AColor.White : bgColor.ToAndroid());
}
{
if (_disposed)
return;
-
+
float elevation = _defaultElevation;
if (elevation == -1f)
{
if (_disposed)
return;
-
+
if (_defaultCornerRadius == -1f)
{
_defaultCornerRadius = Radius;
cornerRadius = Context.ToPixels(cornerRadius);
_backgroundDrawable.SetCornerRadius(cornerRadius);
+
+ UpdateClippedToBounds();
}
}
}
using Android.Views;
using AView = Android.Views.View;
using AColor = Android.Graphics.Color;
+using Android.Graphics;
namespace Xamarin.Forms.Platform.Android
{
{
view.Background = drawable;
}
-
+
}
public static void SetWindowBackground(this AView view)
view.ClipToOutline = value;
}
+ public static void SetClipToOutline(this AView view, bool value, VisualElement element)
+ {
+ if (view.IsDisposed())
+ return;
+
+ var shouldClip = value;
+ if (element is Frame frame)
+ {
+ shouldClip = frame.IsSet(Layout.IsClippedToBoundsProperty)
+ ? frame.IsClippedToBounds : frame.CornerRadius > 0f;
+ }
+
+ if (view is FastRenderers.FrameRenderer && Forms.IsLollipopOrNewer)
+ {
+ view.SetClipToOutline(shouldClip);
+ return;
+ }
+
+ // setClipBounds is only available in API 18 +
+ if ((int)Build.VERSION.SdkInt >= 18)
+ {
+ if (!(view is ViewGroup viewGroup))
+ {
+ return;
+ }
+
+ // Forms layouts should not impose clipping on their children
+ viewGroup.SetClipChildren(false);
+
+ // But if IsClippedToBounds is true, they _should_ enforce clipping at their own edges
+ viewGroup.ClipBounds = shouldClip ? new Rect(0, 0, viewGroup.Width, viewGroup.Height) : null;
+ }
+ else
+ {
+ // For everything in 17 and below, use the setClipChildren method
+ if (!(view.Parent is ViewGroup parent))
+ return;
+
+ if ((int)Build.VERSION.SdkInt >= 18 && parent.ClipChildren == shouldClip)
+ return;
+
+ parent.SetClipChildren(shouldClip);
+ parent.Invalidate();
+ }
+ }
+
+
public static bool SetElevation(this AView view, float value)
{
if (view.IsDisposed() || !Forms.IsLollipopOrNewer)
view.Elevation = value;
return true;
}
-
+
internal static void MaybeRequestLayout(this AView view)
{
var isInLayout = false;
return;
}
- bool shouldClip = layout.IsClippedToBounds;
-
- // setClipBounds is only available in API 18 +
- if ((int)Forms.SdkInt >= 18)
- {
- if (!(_renderer.View is ViewGroup viewGroup))
- {
- return;
- }
-
- // Forms layouts should not impose clipping on their children
- viewGroup.SetClipChildren(false);
-
- // But if IsClippedToBounds is true, they _should_ enforce clipping at their own edges
- viewGroup.ClipBounds = shouldClip ? new Rect(0, 0, viewGroup.Width, viewGroup.Height) : null;
- }
- else
- {
- // For everything in 17 and below, use the setClipChildren method
- if (!(_renderer.View.Parent is ViewGroup parent))
- return;
-
- if ((int)Forms.SdkInt >= 18 && parent.ClipChildren == shouldClip)
- return;
-
- parent.SetClipChildren(shouldClip);
- parent.Invalidate();
- }
+ _renderer.View.SetClipToOutline(layout.IsClippedToBounds, _renderer.Element);
}
void UpdateIsVisible()