B4A Library [B4X] [XUI] [B4XLib] HintOverlay - display hints that also highlight target views

Highlight B4XViews and display your text captions with a connecting line.

For use in B4A, B4J, B4i.
Copy b4xlib file to: \B4X Additional Libraries\B4X.

Custom styling options:
  • BackgroundAlpha (transparency of the hint screen overlay)
  • CaptionColor (base color of the caption box)
  • TextColor
  • TextSize
  • OutlineColor (includes; caption outline, connecting line and target highlight color)
  • HighlightTargetView (display or hide the target outline)
  • ClearTargetView (cuts-out the target view through the overlay tint)
  • MaxDisplayTime (maximum time in milliseconds that hints are displayed if user does not tap screen – Default value is 0 (disabled))
Version 1.20
- Added MaxDisplayTime property, which automatically moves on to the next hint when the user has not tapped the screen within the set amount of time (milliseconds).

Version 1.10
- Added ClearTargetView property, which exposes the target view through the tint when set to True (many thanks to @Blueforcer for the great idea and coding modification)
- The Show method now supports Wait For - very useful if you need to change styling properties between hints.

Version 1.00
- Release

Hints are added to a queue using Show(myB4XView, "My text"), and the hint overlay is removed after all hints in the current queue have been viewed.

Usage:
Sub Class_Globals
    Private Hints As HintOverlay
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Hints.Initialize(Root)
End Sub

Private Sub B4XPage_Resize (Width As Int, Height As Int)
    Hints.Base_Resize(Width,Height)
End Sub

Private Sub ShowHints
'Set HintOverlay style (where required)
    Hints.BackgroundAlpha=80
    Hints.CaptionColor=xui.Color_ARGB(120,0,0,0)
    Hints.TextColor=xui.Color_White
    Hints.OutlineColor=xui.Color_Red

