본문 바로가기
프로그래밍/App 개발

[Xamarin] Custom Bottom Sheet

by 엽기토기 2020. 10. 22.
반응형

Bottom Sheet이란?

💡
하단에서 밀어올릴 수 있는 뷰. Android는 Material Design에서 제공해주는 기능이다.

10/20~10/22 동안 구현하였습니다.

로직

  • PanGestureRecognizer()를 등록하여 Drag 이벤트를 정의합니다.
  • GestureStatus.Running 동안 터치한 만큼을 이전 위치에 더하여 뷰의 위치를 지정합니다.

    → 스크린 크기만큼 움직일 수 있게 지정할 수 있습니다.

  • GestureStatus.Completed 하면 터치를 해제한 위치를 저장합니다. (아래로 내리면 없어지게 하는 기능도 추가할 수 있습니다.)
  • 당연하게도, 화면이 겹칠 수 있게 해야하기 때문에 감싸는 뷰는 RelativeLayout으로 구현합니다.

주의

먼저, 삽질한 경험을 작성합니다.

📌 Xamarin Forms의 PanGestureRecognizer는 현재 Android 플랫폼에서 정상적으로 작동하지 않습니다.

↓ 해당 Xamarin.Forms git issue 입니다.

Android pan TotalX/TotalY bad when the gesture recognizer view is affected by layout change · Issue #3469 · xamarin/Xamarin.Forms
Description On Android, if the view that holds a pan gesture recognizer is affected by a layout change while the pan is running, then the TotalX and TotalY values are incorrect. iOS and UWP do not have this problem. The values are less t...
https://github.com/xamarin/Xamarin.Forms/issues/3469

Frame에 직접 PanGesture를 등록하여 사용하였을 때, e.TotalY의 크기가 터치한 지점보다 약 반 정도 작습니다.(e는 PanUpdatedEventArgs)

✔따라서 PanContainer Content View 따로 생성하여, 구현한 Bottom Sheet을 해당 뷰에 넣고, PanContainer에 PanGesture를 등록하여 사용해야 정상적으로 작동합니다.

코드

PanContainer

using System;
using CustomPickMe;
using CustomPickMeMain;
using Xamarin.Forms;

namespace PanGesture
{
	public class PanContainer : ContentView
	{
		double x, y;

		public PanContainer()
		{
			var panGesture = new PanGestureRecognizer();
			panGesture.PanUpdated += OnPanUpdated;
			GestureRecognizers.Add(panGesture);
		}

