Android Code Snippet Get relative view position

Description: These two subs will get the positions of a view relative to the activity, regardless of how many parent panels it is nested in.

Version: 2

SubName: GetRelativeTop

B4X:
'Iterative sub to get the views Top relative to the activity window
Public Sub GetRelativeTop(V As JavaObject) As Int
    'I tried several methods to do this, this was the only one that worked across API's and devices
 
    'One of these should always be the last parent
    If GetType(V) = "android.view.ViewRoot" Or GetType(V) = "android.view.ViewRootImpl" Or GetType(V) = "android.widget.FrameLayout$LayoutParams" Then
        Return 0
    Else
        'If V.Top is valid for this view returns a value then add it, else skip to the next parent
        Try
            Try
                Dim VW As View = V
                Return VW.Top + GetRelativeTop(V.RunMethod("getParent",Null))
            Catch
                Return 0
            End Try
        Catch
            Try
                Return GetRelativeTop(V.RunMethod("getParent",Null))
            Catch
                Return 0
            End Try
        End Try
    End If
End Sub

SubName: GetRelativeLeft

B4X:
'Iterative sub to get the views Left relative to the activity window
Public Sub GetRelativeLeft(V As JavaObject) As Int
    'I tried several methods to do this, this was the only one that worked across API's and devices

    'One of these should always be the last parent
    If GetType(V) = "android.view.ViewRoot" Or GetType(V) = "android.view.ViewRootImpl" Or GetType(V) = "android.widget.FrameLayout$LayoutParams" Then
        Return 0
    Else
        'If V.Left is valid for this view returns a value then add it, else skip to the next parent
        Try
            Try
                Dim VW As View = V
                Return VW.Left + GetRelativeLeft(V.RunMethod("getParent",Null))
            Catch
                Return 0
            End Try
        Catch
            Try
                Return GetRelativeLeft(V.RunMethod("getParent",Null))
            Catch
                Return 0
            End Try
        End Try
    End If
End Sub

Depends On: JavaObject

Tags: View Position Relative Activity
 
Last edited:

jesustarre

Member
Licensed User
Longtime User
Hello, Thanks! those Subs helpme a lot but I have a Runtime Error:

An error has occured is sub:
java.lang.RuntimeException: Method
getParent not found in:
java.lang.Integer

Continue? (Yes/No)

After press Yes everything work good.

I'm using the Subs on this way:

B4X:
nAsphaltx = GetRelativeLeft(imgasphalt.Left)
nAsphaltY = GetRelativeTop(imgasphalt.width)


Thanks for any help

Sorry but I'm still a rookie with B4A
 

msali

Member
Licensed User
Longtime User
Description: These two subs will get the positions of a view relative to the activity, regardless of how many parent panels it is nested in.

I know this is an old thread and I should not be writing anything to it, but stevel05 just wanted to thank you for the tip. It has been days that i have been working on it and was contentiously getting stuck when a in recursive routine the view had no layout.

Thanks again and admins apologies for writing on this old thread.
 

stevel05

Expert
Licensed User
Longtime User
Don't you just hate it when you pick up an old Code snippet and it doesn't work. Well it happend to me with one of my own snippets. Now updated with a fix. It's a bit belt and braces, but hopefully a bit more future proofed. Let me know if there are problems with it.
 

Robert Valentino

Well-Known Member
Licensed User
Longtime User
I took your routine a long time ago and modified to add other types

B4X:
Public  Sub Process_Globals
           Type  TRelativeLT(Left As Int, Top As Int)
   
           Public  IsInitialized    As Boolean = False
End Sub


