7 Kasım 2016 Pazartesi

Xamarin.Forms Simple Popup Layout

Hi there, I needed Popup in my project, but I couldn't find a simple solution for Xamarin.Forms. So me and my friend developed a simple PopupLayout for us. It is a quick solution until find a better one. Maybe it can help you too;

Let's create a class in Forms project.



using System.Threading.Tasks;
using Xamarin.Forms;

namespace MyProject
{
    public class PopupLayout : RelativeLayout
    {
        private View _content;
        private View _popup;
        private RelativeLayout _backdrop;

        protected override void OnChildAdded(Element child)
        {
            base.OnChildAdded(child);
        }

        public View Content
        {
            get { return _content; }
            set {
                if (_content != null)
                    Children.Remove(_content);
                    _content = value;
                    Children.Add(_content, () => Bounds);
            }

        }

        public bool IsPopupActive
        {
            get { return _popup != null; }
        }

        public async Task<bool> ShowPopup(View popupView, string title = null)
        {
            await DismissPopup();

            _popup = popupView;

            _popup.VerticalOptions = LayoutOptions.CenterAndExpand;

            if (_content != null)
                _content.InputTransparent = true;

            var backdrop = new RelativeLayout
            {
                BackgroundColor = Color.FromRgba(0, 0, 0, 0.4),
                Opacity = 0,
                GestureRecognizers = { new TapGestureRecognizer() },
                Padding = new Thickness(20),
                VerticalOptions = LayoutOptions.CenterAndExpand
            };

            var clickArea = new RelativeLayout
            {
                BackgroundColor = Color.Transparent,
                Opacity = 0
            };

            var tap = new TapGestureRecognizer();
            tap.Tapped += Tap_Tapped;
            clickArea.GestureRecognizers.Add(tap);

            var w = Constraint.RelativeToParent(p => p.Width - 40);
            var h = Constraint.RelativeToParent(p => p.Height - 40);
            var zero = Constraint.Constant(20);

            var sl = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.CenterAndExpand,
                Spacing = 0
            };

            var csl =new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.CenterAndExpand,
                Spacing = 0
            };


            if (!string.IsNullOrEmpty(title))
            {
                //This is a FontAwesome Label. We made it. You can use anything you want instead of this.
                var closeLabel = new FALabel 
                {
                    Text = FAIcon.Times, //this it fontawesome icon Unicode
                    HorizontalOptions = LayoutOptions.EndAndExpand,
                    VerticalOptions = LayoutOptions.StartAndExpand,
                    TextColor = Color.White,
                    VerticalTextAlignment = TextAlignment.Center,
                    FontSize = 22
                };                

                closeLabel.GestureRecognizers.Add(tap);

                var slTitle = new StackLayout
                {
                    HorizontalOptions = LayoutOptions.FillAndExpand,
                    VerticalOptions = LayoutOptions.Center,
                    Orientation = StackOrientation.Horizontal,
                    Children =
                    {
                        new Label
                        {
                            HorizontalOptions = LayoutOptions.StartAndExpand,
                            VerticalOptions = LayoutOptions.Center,
                            Text = title,
                            TextColor = Color.White
                        },
                        closeLabel
                    },

                    Padding = new Thickness(8, 5, 8, 5),
                    BackgroundColor = Color.FromHex("#D10000")
                };

                csl.Children.Add(slTitle);
            }

            csl.Children.Add(_popup);
            sl.Children.Add (csl);

            backdrop.Children.Add(clickArea, Constraint.Constant(0), Constraint.Constant(0), Constraint.RelativeToParent(p => p.Width),
                Constraint.RelativeToParent(p => p.Height));

            backdrop.Children.Add(sl,
                zero,
                zero,
                w,
                h);

            _backdrop = backdrop;

            Children.Add(backdrop,
                Constraint.Constant(0),
                Constraint.Constant(0),
                Constraint.RelativeToParent(p => p.Width),
                Constraint.RelativeToParent(p => p.Height)
            );

            UpdateChildrenLayout();

            return await _backdrop.FadeTo(1);
        }

        private async void Tap_Tapped(object sender, System.EventArgs e)
        {
            await DismissPopup();
        }

        public async Task DismissPopup()
        {

            if (_popup != null)
            {
                await Task.WhenAll(_popup.FadeTo(0), _backdrop.FadeTo(0));
                _backdrop.Children.Remove(_popup);
                Children.Remove(_backdrop);
                _popup = null;
            }

            if (_content != null)
            {
                _content.InputTransparent = false;
            }
        }
    }
}






How to use it in xaml page;


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="MyProject.SamplePopup" 
        xmlns:l="clr-namespace:MyProject;assembly=MyProject">
    <ContentPage.Content>
        <l:PopupLayout x:Name="plDefault" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
            <StackLayout x:Name="slMain" Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">

                .

                .

                .

                .

            </StackLayout>
        </l:PopupLayout>
    </ContentPage.Content>
</ContentPage>





You should set your PopupLayout from .cs too;

