Xamarin Forms Pan Gesture to Grid row bounds?

AG 521 Reputation points
2021-07-08T18:57:52.447+00:00

Hi,

I have a Pan container inside MainPage.xaml where in it I have a Grid with two rows.
I am setting my Pan container to Grid.Row 1 but I would like that the Pan container will stop TranslationX and TranslationY when it reach the bounds of Grid.Row 1 and will not exit them.

Thanks in advanced for any help,
AG

Pan container XAML

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="PanInScrollView.PanControl">
  <ContentView.Content>
    <Frame  BorderColor="Gray" CornerRadius="3" Padding="5" WidthRequest="300" HeightRequest="300">
        <StackLayout>
            <Label Text="104 50" HorizontalOptions="Center" BackgroundColor="WhiteSmoke" FontSize="Medium" FontAttributes="Bold" />
            <BoxView Color="Gray" HeightRequest="2"  />
            <Label Text="Some text for Label" />
        </StackLayout>
    </Frame>
    </ContentView.Content>
</ContentView>

Pan container CS

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace PanInScrollView
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class PanControl : ContentView
    {
        double x, y;
        public PanGestureRecognizer PanGestureRecognizer { get; set; }

        public PanControl()
        {
            InitializeComponent();

            PanGestureRecognizer = new PanGestureRecognizer
            {
                TouchPoints = 1
            };
            PanGestureRecognizer.PanUpdated += PanGestureRecognizer_PanUpdated; 
            GestureRecognizers.Add(PanGestureRecognizer);
        }

        private void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
        {
            switch (e.StatusType)
            {
                case GestureStatus.Running:
                    TranslationX = (Device.RuntimePlatform == Device.Android ? TranslationX : 0) + e.TotalX;
                    TranslationY = (Device.RuntimePlatform == Device.Android ? TranslationY : 0) + e.TotalY;
                    break;

                case GestureStatus.Completed:
                    x = Content.TranslationX;
                    y = Content.TranslationY;
                    break;
            }
        }
    }
}

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:PanInScrollView"
             x:Class="PanInScrollView.MainPage">

    <ContentPage.ToolbarItems>
        <ToolbarItem x:Name="tbiTest1"  Text="Test1" />
        <ToolbarItem x:Name="tbiTest2"  Text="Test2" />
    </ContentPage.ToolbarItems>


    <Grid BackgroundColor="LightGray">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.RowSpacing>5</Grid.RowSpacing>

        <AbsoluteLayout Grid.Row="1">
            <local:PanControl />
        </AbsoluteLayout>

        <StackLayout  x:Name="slAreas"  Grid.Row="0" Orientation="Horizontal" Margin="0,5,0,5" BackgroundColor="White">
            <Button Text="12345" WidthRequest="200"></Button>
            <Button Text="12345" WidthRequest="200"></Button>
            <Button Text="12345" WidthRequest="200"></Button>
            <Button Text="12345" WidthRequest="200"></Button>
            <Button Text="12345" WidthRequest="200"></Button>
            <Button Text="12345" WidthRequest="200"></Button>
         </StackLayout>
    </Grid>
</ContentPage>
Developer technologies | .NET | Xamarin
0 comments No comments
{count} votes

Accepted answer
  1. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 36,436 Reputation points Microsoft External Staff
    2021-07-09T06:46:10.393+00:00

    Hello,
    Welcome to our Microsoft Q&A platform!
    You can have a try with following code in PanControl.xaml.cs , App.ScreenWidth and App.ScreenHeight are defined in APP.xaml.cs, 50 is the height of RowDefinition.

    PanControl.xaml.cs

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Threading.Tasks;  
    using Xamarin.Forms;  
    using Xamarin.Forms.Xaml;  
    namespace PanInScrollView  
    {  
        [XamlCompilation(XamlCompilationOptions.Compile)]  
        public partial class PanControl : ContentView  
        {  
            public PanGestureRecognizer PanGestureRecognizer { get; set; }  
    
            public PanControl()  
            {  
                InitializeComponent();  
    
                PanGestureRecognizer = new PanGestureRecognizer  
                {  
                    TouchPoints = 1  
                };  
                PanGestureRecognizer.PanUpdated += PanGestureRecognizer_PanUpdated;  
                GestureRecognizers.Add(PanGestureRecognizer);  
            }  
    
            private void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)  
            {  
                PanControl pan = (PanControl)sender;  
                switch (e.StatusType)  
                {  
                    case GestureStatus.Running:  
                        double a = pan.TranslationX + e.TotalX;  
                        double b = pan.TranslationY + e.TotalY;  
                        pan.TranslationX = a < 0 ? 0 : (a > (App.ScreenWidth - pan.Width) ? (App.ScreenWidth - pan.Width) : a);  
                        pan.TranslationY = b < 0 ? 0 : (b > (App.ScreenHeight - pan.Height - 50) ? (App.ScreenHeight - pan.Height - 50) : b);  
    
                        break;  
    
                    case GestureStatus.Completed:  
                        break;  
                }  
            }  
        }  
    }  
    

    MainActivity of Android

    var width = Resources.DisplayMetrics.WidthPixels;  
    var height = Resources.DisplayMetrics.HeightPixels;  
    var density = Resources.DisplayMetrics.Density;  
    App.ScreenWidth = (width - 0.5f) / density;  
    App.ScreenHeight = (height - 0.5f) / density;  
    

    APP.xaml.cs

    public static double ScreenWidth;  
    public static double ScreenHeight;  
    

    In addintion, your platform is Android( Device.RuntimePlatform == Device.Android ),you can have a try in iOS.

    AppDelegate.cs

    App.ScreenWidth = UIScreen.MainScreen.Bounds.Width;  
    App.ScreenHeight = UIScreen.MainScreen.Bounds.Height;  
    

    Best Regards,
    Wenyan Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. AG 521 Reputation points
    2021-07-09T11:24:01.217+00:00

    Hi Wenyan,

    Awesome Code!!!

    I have one more issue that PanControl is exiting the Bottom bounds of the Grid.Row 1 and it is probably of the NavigationPage Bar Height that also needs to to be reduced but I can't find how to get NavigationPage Bar Height value from Xamarin Forms page. will be much appreciated if you will able to help me with this.

    Regards,
    AG

    0 comments No comments

  2. AG 521 Reputation points
    2021-07-10T06:44:54.893+00:00

    I got StatusBar Height and NavigationBar Height at MainActivity.cs

    private int getStatusBarHeight()
            {
                Resources res = this.Resources;
                int resourceId = res.GetIdentifier("status_bar_height", "dimen", "android");
                int height = res.GetDimensionPixelSize(resourceId);
                return height;
            }
    
            private int getNavigationBarHeight()
            {
                Resources res = this.Resources;
                int resourceId = res.GetIdentifier("navigation_bar_height", "dimen", "android");
                int height = res.GetDimensionPixelSize(resourceId);
                return height;
            }
    

    Regards,
    AG

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.