'Call Hints.Show(myB4XView, "My text”)
    Hints.Show(Label1,"This is a label”)
    Hints.Show(Button1,"This is a button”)
End Sub
 

Attachments

  • HintOverlayExample 1.10.zip
    46.8 KB · Views: 66
  • 01.png
    01.png
    11.6 KB · Views: 158
  • 02.png
    02.png
    12.9 KB · Views: 158
  • 03.png
    03.png
    11.9 KB · Views: 147
  • 04.png
    04.png
    12.3 KB · Views: 153
  • HintOverlay.b4xlib
    7.4 KB · Views: 52
Last edited:

Blueforcer

Well-Known Member
Licensed User
Longtime User
Thank you for this lib,

I modifed your code a bit for my needs, so the target will not be darken, and pops out to the user.
i draw the darken background via canvas too and clear the area with the target rect
Maybe you can implement it as an option

1650459982681.png


you need to set the alpha of the pnlBG to 0 or remove it completely

B4X:
Private Sub DisplayInstruction As ResumableSub
    Dim Instruction As instructor_info=lstHints.Get(0)
    lblHint.Text=Instruction.Instruction
    SetHintContainerHeight
 
    cvs.ClearRect(cvs.TargetRect) 'Clear the drawings
    cvs.DrawRect(cvs.TargetRect,xui.Color_ARGB(BackgroundAlpha,0,0,0),True,0) 'dimm the background
 
    'Determine if instruction panel should be positioned above or below the target view
    Dim vTop As Int = Instruction.xView.Top
    Dim xParentView As B4XView= Instruction.xView.Parent
 
    Dim vTop2 As Int=0
    If xParentView.IsInitialized Then
        vTop2=xParentView.Top
        vTop2=vTop2-NavHeight 'affects b4i only
        vTop=vTop+vTop2
    End If
 
    If vTop2=0 Then
        Dim vHalf As Int=Instruction.xView.Height/2
        Dim bTopHalf As Boolean=vTop+vHalf<(ParentPanel.Height/2)
        pnlHintContainer.Top=IIf(bTopHalf,Instruction.xView.Top+Instruction.xView.Height+40dip,Instruction.xView.Top-pnlHintContainer.Height-40dip)
    Else 'VIEW IS INSIDE PARENT
        Dim vHalf As Int=xParentView.Top+(Instruction.xView.Top+(Instruction.xView.Height/2))
        Dim bTopHalf As Boolean=vHalf<(ParentPanel.Height/2)
        pnlHintContainer.Top=IIf(bTopHalf, xParentView.Top+Instruction.xView.Top+Instruction.xView.Height+40dip,vTop-pnlHintContainer.Height-40dip)
    End If
    pnlHintContainer.Top=pnlHintContainer.Top+NavHeight 'affects b4i only
 
    'Set the target highlighter size and postion
    If vTop2=0 Then'REGULAR VIEW
        pnlTargetHighlighter.SetLayoutAnimated(0,Instruction.xView.Left,xParentView.Top+Instruction.xView.Top,Instruction.xView.Width,Instruction.xView.Height)
    Else'VIEW IS INSIDE PARENT
        pnlTargetHighlighter.SetLayoutAnimated(0, xParentView.left+Instruction.xView.Left,xParentView.Top+Instruction.xView.Top,Instruction.xView.Width,Instruction.xView.Height)
        pnlTargetHighlighter.Top=pnlTargetHighlighter.Top+NavHeight 'affects b4i only
    End If
    pnlTargetHighlighter.Visible=HighlightTargetView


    If DisplayConnectorLine Then
        'Get the connector line start/end points
        Dim iSection As Int=GetViewQuadSection(Instruction.xView)
        Dim xFromPoint As Int=pnlHintContainer.Left+GetLineStart(iSection)
        Dim yFromPoint As Int=IIf(bTopHalf ,pnlHintContainer.Top+2dip, pnlHintContainer.Top+pnlHintContainer.Height-2dip)
        Dim xToPoint As Int=pnlTargetHighlighter.Left+(pnlTargetHighlighter.Width/2)
        Dim yToPoint As Int=IIf(bTopHalf, pnlTargetHighlighter.Top+pnlTargetHighlighter.Height-2dip, pnlTargetHighlighter.Top+2dip)
        yFromPoint=yFromPoint+NavHeight'affects b4i only
        yToPoint=yToPoint+NavHeight'affects b4i only
   
        'Draw the connector line
        If cvs.TargetView<>pnlCanvas Then cvs.Initialize(pnlCanvas)'b4i only - required after calling cvs.Release
'        cvs.ClearRect(cvs.TargetRect)
        cvs.DrawLine(xFromPoint, yFromPoint, xToPoint, yToPoint, OutlineColor, 3dip)
        cvs.Invalidate
    End If
 
    'Display correct colors
    Dim rect As B4XRect
    rect.Initialize(pnlTargetHighlighter.Left+3dip,pnlTargetHighlighter.Top+3dip,pnlTargetHighlighter.Left+pnlTargetHighlighter.Width-3dip,pnlTargetHighlighter.Top+pnlTargetHighlighter.Height-3dip)
    cvs.ClearRect(rect) 'cut out the Target

    pnlHintContainer.SetColorAndBorder(CaptionColor,3dip,OutlineColor,8dip)
    pnlTargetHighlighter.SetColorAndBorder(xui.Color_Transparent,3dip,OutlineColor,3dip)
    pnlHintContainer.BringToFront
    'Display the instruction text
    lblHint.Text=Instruction.Instruction
    lblHint.TextColor=TextColor
    pnlBG.BringToFront
    pnlTargetHighlighter.BringToFront
    pnlBG.SetVisibleAnimated(200, True)
    Return True
End Sub
 

Attachments

  • 1650459678825.png
    1650459678825.png
    60.7 KB · Views: 47
Last edited:

Segga

Member
Licensed User
Longtime User
Thank you for this lib,

I modifed your code a bit for my needs, so the target will not be darken, and pops out to the user.
i draw the darken background via canvas too and clear the area with the target rect
Maybe you can implement it as an option

View attachment 128159

you need to set the alpha of the pnlBG to 0 or remove it completely

B4X:
Private Sub DisplayInstruction As ResumableSub
    Dim Instruction As instructor_info=lstHints.Get(0)
    lblHint.Text=Instruction.Instruction
    SetHintContainerHeight
 
    cvs.ClearRect(cvs.TargetRect) 'Clear the drawings
    cvs.DrawRect(cvs.TargetRect,xui.Color_ARGB(BackgroundAlpha,0,0,0),True,0) 'dimm the background
 
    'Determine if instruction panel should be positioned above or below the target view
    Dim vTop As Int = Instruction.xView.Top
    Dim xParentView As B4XView= Instruction.xView.Parent
 
    Dim vTop2 As Int=0
    If xParentView.IsInitialized Then
        vTop2=xParentView.Top
        vTop2=vTop2-NavHeight 'affects b4i only
        vTop=vTop+vTop2
    End If
 
    If vTop2=0 Then
        Dim vHalf As Int=Instruction.xView.Height/2
        Dim bTopHalf As Boolean=vTop+vHalf<(ParentPanel.Height/2)
        pnlHintContainer.Top=IIf(bTopHalf,Instruction.xView.Top+Instruction.xView.Height+40dip,Instruction.xView.Top-pnlHintContainer.Height-40dip)
    Else 'VIEW IS INSIDE PARENT
        Dim vHalf As Int=xParentView.Top+(Instruction.xView.Top+(Instruction.xView.Height/2))
        Dim bTopHalf As Boolean=vHalf<(ParentPanel.Height/2)
        pnlHintContainer.Top=IIf(bTopHalf, xParentView.Top+Instruction.xView.Top+Instruction.xView.Height+40dip,vTop-pnlHintContainer.Height-40dip)
    End If
    pnlHintContainer.Top=pnlHintContainer.Top+NavHeight 'affects b4i only
 
    'Set the target highlighter size and postion
    If vTop2=0 Then'REGULAR VIEW
        pnlTargetHighlighter.SetLayoutAnimated(0,Instruction.xView.Left,xParentView.Top+Instruction.xView.Top,Instruction.xView.Width,Instruction.xView.Height)
    Else'VIEW IS INSIDE PARENT
        pnlTargetHighlighter.SetLayoutAnimated(0, xParentView.left+Instruction.xView.Left,xParentView.Top+Instruction.xView.Top,Instruction.xView.Width,Instruction.xView.Height)
        pnlTargetHighlighter.Top=pnlTargetHighlighter.Top+NavHeight 'affects b4i only
    End If
    pnlTargetHighlighter.Visible=HighlightTargetView


    If DisplayConnectorLine Then
        'Get the connector line start/end points
        Dim iSection As Int=GetViewQuadSection(Instruction.xView)
        Dim xFromPoint As Int=pnlHintContainer.Left+GetLineStart(iSection)
        Dim yFromPoint As Int=IIf(bTopHalf ,pnlHintContainer.Top+2dip, pnlHintContainer.Top+pnlHintContainer.Height-2dip)
        Dim xToPoint As Int=pnlTargetHighlighter.Left+(pnlTargetHighlighter.Width/2)
        Dim yToPoint As Int=IIf(bTopHalf, pnlTargetHighlighter.Top+pnlTargetHighlighter.Height-2dip, pnlTargetHighlighter.Top+2dip)
        yFromPoint=yFromPoint+NavHeight'affects b4i only
        yToPoint=yToPoint+NavHeight'affects b4i only
  
        'Draw the connector line
        If cvs.TargetView<>pnlCanvas Then cvs.Initialize(pnlCanvas)'b4i only - required after calling cvs.Release
'        cvs.ClearRect(cvs.TargetRect)
        cvs.DrawLine(xFromPoint, yFromPoint, xToPoint, yToPoint, OutlineColor, 3dip)
        cvs.Invalidate
    End If
 
    'Display correct colors
    Dim rect As B4XRect
    rect.Initialize(pnlTargetHighlighter.Left+3dip,pnlTargetHighlighter.Top+3dip,pnlTargetHighlighter.Left+pnlTargetHighlighter.Width-3dip,pnlTargetHighlighter.Top+pnlTargetHighlighter.Height-3dip)
    cvs.ClearRect(rect) 'cut out the Target

    pnlHintContainer.SetColorAndBorder(CaptionColor,3dip,OutlineColor,8dip)
    pnlTargetHighlighter.SetColorAndBorder(xui.Color_Transparent,3dip,OutlineColor,3dip)
    pnlHintContainer.BringToFront
    'Display the instruction text
    lblHint.Text=Instruction.Instruction
    lblHint.TextColor=TextColor
    pnlBG.BringToFront
    pnlTargetHighlighter.BringToFront
    pnlBG.SetVisibleAnimated(200, True)
    Return True
End Sub
Excellent idea @Blueforcer!!!
I have updated the library. The new ClearTargetView property is set to True by default:)
 

Johan Hormaza

Well-Known Member
Licensed User
In iOS does not lighten the view
Thank you for this lib,

I modifed your code a bit for my needs, so the target will not be darken, and pops out to the user.
i draw the darken background via canvas too and clear the area with the target rect
Maybe you can implement it as an option

View attachment 128159

you need to set the alpha of the pnlBG to 0 or remove it completely

B4X:
Private Sub DisplayInstruction As ResumableSub
    Dim Instruction As instructor_info=lstHints.Get(0)
    lblHint.Text=Instruction.Instruction
    SetHintContainerHeight
 
    cvs.ClearRect(cvs.TargetRect) 'Clear the drawings
    cvs.DrawRect(cvs.TargetRect,xui.Color_ARGB(BackgroundAlpha,0,0,0),True,0) 'dimm the background
 
    'Determine if instruction panel should be positioned above or below the target view
    Dim vTop As Int = Instruction.xView.Top
    Dim xParentView As B4XView= Instruction.xView.Parent
 
    Dim vTop2 As Int=0
    If xParentView.IsInitialized Then
        vTop2=xParentView.Top
        vTop2=vTop2-NavHeight 'affects b4i only
        vTop=vTop+vTop2
    End If
 
    If vTop2=0 Then
        Dim vHalf As Int=Instruction.xView.Height/2
        Dim bTopHalf As Boolean=vTop+vHalf<(ParentPanel.Height/2)
        pnlHintContainer.Top=IIf(bTopHalf,Instruction.xView.Top+Instruction.xView.Height+40dip,Instruction.xView.Top-pnlHintContainer.Height-40dip)
    Else 'VIEW IS INSIDE PARENT
        Dim vHalf As Int=xParentView.Top+(Instruction.xView.Top+(Instruction.xView.Height/2))
        Dim bTopHalf As Boolean=vHalf<(ParentPanel.Height/2)
        pnlHintContainer.Top=IIf(bTopHalf, xParentView.Top+Instruction.xView.Top+Instruction.xView.Height+40dip,vTop-pnlHintContainer.Height-40dip)
    End If
    pnlHintContainer.Top=pnlHintContainer.Top+NavHeight 'affects b4i only
 
    'Set the target highlighter size and postion
    If vTop2=0 Then'REGULAR VIEW
        pnlTargetHighlighter.SetLayoutAnimated(0,Instruction.xView.Left,xParentView.Top+Instruction.xView.Top,Instruction.xView.Width,Instruction.xView.Height)
    Else'VIEW IS INSIDE PARENT
        pnlTargetHighlighter.SetLayoutAnimated(0, xParentView.left+Instruction.xView.Left,xParentView.Top+Instruction.xView.Top,Instruction.xView.Width,Instruction.xView.Height)
        pnlTargetHighlighter.Top=pnlTargetHighlighter.Top+NavHeight 'affects b4i only
    End If
    pnlTargetHighlighter.Visible=HighlightTargetView


    If DisplayConnectorLine Then
        'Get the connector line start/end points
        Dim iSection As Int=GetViewQuadSection(Instruction.xView)
        Dim xFromPoint As Int=pnlHintContainer.Left+GetLineStart(iSection)
        Dim yFromPoint As Int=IIf(bTopHalf ,pnlHintContainer.Top+2dip, pnlHintContainer.Top+pnlHintContainer.Height-2dip)
        Dim xToPoint As Int=pnlTargetHighlighter.Left+(pnlTargetHighlighter.Width/2)
        Dim yToPoint As Int=IIf(bTopHalf, pnlTargetHighlighter.Top+pnlTargetHighlighter.Height-2dip, pnlTargetHighlighter.Top+2dip)
        yFromPoint=yFromPoint+NavHeight'affects b4i only
        yToPoint=yToPoint+NavHeight'affects b4i only
  
        'Draw the connector line
        If cvs.TargetView<>pnlCanvas Then cvs.Initialize(pnlCanvas)'b4i only - required after calling cvs.Release
'        cvs.ClearRect(cvs.TargetRect)
        cvs.DrawLine(xFromPoint, yFromPoint, xToPoint, yToPoint, OutlineColor, 3dip)
        cvs.Invalidate
    End If
 
    'Display correct colors
    Dim rect As B4XRect
    rect.Initialize(pnlTargetHighlighter.Left+3dip,pnlTargetHighlighter.Top+3dip,pnlTargetHighlighter.Left+pnlTargetHighlighter.Width-3dip,pnlTargetHighlighter.Top+pnlTargetHighlighter.Height-3dip)
    cvs.ClearRect(rect) 'cut out the Target

    pnlHintContainer.SetColorAndBorder(CaptionColor,3dip,OutlineColor,8dip)
    pnlTargetHighlighter.SetColorAndBorder(xui.Color_Transparent,3dip,OutlineColor,3dip)
    pnlHintContainer.BringToFront
    'Display the instruction text
    lblHint.Text=Instruction.Instruction
    lblHint.TextColor=TextColor
    pnlBG.BringToFront
    pnlTargetHighlighter.BringToFront
    pnlBG.SetVisibleAnimated(200, True)
    Return True
End Sub
 

tsteward

Well-Known Member
Licensed User
Longtime User
Is it possible to add a timer to auto close the hint?
 

tsteward

Well-Known Member
Licensed User
Longtime User
Also a "Completed event" maybe so I can set focus and raise keyboard ready for the user.
 

Segga

Member
Licensed User
Longtime User
Also a "Completed event" maybe so I can set focus and raise keyboard ready for the user.
You can make changes between hints to the background UI or HintOverlay style using Wait For.
Completed Event:
Hints.Show(Label1, "This is hint one.")
Wait For(Hints.Show(Label2, "This is a hint two.")) Complete (b As Boolean)
  Hints.OutlineColor=xui.Color_Red 'Change outline color before the next hint is displayed.
Wait For(Hints.Show(TextBox1, "This is a hint three.")) Complete (b As Boolean)
' Set focus on textbox after last hint is displayed.
#if b4a
   ime.ShowKeyboard(TextBox1)
#Else
    TextBox1.RequestFocus
#end if
 
Last edited:

Segga

Member
Licensed User
Longtime User
Is it possible to add a timer to auto close the hint?
...as in moving on to the next hint (or closing if its the last one) automatically if the user doesn't tap the screen within a certain amount of time?
 

tsteward

Well-Known Member
Licensed User
Longtime User
...as in moving on to the next hint (or closing if its the last one) automatically if the user doesn't tap the screen within a certain amount of time?
Yes exactly
 

Segga

Member
Licensed User
Longtime User
Yes exactly
I have updated the lib - please refer to first post.
I've added a new MaxDisplayTime property.
Set the value in milliseconds to automatically display next hint (or close the overlay if it's the last one in the queue) if the user does not tap the screen.
The default value of 0, which disables this feature.
 
Top