Hi guys,
In this post, I will create overlay loading in android and ios use DependencyService in Xamarin Forms
Create XOverLayControl
public class XOverLayControl { public XOverLayControl() { BackgroundColor = Color.Default; HasNavigationBar = true; HasTabbedBar = false; Alpha = Device.OS == TargetPlatform.Android ? 255 : 1; AnimateClosing = false; } public Color BackgroundColor { get; set; } public bool HasTabbedBar { get; set; } public bool HasNavigationBar { get; set; } public bool AnimateClosing { get; set; } /// <summary> /// <para>Android: 0 - 255</para> /// <para>iOS: 0 - 1</para> /// </summary> /// <value>The alpha.</value> public float Alpha { get; set; } }
Create interface IShowOverlay
public interface IShowOverLay { /// <summary> /// Shows the loading screen. /// </summary> /// <param name="details">OverlayDetails</param> void ShowLoadingScreen(XOverLayControl details); /// <summary> /// Hides all. /// </summary> void HideAll(); }
In your iOS project create OverlayView
public static class ViewExtensions { /// <summary> /// Flatten the specified source and recursion. /// foreach(var category in categories.Flatten(c => c.Children)) /// </summary> /// <param name="source">Source.</param> /// <param name="childrenSelector"></param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static IEnumerable<T> Flatten<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector) { foreach (var item in source) { yield return item; foreach (var child in childrenSelector(item).Flatten(childrenSelector)) { yield return child; } } } public static T FirstOrDefaultFromMany<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector, Predicate<T> condition) { while (true) { // return default if no items var enumerable = source as T[] ?? source.ToArray(); if (source == null || !enumerable.Any()) return default(T); // return result if found and stop traversing hierarchy var attempt = enumerable.FirstOrDefault(t => condition(t)); if (!Equals(attempt, default(T))) return attempt; // recursively call this function on lower levels of the // hierarchy until a match is found or the hierarchy is exhausted source = enumerable.SelectMany(childrenSelector); } } } public abstract class OverlayView : UIView { protected internal readonly float NavigationBarHeightPortrait = 45; protected internal readonly float NavigationBarHeightOther = 33; //maybe + 1 protected internal readonly float TabBarHeight = 49; protected internal readonly float NotPortraitHeightOffset = 10; private bool _registeredForObserver; private readonly XOverLayControl _viewDetails; protected OverlayView(IntPtr h) : base(h) { } protected OverlayView() { } private void RegisterForObserver() { var notificationCenter = NSNotificationCenter.DefaultCenter; notificationCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange); UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications(); _registeredForObserver = true; } protected OverlayView(XOverLayControl details, bool xibView = false) { // configurable bits _viewDetails = details; //this.BackgroundColor = UIColor.Black; if (_viewDetails.HasNavigationBar == false) { // check NavigationBar _viewDetails.HasNavigationBar = UIApplication.SharedApplication.KeyWindow.Subviews.FirstOrDefaultFromMany(item => item.Subviews, x => x is UINavigationBar) != null; NavigationBarHeightOther = 0; NavigationBarHeightPortrait = 0; } if (xibView == false) { SetViewProperties(this); } RegisterForObserver(); } protected internal void SetViewProperties(UIView view) { BackgroundColor = _viewDetails.BackgroundColor != Color.Default ? _viewDetails.BackgroundColor.ToUIColor() : UIColor.White; Alpha = 1; //(nfloat)this.ViewDetails.Alpha; } private void DeviceOrientationDidChange(NSNotification notification) { DoLayout(); } internal abstract void DoLayout(); /// <summary> /// Fades out the control and then removes it from the super view /// </summary> protected internal void Hide() { if (_viewDetails != null && _viewDetails.AnimateClosing) { Animate( 0.5, // duration () => { Alpha = 0; }, RemoveFromSuperview ); } else { RemoveFromSuperview(); } if (_registeredForObserver) { var notificationCenter = NSNotificationCenter.DefaultCenter; notificationCenter.RemoveObserver(this, UIDevice.OrientationDidChangeNotification, UIApplication.SharedApplication); UIDevice.CurrentDevice.EndGeneratingDeviceOrientationNotifications(); notificationCenter.RemoveObserver(this, UIApplication.DidBecomeActiveNotification, UIApplication.SharedApplication); } Dispose(); } /// <summary> /// Gets the height of the status bar. /// </summary> /// <value>The height of the status bar.</value> protected internal nfloat StatusBarHeight { get { var statusHidden = UIApplication.SharedApplication.StatusBarHidden; nfloat statusHeight = 0; if (statusHidden == false) { statusHeight = UIApplication.SharedApplication.StatusBarFrame.Height; } return statusHeight; } } protected internal void SetFrame() { Frame = GetFrame(); } protected internal CGRect GetFrame() { var bounds = UIScreen.MainScreen.ApplicationFrame; //Show overlay full Screen var frame = new CGRect(0, StatusBarHeight, bounds.Width, bounds.Height); return frame; } }
create LoadingView
public sealed class LoadingView : OverlayView { // control declarations private readonly UIActivityIndicatorView _activitySpinner; public LoadingView(XOverLayControl details) : base(details) { DoLayout(); // derive the center x and y var centerX = Frame.Width/2; var centerY = Frame.Height/2; // create the activity spinner, center it horizontall and put it 5 points above center x var transform = CoreGraphics.CGAffineTransform.MakeScale(1.5f, 1.5f); _activitySpinner = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.Gray) {Transform = transform}; //WhiteLarge); _activitySpinner.Frame = new CGRect( centerX - (_activitySpinner.Frame.Width/2), centerY - (_activitySpinner.Frame.Height/2), _activitySpinner.Frame.Width, _activitySpinner.Frame.Height); _activitySpinner.AutoresizingMask = UIViewAutoresizing.FlexibleMargins; AddSubview(_activitySpinner); _activitySpinner.StartAnimating(); } internal override void DoLayout() { base.SetFrame(); if (_activitySpinner != null) { var centerX = Frame.Width/2; var centerY = Frame.Height/2; _activitySpinner.Frame = new CGRect( centerX - (_activitySpinner.Frame.Width/2), centerY - (_activitySpinner.Frame.Height/2), _activitySpinner.Frame.Width, _activitySpinner.Frame.Height); } } }
create DependencyService
[assembly: Dependency(typeof(ShowOverlay))] namespace yournamespace { public class ShowOverlay : IShowOverLay { private const int LoadingOverLay = 1001; public ShowOverlay () { } private static UIWindow MainWindow => UIApplication.SharedApplication.KeyWindow; public void HideAll() { WriteMessage ("HideAll"); HideAll(-1); } private static void WriteMessage(string message) { System.Diagnostics.Debug.WriteLine(message); } private static bool HideAll(int keepOverlay) { var found = false; var items = MainWindow.Subviews; if (keepOverlay != DisabledOverLay) { var frag = items.FirstOrDefault(x => x.Tag == DisabledOverLay); if (frag != null) { WriteMessage ("Hiding: DisabledOverLay"); var overlayView = frag as OverlayView; overlayView?.Hide(); found = true; } } if (keepOverlay != LoadingOverLay) { var frag = items.FirstOrDefault(x => x.Tag == LoadingOverLay); if (frag != null) { WriteMessage ("Hiding: LoadingOverLay"); var overlayView = frag as OverlayView; overlayView?.Hide(); found = true; } } if (keepOverlay != BlankOverLay) { var frag = items.FirstOrDefault(x => x.Tag == BlankOverLay); if (frag != null) { WriteMessage ("Hiding: BlankOverLay"); var overlayView = frag as OverlayView; overlayView?.Hide(); found = true; } } return found; } public void ShowLoadingScreen(XOverLayControl details) { if (IsActive(LoadingOverLay) == false) { WriteMessage ("ShowLoadingScreen"); var view = new LoadingView(details) { Tag = LoadingOverLay, Alpha = details.Alpha }; MainWindow.AddSubview(view); HideAll (LoadingOverLay); } } private static bool IsActive(int overlay) { var t = UIApplication.SharedApplication.KeyWindow; return MainWindow.Subviews.FirstOrDefault(x => x.Tag == overlay) != null; } public bool CanRun => MainWindow != null; } }
In Android Project
Create OverlayFragment
internal class OverLayFragments : Fragment { protected internal readonly float NavigationBarHeightPortrait = 44; protected internal readonly float NavigationBarHeightOther = 32; protected internal readonly float TabBarHeight = 49; protected internal readonly float NotPortraitHeightOffset = 10; protected internal XOverLayControl ViewDetails; public OverLayFragments() { } public OverLayFragments(XOverLayControl details) { ViewDetails = details; } protected internal void SetView(View view, Activity activity) { if (ViewDetails != null) { if (ViewDetails.BackgroundColor == Color.Default) { var r = activity.Window.DecorView.RootView; view.Background = r.Background; } else { view.SetBackgroundColor(ViewDetails.BackgroundColor.ToAndroid()); } // 1 to 255 for Android // 0 (fully transparent) to 255 (completely opaque) if (Math.Abs(ViewDetails.Alpha - 1) > double.Epsilon) { view.Background.Alpha = (int) ViewDetails.Alpha; } } } internal void Hide() { if (ViewDetails != null && ViewDetails.AnimateClosing && View != null) { var animation1 = new AlphaAnimation(View.Alpha, 0) { Duration = 500, StartOffset = 100 }; View.StartAnimation(animation1); } } }
and then LoadingFragment
internal class LoadingFragment : OverLayFragments { public static LoadingFragment NewInstance(XOverLayControl details) { var detailsFrag = new LoadingFragment { Arguments = new Bundle(), ViewDetails = details }; return detailsFrag; } public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (container == null) { return null; } var view = inflater.Inflate(Resource.Layout.LoadingLayout, null); var activity = Xamarin.Forms.Forms.Context as Activity; SetView(view, activity); return view; } }
create layout for this fragment, LoadingLayout.axml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/relativeLayout1" android:minWidth="25px" android:minHeight="25px"> <ProgressBar style="?android:attr/progressBarStyleLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar1" android:layout_centerInParent="true" android:minWidth="100dp" android:minHeight="100dp" /> </RelativeLayout>
create DependencyService
[assembly: Dependency(typeof(ShowOverlay))] namespace yournamespace { public class ShowOverlay : IShowOverLay { private readonly string LoadingOverLay = "loading"; private static Activity Current => Forms.Context as Activity; public void HideAll() { using (var manager = Current.FragmentManager.BeginTransaction()) { if (HideAll(manager, "")) { manager.Commit(); } } } public void HideAll(string keepOverlay) { using (var manager = Current.FragmentManager.BeginTransaction()) { if (HideAll(manager, keepOverlay)) { manager.Commit(); } } } private bool HideAll(FragmentTransaction manager, string keepOverlay) { var found = false; if (keepOverlay != DisabledOverLay) { var frag = Current.FragmentManager.FindFragmentByTag(DisabledOverLay); if (frag != null) { manager.Remove(frag); found = true; } } if (keepOverlay != LoadingOverLay) { var frag = Current.FragmentManager.FindFragmentByTag(LoadingOverLay); if (frag != null) { manager.Remove(frag); found = true; } } if (keepOverlay != BlankOverLay) { var frag = Current.FragmentManager.FindFragmentByTag(BlankOverLay); if (frag != null) { manager.Remove(frag); found = true; } } return found; } public void ShowLoadingScreen(XOverLayControl details) { if (IsActive(LoadingOverLay) == false) { var frag = LoadingFragment.NewInstance(details); using (var manager = Current.FragmentManager.BeginTransaction()) { manager.Add(Android.Resource.Id.Content, frag, LoadingOverLay); HideAll(manager, LoadingOverLay); manager.Commit(); } } } private static bool IsActive(string overlay) { var activity = Forms.Context as Activity; var f = activity?.FragmentManager.FindFragmentByTag(overlay); return f != null; } public bool CanRun => true; } }
and How to use
var overlay = DependencyService.Get<IShowOverLay>();
overlay.ShowLoadingScreen(new XOverLayControl
{
Alpha = Device.OnPlatform(0.5f, 150, 1),
BackgroundColor = Color.Gray
});
The Result
Happy Codding!
Should this disable all below control or not?
LikeLike