Permalink
Browse files

Remove status bar underlay view in Android AppCompat (#892)

* Remove status bar underlay and handle status bar color with theme colors

* Fix layout gap when SoftInputMode is set to resize

* Restore linker settings
  • Loading branch information...
hartez authored and kingces95 committed May 4, 2017
1 parent 34a1cc8 commit 1e1785016aef68fb36907d5b7662eda2aa403825
@@ -15,6 +15,8 @@
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppLinks;
using Android.Content;
using Android.Views;
using AColor = Android.Graphics.Color;
[assembly: Dependency (typeof (CacheService))]
[assembly: Dependency (typeof (TestCloudService))]
@@ -286,6 +288,9 @@ protected override void OnCreate (Bundle bundle)
ToolbarResource = Resource.Layout.Toolbar;
TabLayoutResource = Resource.Layout.Tabbar;
// Uncomment the next line to run this as a full screen app (no status bar)
//Window.AddFlags(WindowManagerFlags.Fullscreen | WindowManagerFlags.TurnScreenOn);
base.OnCreate (bundle);
if (!Debugger.IsAttached)
@@ -311,6 +316,9 @@ protected override void OnCreate (Bundle bundle)
// When the native binding gallery loads up, it'll let us know so we can set up the native bindings
MessagingCenter.Subscribe<NativeBindingGalleryPage >(this, NativeBindingGalleryPage.ReadyForNativeBindingsMessage, AddNativeBindings);
// Listen for the message from the status bar color toggle test
MessagingCenter.Subscribe<AndroidStatusBarColor>(this, AndroidStatusBarColor.Message, color => SetStatusBarColor(AColor.Red));
LoadApplication(app);
}
@@ -2,4 +2,5 @@
<resources>
<color name="cellback">#FFFFFFE0</color>
<color name="cellback2">#FFDAFF7F</color>
<color name="primary_dark">#1976D2</color>
</resources>
@@ -18,7 +18,7 @@
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">#2196F3</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#1976D2</item>
<item name="android:colorPrimaryDark">@color/primary_dark</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#FF4081</item>
@@ -0,0 +1,37 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.None, 5553226, "Set status bar color on Android", PlatformAffected.Android)]
public class AndroidStatusBarColor : TestContentPage
{
public const string Message = "ChangeStatusBarToRed";
protected override void Init()
{
var layout = new StackLayout
{
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
Margin = new Thickness(100)
};
var instructions = new Label
{
Text =
"Tapping the button below should change the status bar color to red. If the status bar does not change to red, the test has failed. (Ignore this test for pre-Lollipop devices.)"
};
var button = new Button { Text = "Change Status Bar Color" };
button.Clicked += (sender, args) => { MessagingCenter.Send(this, Message); };
layout.Children.Add(instructions);
layout.Children.Add(button);
Content = layout;
}
}
}
@@ -0,0 +1,59 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Bugzilla, 47548, "Setting soft input mode to resize creates gap", PlatformAffected.Android)]
public class Bugzilla47548 : TestContentPage
{
static string GetMode()
{
return Application.Current.On<Android>().GetWindowSoftInputModeAdjust() == WindowSoftInputModeAdjust.Pan
? "Pan"
: "Resize";
}
protected override void Init()
{
var button = new Button() { Text = $"Toggle Soft Input Mode (Currently {GetMode()})"};
button.Clicked += (sender, args) =>
{
Application.Current.On<Android>()
.UseWindowSoftInputModeAdjust(Application.Current.On<Android>().GetWindowSoftInputModeAdjust() ==
WindowSoftInputModeAdjust.Pan
? WindowSoftInputModeAdjust.Resize
: WindowSoftInputModeAdjust.Pan);
button.Text = $"Toggle Soft Input Mode (Currently {GetMode()})";
};
Content = new StackLayout
{
BackgroundColor = Color.CadetBlue,
Spacing = 10,
VerticalOptions = LayoutOptions.Fill,
Children =
{
new Label
{
Text = @"With Soft Input Mode set to Pan, tapping the Entry at the bottom of the screen should cause the whole page to scroll up above the keyboard.
With Soft Input Mode set to Resize, tapping the Entry at the bottom of the screen should resize the content to display everything above the keyboard (the Crimson Label in the middle should be squashed to fit)."
},
button,
new Label
{
FontSize = 12f,
HeightRequest = 500,
Text = @"Meh",
BackgroundColor = Color.Crimson
},
new Entry()
}
};
}
}
}
@@ -10,6 +10,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)AddingMultipleItemsListView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AndroidStatusBarColor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AppBarIconColors.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla21368.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla21501.cs" />
@@ -160,6 +161,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44096.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44176.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44453.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla47548.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla53834.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla51536.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44940.cs" />
@@ -45,8 +45,6 @@ public class FormsAppCompatActivity : AppCompatActivity, IDeviceInfoProvider, IS
AndroidApplicationLifecycleState _previousState;
bool _renderersAdded, _isFullScreen;
int _statusBarHeight = -1;
global::Android.Views.View _statusBarUnderlay;
// Override this if you want to handle the default Android behavior of restoring fragments on an application restart
protected virtual bool AllowFragmentRestore => false;
@@ -105,7 +103,10 @@ public override bool OnOptionsItemSelected(IMenuItem item)
public void SetStatusBarColor(AColor color)
{
_statusBarUnderlay.SetBackgroundColor(color);
if (Forms.IsLollipopOrNewer)
{
Window.SetStatusBarColor(color);
}
}
protected void LoadApplication(Application application)
@@ -171,7 +172,7 @@ protected override void OnCreate(Bundle savedInstanceState)
}
else
bar = new AToolbar(this);
SetSupportActionBar(bar);
_layout = new ARelativeLayout(BaseContext);
@@ -184,7 +185,11 @@ protected override void OnCreate(Bundle savedInstanceState)
OnStateChanged();
AddStatusBarUnderlay();
if (Forms.IsLollipopOrNewer)
{
// Allow for the status bar color to be changed
Window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
}
}
protected override void OnDestroy()
@@ -280,45 +285,6 @@ protected override void OnStop()
OnStateChanged();
}
internal int GetStatusBarHeight()
{
if (_statusBarHeight >= 0)
return _statusBarHeight;
var result = 0;
int resourceId = Resources.GetIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
result = Resources.GetDimensionPixelSize(resourceId);
return _statusBarHeight = result;
}
void AddStatusBarUnderlay()
{
_statusBarUnderlay = new global::Android.Views.View(this);
var layoutParameters = new ARelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, GetStatusBarHeight()) { AlignWithParent = true };
layoutParameters.AddRule(LayoutRules.AlignTop);
_statusBarUnderlay.LayoutParameters = layoutParameters;
_layout.AddView(_statusBarUnderlay);
if (Forms.IsLollipopOrNewer)
{
Window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
Window.SetStatusBarColor(AColor.Transparent);
int primaryColorDark = GetColorPrimaryDark();
if (primaryColorDark != 0)
{
int r = AColor.GetRedComponent(primaryColorDark);
int g = AColor.GetGreenComponent(primaryColorDark);
int b = AColor.GetBlueComponent(primaryColorDark);
int a = AColor.GetAlphaComponent(primaryColorDark);
SetStatusBarColor(AColor.Argb(a, r, g, b));
}
}
}
void AppOnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == "MainPage")
@@ -338,32 +304,6 @@ void CheckForAppLink(Intent intent)
_application?.SendOnAppLinkRequestReceived(link);
}
int GetColorPrimaryDark()
{
FormsAppCompatActivity context = this;
int id = global::Android.Resource.Attribute.ColorPrimaryDark;
using (var value = new TypedValue())
{
try
{
Resources.Theme theme = context.Theme;
if (theme != null && theme.ResolveAttribute(id, value, true))
{
if (value.Type >= DataType.FirstInt && value.Type <= DataType.LastInt)
return value.Data;
if (value.Type == DataType.String)
return ContextCompat.GetColor(context, value.ResourceId);
}
}
catch (Exception ex)
{
Internals.Log.Warning("Xamarin.Forms.Platform.Android.FormsAppCompatActivity", "Error retrieving color resource: {0}", ex);
}
return -1;
}
}
void InternalSetPage(Page page)
{
if (!Forms.IsInitialized)
@@ -477,7 +417,6 @@ void SetSoftInputMode()
}
Window.SetSoftInputMode(adjust);
SetStatusBarVisibility(adjust);
}
public override void OnWindowAttributesChanged(WindowManagerLayoutParams @params)
@@ -512,21 +451,6 @@ public override void OnWindowAttributesChanged(WindowManagerLayoutParams @params
AppCompat.Platform.LayoutRootPage(this, Xamarin.Forms.Application.Current.MainPage, width, height);
}
void SetStatusBarVisibility(SoftInput mode)
{
if (!Forms.IsLollipopOrNewer)
return;
if (mode == SoftInput.AdjustResize)
{
Window.DecorView.SystemUiVisibility = (StatusBarVisibility)(SystemUiFlags.Immersive);
}
else
Window.DecorView.SystemUiVisibility = (StatusBarVisibility)(SystemUiFlags.LayoutFullscreen | SystemUiFlags.LayoutStable);
_layout?.Invalidate();
}
void UpdateProgressBarVisibility(bool isBusy)
{
if (!Forms.SupportsProgress)
@@ -113,23 +113,17 @@ void IVisualElementRenderer.SetElement(VisualElement element)
oldElement.Disappearing -= MasterDetailPageDisappearing;
}
var statusBarHeight = 0;
if (Forms.IsLollipopOrNewer)
statusBarHeight = ((FormsAppCompatActivity)Context).GetStatusBarHeight();
if (newElement != null)
{
if (_detailLayout == null)
{
_detailLayout = new MasterDetailContainer(newElement, false, Context)
{
TopPadding = HasAncestorNavigationPage(Element) ? 0 : statusBarHeight,
LayoutParameters = new LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent)
};
_masterLayout = new MasterDetailContainer(newElement, true, Context)
{
TopPadding = ((IMasterDetailPageController)newElement).ShouldShowSplitMode ? statusBarHeight : 0,
LayoutParameters = new LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent) { Gravity = (int)GravityFlags.Start }
};
@@ -8,7 +8,6 @@
using Android.Views.Animations;
using ARelativeLayout = Android.Widget.RelativeLayout;
using Xamarin.Forms.Internals;
using Debug = System.Diagnostics.Debug;
namespace Xamarin.Forms.Platform.Android.AppCompat
{
@@ -196,7 +195,9 @@ SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint,
void IPlatformLayout.OnLayout(bool changed, int l, int t, int r, int b)
{
if (changed)
{
LayoutRootPage((FormsAppCompatActivity)_context, Page, r - l, b - t);
}
Android.Platform.GetRenderer(Page).UpdateLayout();
@@ -286,15 +287,7 @@ bool HandleBackPressed(object sender, EventArgs e)
internal static void LayoutRootPage(FormsAppCompatActivity activity, Page page, int width, int height)
{
int statusBarHeight = Forms.IsLollipopOrNewer ? activity.GetStatusBarHeight() : 0;
statusBarHeight = activity.Window.Attributes.Flags.HasFlag(WindowManagerFlags.Fullscreen) || Forms.TitleBarVisibility == AndroidTitleBarVisibility.Never ? 0 : statusBarHeight;
if (page is MasterDetailPage)
page.Layout(new Rectangle(0, 0, activity.FromPixels(width), activity.FromPixels(height)));
else
{
page.Layout(new Rectangle(0, activity.FromPixels(statusBarHeight), activity.FromPixels(width), activity.FromPixels(height - statusBarHeight)));
}
page.Layout(new Rectangle(0, 0, activity.FromPixels(width), activity.FromPixels(height)));
}
Task PresentModal(Page modal, bool animated)
@@ -381,18 +374,12 @@ protected override void Dispose(bool disposing)
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
var activity = (FormsAppCompatActivity)Context;
int statusBarHeight = Forms.IsLollipopOrNewer ? activity.GetStatusBarHeight() : 0;
if (changed)
{
if (_modal is MasterDetailPage)
_modal.Layout(new Rectangle(0, 0, activity.FromPixels(r - l), activity.FromPixels(b - t)));
else
{
_modal.Layout(new Rectangle(0, activity.FromPixels(statusBarHeight), activity.FromPixels(r - l), activity.FromPixels(b - t - statusBarHeight)));
}
var activity = (FormsAppCompatActivity)Context;
_backgroundView.Layout(0, statusBarHeight, r - l, b - t);
_modal.Layout(new Rectangle(0, 0, activity.FromPixels(r - l), activity.FromPixels(b - t)));
_backgroundView.Layout(0, 0, r - l, b - t);
}
_renderer.UpdateLayout();

0 comments on commit 1e17850

Please sign in to comment.