How can I get absolute position of element/view in xamarin.forms

ShivaprakashAngadiShivaprakashAngadi USMember
edited September 2014 in Xamarin.Forms

I am using Xamarin Forms version 1.2.2.0.

I have a Grid with 2 rows (1st row 50pixels height) in a Page, I have a Layout Control in 2nd row of Grid.

I am working on touch gestures. I am getting X & Y of touch positions relative to MainPage(using platform specific custom renderers).

I need either touch positions relative to the Layout Control or a method to find absolute position of that Layout Control Relative to MainPage.

(Layout Control here is a Custom AbsoluteLayout Control of Xamarin.Forms)

Thanks.

Answers

  • Flame239Flame239 USMember ✭✭

    @ThomasUllrich it works, thanks

  • @ThomasUllrich said:
    I know, it's kind of late, but I found this one as I searched for a solution for my similar problem. I just looped through all parentViews, and calculated the absolute Y. Looks like this:

    var y = button.Y; var parent = button.ParentView; while (parent != null) { y += parent.Y; parent = parent.ParentView; }

    Hope this helps. :)

    Nice solution Thomas :smiley:

  • ThomasUllrichThomasUllrich DEMember ✭✭

    @alessandrosuppiej Thanks :)

    As far as ParentView is now deprecated I changed my code to the following:

    var y = button.Y; var parent = (VisualElement)button.Parent; while (parent != null && parent.Parent.GetType() == typeof(VisualElement)) { y += parent.Y; parent = (VisualElement)parent.Parent; }

    Element.Parent can be anything, like the class App. Because I know, the initial parent of my button is a VisualElement, I can cast the first time without problems. As far as I loop through the parents, I have to check for the right class type. It works for me. :)

  • alessandrosuppiejalessandrosuppiej ITMember ✭✭

    i like pragmatic solutions like yours! we're here to work and simplify our life! not for academy!. Thanks agarin @ThomasUllrich

  • DonMesserli.1843DonMesserli.1843 USMember ✭✭

    I am doing this in my MeasureInvalidated handler. It is called twice and the calculations for x and y are always 0 (zero). When is the best time to do this calculation?

  • FactoryOptimizrFactoryOptimizr USUniversity ✭✭

    @DonMesserli.1843, definitely need to do this after any layout sequence has completed. I had hoped that I could load screen coordinates for key views at the end of the main page constructor during app start-up, but no...kept getting 0 in X and Y coordinates like you. So I typically leave it until just before I need to use the information -- the coordinates are guaranteed to be accurate then.

    Here's the method I use to retrieve a view's screen coordinates. Of course, since a view's X and Y coordinates are read-only properties, changing the view's location on-screen is a matter of setting its TranslationX and TranslationY properties to the difference between the proposed "new" coordinates and the view's current screen coordinates.

    public (double X, double Y) GetScreenCoordinates(VisualElement view)
    {
        // A view's default X- and Y-coordinates are LOCAL with respect to the boundaries of its parent,
        // and NOT with respect to the screen. This method calculates the SCREEN coordinates of a view.
        // The coordinates returned refer to the top left corner of the view.
    
        // Initialize with the view's "local" coordinates with respect to its parent
        double screenCoordinateX = view.X;
        double screenCoordinateY = view.Y;
    
        // Get the view's parent (if it has one...)
        if (view.Parent.GetType() != typeof(App))
        {
            VisualElement parent = (VisualElement)view.Parent;
    
    
            // Loop through all parents
            while (parent != null)
            {
                // Add in the coordinates of the parent with respect to ITS parent
                screenCoordinateX += parent.X;
                screenCoordinateY += parent.Y;
    
                // If the parent of this parent isn't the app itself, get the parent's parent.
                if (parent.Parent.GetType() == typeof(App))
                    parent = null;
                else
                    parent = (VisualElement)parent.Parent;
            }
        }
    
        // Return the final coordinates...which are the global SCREEN coordinates of the view
        return (screenCoordinateX, screenCoordinateY);
    }
    
  • DonMesserli.1843DonMesserli.1843 USMember ✭✭

    @FactoryOptimizr

    I have the same code. My problem is that I want to show a bubble attached to a ViewElement as soon as the page is visible. I can't find any way to know when the page is done bing laid out.

  • FactoryOptimizrFactoryOptimizr USUniversity ✭✭

    @DonMesserli.1843, looks like you might be able to override the page-level "OnAppearing" event. This fires immediately before the page becomes visible, though I haven't tested to determine whether the layout manager has allocated sizes for everything on the page at that point. Another possibility might be to respond to the page's "LayoutChanged" event. If you test these options, it'd be terrific if you'd post back here about what you found.

  • DonMesserli.1843DonMesserli.1843 USMember ✭✭

    @FactoryOptimizr, I've tried both of those and the screen coordinates alway come back as 0,0.

  • DavidDancyDavidDancy AUMember ✭✭✭✭

    You can override the OnElementPropertyChanged callback and look for the relevant properties.

    There is also the SizeAllocated callback but you'll get this one multiple times and it may take a while to "settle down" to non-changing values as the layout gets calculated.

  • SlavaOsipovSlavaOsipov USMember ✭✭

    One more note about absolute position calculation.
    Code samples that suggests to accomulate X and Y coordinates of parent views does not handle TranslationX and TranslationY. TranslationX and TranslationY must be added to X and Y accomulators too if you want to have correct result.
    somethig like that:

    screenCoordinateX += parent.X + parent.TranslationX;
    screenCoordinateY += parent.Y + parent.TranslationY;

  • This technique does not work. If the page is inside a NavigationPage, it doesn't take into account the extra space from the navigation bar and stuff.

  • JobornJoborn ATMember ✭✭

    I worked out a solution.

    You need to ad this method to your code and use it in your renderer class.

    Improtand is to call it after the constructor and OnElementChanged(..). For example in the touch of your renderer.

            public static (double X, double Y) GetScreenCoordinates<TRenderer>(TRenderer renderer) where TRenderer : Android.Views.View
            {
                double screenCoordinateX = renderer.GetX();
                double screenCoordinateY = renderer.GetY();
                Android.Views.IViewParent viewParent = renderer.Parent;
                while (viewParent != null)
                {
                    if (viewParent is Android.Views.ViewGroup group)
                    {
                        screenCoordinateX += group.GetX();
                        screenCoordinateY += group.GetY();
                        viewParent = group.Parent;
                    }
                    else
                    {
                        viewParent = null;
                    }
                }
                return (screenCoordinateX, screenCoordinateY);
            }
    
  • JobornJoborn ATMember ✭✭

    Update to my last post.

    You can get the exact position, which also works with ScrollView, with:

    renderer.GetGlobalVisibleRect(globalViewRectangle);

  • MondonnoMondonno Member ✭✭
    edited August 12

    I have a problem, I set the button position in the Main.Storyboard and when I start the button simulator I have a completely different place, please help :|

Sign In or Register to comment.