Private Sub GetRelative_LT(RelativeLT As TRelativeLT, V As JavaObject) As TRelativeLT
          
           Try
               '-----------------------------------------------------------------------------------------------------------------
               '  Just in case the Passed Structure has not been Initialized
               '-----------------------------------------------------------------------------------------------------------------
               If  RelativeLT.IsInitialized = False Then
                   RelativeLT.Initialize
               End If
              
               '-----------------------------------------------------------------------------------------------------------------
               '  Get the Parent to this View
               '-----------------------------------------------------------------------------------------------------------------
                 Dim parent      As Object = V.RunMethod("getParent", Null)

              
               '-----------------------------------------------------------------------------------------------------------------
               '  If Parent is Null then Done
               '-----------------------------------------------------------------------------------------------------------------
                 If  parent = Null                                                                            Then
                   Return RelativeLT
               End If

               '-----------------------------------------------------------------------------------------------------------------
               '  If Parent Type is ANY of these we are Done
               '-----------------------------------------------------------------------------------------------------------------
                 Dim parentType As String = GetType(parent)

               '-----------------------------------------------------------------------------------------------------------------
               '  It turns out that if we get the Parent of the ScrollView we can work our way right down the children              
               '-----------------------------------------------------------------------------------------------------------------
               If  parentType = "anywheresoftware.b4a.objects.ScrollViewWrapper$MyScrollView"               Then
                   V        = parent
                   parent    = V.RunMethod("getParent", Null)
                  
                   If  parent = Null Then
                       Return RelativeLT
                   End If
               End If
              
                If  parentType = "android.view.ViewRoot"                                                    Then Return RelativeLT
                If  parentType = "android.view.ViewRootImpl"                                                Then Return RelativeLT
                If  parentType = "android.widget.FrameLayout"                                               Then Return RelativeLT
                If  parentType = "android.widget.FrameLayout$LayoutParams"                                  Then Return RelativeLT
                If  parentType = "androidx.viewpager.widget.ViewPager"                                      Then Return RelativeLT
                If  parentType = "anywheresoftware.b4a.BALayout$LayoutParams"                               Then Return RelativeLT
                If  parentType = "anywheresoftware.b4a.objects.HorizontalScrollViewWrapper$MyHScrollView"   Then Return RelativeLT
                If  parentType = "anywheresoftware.b4a.objects.IME$ExtendedBALayout"                        Then Return RelativeLT
                If  parentType = "flm.b4a.scrollview2d.ScrollView2DWrapper$MyScrollView"                    Then Return RelativeLT


               '-----------------------------------------------------------------------------------------------------------------
               '  OK - ADD on this Views Left and Top variables
               '-----------------------------------------------------------------------------------------------------------------
                   Dim VW As View = V

               RelativeLT.Left = RelativeLT.Left + VW.Left
               RelativeLT.Top  = RelativeLT.Top  + VW.Top
              
#if debug
               Log("RelativeLT (l/t):" &RelativeLT.Left &" / " &RelativeLT.Top &"   View (l/t):" &VW.Left &" / " &VW.Top &"  (w/h):" &VW.Width &" / " &VW.Height)                              
#end If
               '-----------------------------------------------------------------------------------------------------------------
               '  Get the settings for our Parent
               '-----------------------------------------------------------------------------------------------------------------              
               Return GetRelative_LT(RelativeLT, parent)              
           Catch
               '-----------------------------------------------------------------------------------------------------------------
               '  I DO NOT like just catching errors
               '    But if we are here then I have missed some new type Log a then Exception msg
               '-----------------------------------------------------------------------------------------------------------------
               Log("GetRelative_LT - Error" &LastException.Message)
              
               Return RelativeLT
           End Try              
End Sub
 

Robert Valentino

Well-Known Member
Licensed User
Longtime User
LucaMs

Have you tried this with a TabStrip on the page. I was having trouble getting the right location for a field on TabStrip page.
 

Robert Valentino

Well-Known Member
Licensed User
Longtime User
I found this works

B4X:
'-----------------------------------------------------------------------------------------------------------------
'  Get this Views relative position on the screen
'-----------------------------------------------------------------------------------------------------------------
Public  Sub GetRelativeLT(V As JavaObject) As TRelativeLT
           Dim RelativeLT As TRelativeLT
           
           RelativeLT.Initialize
           
           Return GetRelative_LT(RelativeLT, V)   
End Sub