		void OnPanUpdated(object sender, PanUpdatedEventArgs e)
		{
			switch (e.StatusType)
			{
				case GestureStatus.Running:
					Console.WriteLine("**** GestureStatus.Running: ");
				  Content.TranslationY = y + e.TotalY;
					Console.WriteLine("**** Content.TranslationY: " + Content.TranslationY);
					break;

				case GestureStatus.Completed:
					Console.WriteLine("**** GestureStatus.Completed: ");
					y = Content.TranslationY;

					if (y > Height-100)
					{
						((MainPageItem)BindingContext).IsVisible = false;
					}
					break;
			}
    }
}

MainPage

using System;
using CustomPickMeMain;
using Xamarin.Forms;
using PanGesture;

namespace CustomPickMe.ViewFolder
{
    public partial class MainPage4 : ContentPage
    {
        Frame _bottomSheetFrame;
        mycollectionview _myCollectionview;
        StackLayout _bottomSheetGestureAreaStackLayout;
        StackLayout _bottomSheetInnerStackLayout;
        public MainPage4()
        {
            _myCollectionview = new mycollectionview();

            _bottomSheetGestureAreaStackLayout = new StackLayout
            {
                Children =
                {
                    new BoxView
                    {
                    Margin=10,
                    HeightRequest=6,
                    CornerRadius=4,
                    WidthRequest=100,
                    BackgroundColor=Color.Gray,
                    HorizontalOptions=LayoutOptions.Center
                    }
                }
            };
            _bottomSheetInnerStackLayout = new StackLayout
            {
                Children =
                {
                    _bottomSheetGestureAreaStackLayout, _myCollectionview.stackLayout
                }
            };

            _bottomSheetFrame = new Frame
            {
                HasShadow = true,
                CornerRadius = 20,
                Content = _bottomSheetInnerStackLayout
            };

            //_bottomSheetFrame.SetBinding(Frame.IsVisibleProperty, "IsVisible");

            BindingContext = new MainPageItem();

            RelativeLayout relativeLayout = new RelativeLayout();
            relativeLayout.BackgroundColor = Color.FromHex("#FFB822");


            relativeLayout.Children.Add(
                new PanContainer
            {
                Content = _bottomSheetFrame
            },
            Constraint.RelativeToParent((parent) =>
            {
                return parent.X;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Y * .8;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Width;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Height;
            }));
            Content = relativeLayout;
        }
    }
}

느낀 점

이번 기능을 구현하면서,

'되는데 왜 안돼!!!!!(?)'

'되는데 이유를 모르겠어!!!!!!(?)'

를 한 시간에 한 번씩 시전했다.

그래도 해결해서 너무 기분이 좋다.

역시 코딩은 재밌어 ^^

Reference

이동 제스처 인식기 추가 - Xamarin
샘플 다운로드 Download the sample 이동 제스처는 화면에서 손가락의 움직임을 감지하고 이 움직임을 콘텐츠에 적용하는 데 사용되며 PanGestureRecognizer 클래스로 구현됩니다. 이동 제스처에 대한 일반적인 시나리오는 이미지 콘텐츠가 이미지 차원보다 작게 뷰포트에 표시되는 경우 모든 이미지 콘텐츠를 볼 수 있도록 이미지를 가로 및 세로로 이동하는 것입니다. 이는 뷰포트 내의 이미지를 이동하여 수행되며 이 문서에서 설명됩니다.
https://docs.microsoft.com/ko-kr/xamarin/xamarin-forms/app-fundamentals/gestures/pan
BottomSheet in Xamarin Forms
Hello everyone, it's time to adopt to new design styles to compete the world with current trends. Such a trend in mobile community is bottom sheet. Bottom sheets are used commonly nowadays to give user a sub view with-in a main view with animation and sliding options.
https://medium.com/xamarinlife/bottomsheet-in-xamarin-forms-f99fd8b48bc4
Dashboard Drawer
Snppts - A Xamarin Forms UI snippet library
https://www.snppts.dev/snippet/dashboard-drawer

nuget

galadril/Xam.Plugin.SimpleBottomDrawer
Just a nice and simple BottomDrawer for your Xamarin Forms project, like how it is implemented on Google Maps. !!Install into your .net standard Forms project. !! This control Google Maps The content of the Bottom Drawer is completely via xaml to your preferences!!
https://github.com/galadril/Xam.Plugin.SimpleBottomDrawer
SimonePit/CoolBottomSheet
Xamarin Forms: Material Design bottom sheet xmlns:customControl="clr-namespace:CoolBottomSheet;assembly=CoolBottomSheet" ContentMainPage - Is the content view of Main page (you can use every layout) ContentBottomSheet - Is the content view of BottomSheet (you can use every layout) BackgroundBottomSheetColor - Background color of bottom sheet CornerRadiusBottomSheet - Corner radius of bottom sheet PercentageLockMainPageTranslation -
https://github.com/SimonePit/CoolBottomSheet
rlingineni/Forms-BottomSheet
A bottom sheet control for Xamarin Forms with Tutorial Dismiss GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together. Sign up Permalink Failed to load latest commit information.
https://github.com/rlingineni/Forms-BottomSheet/tree/7747b002f73595ac061b70e0a6b36b21f3a02072
enisn/Plugin.BottomSheet
Bottom Sheet implementation for Xamarin Forms Dismiss GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together. Sign up Permalink Failed to load latest commit information.
https://github.com/enisn/Plugin.BottomSheet

Material Design

Material Design
Build beautiful, usable products faster. Material Design is an adaptable system-backed by open-source code-that helps teams build high quality digital experiences.
https://material.io/components/sheets-bottom#usage

반응형