Appearing class;


    plDefault.Children.Remove(slMain);
    plDefault.Children.Add(slMain, Constraint.Constant(0), Constraint.Constant(0), Constraint.RelativeToParent(p => p.Width), Constraint.RelativeToParent(p => p.Height));




override OnSizeAllocated class for issues;



        protected override void OnSizeAllocated(double width, double height)
        {
            base.OnSizeAllocated(width, height); //must be called    

            slMain.WidthRequest = width;
            slMain.HeightRequest = height;

        }




How to open/close it;


   var popupMainStack = new StackLayout
   {
      VerticalOptions = LayoutOptions.FillAndExpand,
      HorizontalOptions = LayoutOptions.FillAndExpand,
      BackgroundColor = Color.White
   };
//You can add anything you want to main stack as children.
   await Popup.ShowPopup(popupMainStack,"Popup Title");






await Popup.DismissPopup(); //Close popup




Simple ;)


(Burada bir karikatür vardı ama telif yerim diye kaldırdım. Herkese dava açıyorlarmış karikatür paylaşılıyor diye. Karikatürün doğasına hiç uymuyor bence bu tavır :-/ Çakallar çok yanlış tanıtılıyor.)





4 Kasım 2016 Cuma

Xamarin.Forms Force Page Orientation and how to use Dependency simply


In Forms Project;

Dependency;



using Xamarin.Forms;

namespace MyProject
{
    public static class MBDGeneralMethods
    {
        static IMBDGeneralMethods _instance;
        public static IMBDGeneralMethods Instance {
            get{ 
                if (_instance == null) {
                    _instance = DependencyService.Get<IMBDGeneralMethods> ();
                }

                return _instance;
            }
        }
    }
}


DependencyInterface;


   using System;
   namespace MyProject
   {
      public interface IMBDGeneralMethods
      {
         void ForceLandscape();
         void ForcePortrait();
         void SetOrientionFree();
      }
   }




How to call it from any page;

In OnAppearing or in OnSizeAllocated or anywhere you want;


  
  protected override void OnSizeAllocated(double width, double height)
  {
     base.OnSizeAllocated(width, height); //must be called
     MBDGeneralMethods.Instance.ForceLandscape();
  }




In iOS Project; 

Info.plist;




AppDelegate.cs;


    [Export("application:supportedInterfaceOrientationsForWindow:")]
    public UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, IntPtr forWindow)
    {
       return UIInterfaceOrientationMask.AllButUpsideDown;
    }



Dependency;


using System;
using System.Threading;
using Foundation;
using YH.MB.iOS;
using UIKit;
using System.Drawing;
using UIKit;
using CoreGraphics;

[assembly: Xamarin.Forms.Dependency(typeof(MBDGeneralMethods))]
namespace MyProject.iOS
{
    public class MBDGeneralMethods : IMBDGeneralMethods
    {      
        public void ForceLandscape()
        {
            UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.LandscapeRight), new NSString("orientation"));
        }

        public void ForcePortrait()
        {
            UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Portrait), new NSString("orientation"));
        }

        public void SetOrientionFree()
        {
            UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Unknown), new NSString("orientation"));
        }
    }
}



In Android Project;

Dependency;


using System;
using YH.MB.Droid;
using System.Net;
using Xamarin.Forms;
using Android.Graphics;
using Android.Content;
using System.IO;
using Android.App;
using Android;
using Android.Support.V4.Content;
using Android.Content.PM;
using Android.Support.V4.App;
using XLabs.Platform;
using Android.Views.InputMethods;
using System.Collections.Generic;
using System.Text;
using Android.Support.V4.Hardware.Fingerprint;
using Android.Hardware.Fingerprints;
using Android.Security.Keystore;
using Javax.Crypto;
using Java.Security;
using Android.Util;
using Java.Lang;

[assembly: Dependency(typeof(MBDGeneralMethods))]
namespace MyProject.Droid
{
    public class MBDGeneralMethods : IMBDGeneralMethods 
    {    
        public void ForceLandscape()
        {
            var activity = (Activity)Forms.Context;
            activity.RequestedOrientation = ScreenOrientation.Landscape;
        }

        public void ForcePortrait()
        {
            var activity = (Activity)Forms.Context;
            activity.RequestedOrientation = ScreenOrientation.Portrait;
        }

        public void SetOrientionFree()
        {
            var activity = (Activity)Forms.Context;
            activity.RequestedOrientation = ScreenOrientation.FullSensor;
        }
    }    
}


MainActivity.cs;

Add this line;
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)

like this;

    namespace MyProject.Droid{

    [Activity(Label = MBConsts.ApplicationName, Icon = "@drawable/icon",
        ScreenOrientation = Android.Content.PM.ScreenOrientation.Portrait,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : XFormsAppCompatApplicationDroid
    {

    ............



That's all.
Bye.
Kib :P

(Burada bir karikatür vardı ama telif yerim diye kaldırdım. Herkese dava açıyorlarmış karikatür paylaşılıyor diye. Karikatürün doğasına hiç uymuyor bence bu tavır :-/ Hayatın anlamını bulduktan hemen sonrası... amaan bu muymuş)