Install and How to use

How to show ovelay loading in Xamarin Forms

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

IMG_0239

Screen Shot 2016-05-12 at 11.51.00 PM

Happy Codding!

One thought on “How to show ovelay loading in Xamarin Forms

Leave a comment