Private Sub GetRelative_LT(RelativeLT As TRelativeLT, V As JavaObject) As TRelativeLT
          
           Try
               '-----------------------------------------------------------------------------------------------------------------
               '  Just in case the Passed Structure has not been Initialized
               '-----------------------------------------------------------------------------------------------------------------
               If  RelativeLT.IsInitialized = False Then
                   RelativeLT.Initialize
               End If
              
               '-----------------------------------------------------------------------------------------------------------------
               '  Get the Parent to this View
               '-----------------------------------------------------------------------------------------------------------------
                 Dim parent      As Object = V.RunMethod("getParent", Null)

              
               '-----------------------------------------------------------------------------------------------------------------
               '  If Parent is Null then Done
               '-----------------------------------------------------------------------------------------------------------------
                 If  parent = Null                                                                            Then
                   Return RelativeLT
               End If

               '-----------------------------------------------------------------------------------------------------------------
               '  If Parent Type is ANY of these we are Done
               '-----------------------------------------------------------------------------------------------------------------
                 Dim parentType As String = GetType(parent)

               '-----------------------------------------------------------------------------------------------------------------
               '  It turns out that if we get the Parent of the ScrollView we can work our way right down the children              
               '-----------------------------------------------------------------------------------------------------------------
               If  parentType = "anywheresoftware.b4a.objects.ScrollViewWrapper$MyScrollView"               Then
                   V        = parent
                   parent    = V.RunMethod("getParent", Null)
                  
                   If  parent = Null Then
                       Return RelativeLT
                   End If
               End If

               '-----------------------------------------------------------------------------------------------------------------
               '  If it is a ViewPager - we just need to keep going  - SEEMS to handle TabStrip
               '-----------------------------------------------------------------------------------------------------------------              
               If  parentType = "androidx.viewpager.widget.ViewPager"                                      Then
                   Return GetRelative_LT(RelativeLT, parent)              
               End If
              
              
                If  parentType = "android.view.ViewRoot"                                                    Then Return RelativeLT
                If  parentType = "android.view.ViewRootImpl"                                                Then Return RelativeLT
                If  parentType = "android.widget.FrameLayout"                                               Then Return RelativeLT
                If  parentType = "android.widget.FrameLayout$LayoutParams"                                  Then Return RelativeLT
                If  parentType = "anywheresoftware.b4a.BALayout$LayoutParams"                               Then Return RelativeLT
                If  parentType = "anywheresoftware.b4a.objects.HorizontalScrollViewWrapper$MyHScrollView"   Then Return RelativeLT
                If  parentType = "anywheresoftware.b4a.objects.IME$ExtendedBALayout"                        Then Return RelativeLT
                If  parentType = "flm.b4a.scrollview2d.ScrollView2DWrapper$MyScrollView"                    Then Return RelativeLT


               '-----------------------------------------------------------------------------------------------------------------
               '  OK - ADD on this Views Left and Top variables
               '-----------------------------------------------------------------------------------------------------------------
                   Dim VW As View = V

               RelativeLT.Left = RelativeLT.Left + VW.Left
               RelativeLT.Top  = RelativeLT.Top  + VW.Top
              
#if debug
               Log("RelativeLT (l/t):" &RelativeLT.Left &" / " &RelativeLT.Top &"   View (l/t):" &VW.Left &" / " &VW.Top &"  (w/h):" &VW.Width &" / " &VW.Height)                              
#end If
               '-----------------------------------------------------------------------------------------------------------------
               '  Get the settings for our Parent
               '-----------------------------------------------------------------------------------------------------------------              
               Return GetRelative_LT(RelativeLT, parent)              
           Catch
               '-----------------------------------------------------------------------------------------------------------------
               '  I DO NOT like just catching errors
               '    But if we are here then I have missed some new type Log a then Exception msg
               '-----------------------------------------------------------------------------------------------------------------
               Log("GetRelative_LT - Error" &LastException.Message)
              
               Return RelativeLT
           End Try              
End Sub

I use it to position a popup dropdown menu selection and it seems to be working with a Tabstip on the page
 

Attachments

  • Screenshot_2019-11-06-11-16-46.png
    Screenshot_2019-11-06-11-16-46.png
    112 KB · Views: 240
  • Screenshot_2019-11-06-11-15-44.png
    Screenshot_2019-11-06-11-15-44.png
    106 KB · Views: 244
Last edited:

Robert Valentino

Well-Known Member
Licensed User
Longtime User
BUT I did find one strange problem

When my app initially starts I get this for a device list

B4X:
GetRelativeLT - Start
parentType:anywheresoftware.b4a.BALayout
parentType:anywheresoftware.b4a.BALayout
parentType:androidx.viewpager.widget.ViewPager
parentType:anywheresoftware.b4a.BALayout
parentType:anywheresoftware.b4a.BALayout
parentType:anywheresoftware.b4a.BALayout
parentType:android.widget.FrameLayout

AFTER Rotating the screen I get this

B4X:
GetRelativeLT - Start
parentType:anywheresoftware.b4a.BALayout
parentType:anywheresoftware.b4a.BALayout

If I back out to the main menu and come in again I get the full list again

B4X:
GetRelativeLT - Start
parentType:anywheresoftware.b4a.BALayout
parentType:anywheresoftware.b4a.BALayout
parentType:androidx.viewpager.widget.ViewPager
parentType:anywheresoftware.b4a.BALayout
parentType:anywheresoftware.b4a.BALayout
parentType:anywheresoftware.b4a.BALayout
parentType:android.widget.FrameLayout

NOT sure why I get only a short list after rotating the screen - will have to dig deeper. BUT does work when I get the full list.
 
Top