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.)





Hiç yorum yok:

Yorum Gönder