iOS Tutorial Custom Dialogs with iCustomDialog library

Discussion in 'iOS Tutorials' started by Erel, Sep 4, 2017.

  1. Erel

    Erel Administrator Staff Member Licensed User

    B4i v4.30 includes a new library named iCustomDialog. It is based on SCLAlertView open source project (https://github.com/dogo/SCLAlertView).

    It makes it simple to create custom dialogs. It is quite similar to B4A CustomLayoutDialog from the Dialogs library (https://www.b4x.com/android/forum/t...stom-dialogs-and-async-methods.80204/#content).

    [​IMG]

    The steps to create a custom dialog are:

    1. Create and initialize a new panel.
    2. Set its size.
    3. Load a layout file with the dialog layout.
    4. Initialize a CustomDialog object.
    5. Change the dialog style if you like.
    6. Show it with ShowAsync.
    7. Wait for the Diaog_Result event.

    Example:
    Code:
    'create the panel.
    Dim p As Panel
    p.Initialize(
    "")
    'set its size
    p.SetLayoutAnimated(0100, Page1.RootPanel.Width - 50dip300dip)
    'load the layout
    p.LoadLayout("DetailsDialog")
    'initialize the dialog
    DetailsDialog.Initialize(p)
    'show it
    Dim sf As Object = DetailsDialog.ShowAsync("Enter Details""OK""CANCEL"""False)
    'wait for the result
    Wait For (sf) Dialog_Result (Result As Int)
    If Result = DetailsDialog.RESULT_POSITIVE Then
       Page1.Title = 
    "Welcome " & txtFirstName.Text
    End If
    You can see the various styles here: https://github.com/dogo/SCLAlertView
    STYLE_WAITING shows an animated waiting indicator.

    The attached example is a bit more complicated. It disables the OK button until both text fields are not empty.
     

    Attached Files:

  2. Erel

    Erel Administrator Staff Member Licensed User

    Second example with a dialog that closes automatically after 10 seconds:

    [​IMG]

    Relevant code:
    Code:
    Sub btnDetails_Click
       
    Dim p As Panel
       p.Initialize(
    "")
       p.SetLayoutAnimated(
    0100, Page1.RootPanel.Width - 50dip100dip)
       p.LoadLayout(
    "TimedDialog")
       
    Dim TimedDialog As CustomLayoutDialog
       TimedDialog.Initialize(p)
       TimedDialog.Style = TimedDialog.STYLE_WAITING
       lblMessage.Text = 
    "Do you want to do something?"
       
    Dim sf As Object = TimedDialog.ShowAsync("""OK""CANCEL"""False)
       
    Dim disable() As Boolean = Array As Boolean(False)
       AutoClose(TimedDialog, lblSeconds, disable)
       
    Wait For (sf) Dialog_Result (Result As Int)
       disable(
    0) = True 'disable the AutoClose timer
       If Result = TimedDialog.RESULT_POSITIVE Then
         
    Log("Yes")
       
    End If
    End Sub

    Sub AutoClose (TimedDialog As CustomLayoutDialog, UpdateLabel As Label, Disable() As Boolean)
       UpdateLabel.Text = 
    9 '9 seconds
       Do While UpdateLabel.Text > 0
         Sleep(
    1000)
         
    'the timer was disabled
         If Disable(0) = True Then Return
         UpdateLabel.Text = 
    NumberFormat(UpdateLabel.Text - 100)
       
    Loop
       TimedDialog.CloseDialog(TimedDialog.RESULT_CANCEL)
    End Sub
    It is explained in the B4A tutorial: https://www.b4x.com/android/forum/t...-dialogs-and-async-methods.80204/#post-507930
     

    Attached Files:

    Last edited: Sep 4, 2017
  3. nwhitfield

    nwhitfield Active Member Licensed User

    This looks great, but I'm trying to use it to pop up a panel for composing a new message, which has the OK and Cancel buttons, and a textview.

    Once you tap in the textview to enable the keyboard, there's no way to hide it again, and consequently I can't complete the dialog.
     
  4. Erel

    Erel Administrator Staff Member Licensed User

    Clicking on 'enter' button should hide it. Another option is to set the event name of the panel to pnlDialog and add this code:
    Code:
    Sub pnlDialog_Click
       
    Dim p As Panel = Sender
       
    For Each v As View In p.GetAllViewsRecursive
         
    If v Is TextField Then
           
    Dim tf As TextField = v
           tf.ResignFocus
         
    End If
       
    Next
    End Sub
     
  5. nwhitfield

    nwhitfield Active Member Licensed User

    Hmmm. Well, the Return/Enter option does remove the keyboard for a textfield, but not for a TextView, which is more suitable to sending a message. Which is a bit irksome.

    And sadly the panel click event doesn't seem be be being propagated - I've put
    Code:
    Log("Panel click")
    in my sub, and it's never triggered.
    For now, I'll just use a TextView; there'll be another way for people to send really long messages elsewhere anyway.
     
  6. Erel

    Erel Administrator Staff Member Licensed User

    Have you set the event name to pnlDialog:
    Code:
    p.Initialize("pnlDialog")
    It will only be raised outside of the TextView.
    You also need to modify the code I posted and change TextField with TextView.
     
  7. nwhitfield

    nwhitfield Active Member Licensed User

    Yes, it was named correctly. Problem solved however - and this may be useful for others:

    The TextView was the only item on my panel, and in the designer I anchored it to all sides, so it filled the panel.

    Of course, while the dialog looks as if it has space above the panel - where the title is - that's not the panel. So you need to have a bit of space at the top of the panel, before the TextView, where the user can tap, to hide the keyboard. (Or, if at some stage, there was an option to trigger an event on tapping in the dialog, but not on a field or button, that would fix it. So too, of course, would "Don't use TextViews in dialogs")
     
  8. Misterbates

    Misterbates Active Member Licensed User

    @nwhitfield The following code implements three things that may be useful to you:
    1) Using a panel to enclose a TextField or TextView then handling a click on the panel to ResignFocus from the active TextField/View, closing the keyboard.
    2) Adding a "close keyboard" icon to the top of the keyboard (as a keyboard accessory) that when clicked, calls ResignFocus on the active TextField/View.
    3) Changing the position of the CustomDialog on the display, so that the keyboard doesn't pop-up and cover the CustomDialog TextField/View.

    Code:
    private Sub MoveCustomDialog(cd As CustomLayoutDialog, Top As Int)
        
    Dim no As NativeObject = cd
        
    Dim v As View = no.GetField("alertView").GetField("view")
        
    Do While v.Top = 0
            Sleep(
    5)
        
    Loop
        v.Top = Top
    End Sub

    private Sub AddCloseKeyboardView(no As NativeObject)
        
    Private const miKEYBOARD_CLOSE As String = Chr(0xE31A)
        
    Dim l As Label
        l.Initialize(
    "lblHideKeyboard")
        l.Font = 
    Font.CreateMaterialIcons(30)
        l.Text = miKEYBOARD_CLOSE
        l.TextColor = 
    Colors.White
        l.TextAlignment = l.ALIGNMENT_RIGHT
        l.Height = 
    50dip
        l.Width = 
    50dip
        l.Color = 
    Colors.Transparent
        l.Tag = no
        no.SetField(
    "inputAccessoryView", l)
    End Sub
    private Sub lblHideKeyboard_Click
        
    Dim l As Label = Sender
        
    Dim v As Object = l.Tag
        
    If v Is TextField Then
            
    Dim tf As TextField = v
            
    If tf.IsFocused Then tf.ResignFocus
        
    Else If v Is TextView Then
            
    Dim tv As TextView = v
            
    If tv.IsFocused Then tv.ResignFocus
        
    End If
    End Sub
    private Sub pnlDialog_Click
        
    Log("pnlDialog_Click")
        
    Dim p As Panel = Sender
        
    For Each v As View In p.GetAllViewsRecursive
            
    If v Is TextField Then
                
    Dim tf As TextField = v
                
    If tf.IsFocused Then tf.ResignFocus
            
    Else If v Is TextView Then
                
    Dim tv As TextView = v
                
    If tf.IsFocused Then tf.ResignFocus
            
    End If
        
    Next
    End Sub
    The CustomDialog is built per the following example (so that the pnlDialog_Click event is fired):
    Code:
    'Enables the user to change the value of a TextItem. Updates the item with the vew Value and returns TRUE if the Value was changed
    public Sub ChangeTextItem(Item As PropertyEditorItem, Width As Int) As ResumableSub
        
    Dim Changed As Boolean ' Return TRUE if selection changed, FALSE otherwise
        'Setup custom panel
        Dim PanelWidth As Int = Width - 16dip
        
    Dim PanelHeight As Int = DipToCurrent(Min(100dipMin(100%x100%y)))
        
    Dim p As Panel
        p.Initialize(
    "pnlDialog")
        p.SetLayoutAnimated(
    200100, PanelWidth, PanelHeight)
        p.SetBorder(
    2dipColors.LightGray, 10)
        
    Dim tv As TextView
        tv.Initialize(
    "")
        tv.Font = 
    Font.CreateNew(18)
        tv.Text = Item.TextValue
        AddCloseKeyboardView(tv)
        p.AddView(tv, 
    8dip8dip, PanelWidth - 16dip, PanelHeight - 16dip)
        
    'Setup/show the dialog
        Dim d As CustomLayoutDialog
        d.Initialize(p)
        d.Style = d.STYLE_EDIT
        
    Dim sf As Object = d.ShowAsync("Edit text""Done""Cancel"""False)
        MoveCustomDialog(d, 
    100'Move the dialog to the top of the display
        Wait For (sf) Dialog_Result (dr As Int) 'Wait for then return result
        Select dr
        
    Case d.RESULT_POSITIVE
            
    Dim NewValue As String = tv.Text
            Changed = (NewValue <> Item.TextValue)
            Item.TextValue = NewValue
        
    Case Else
        
    End Select
        
    Return Changed
    End Sub
     
    Last edited: Sep 12, 2017
    skrjabin and nwhitfield like this.
  9. nwhitfield

    nwhitfield Active Member Licensed User

    That's absolutely excellent - many thanks; I shall have a play with all that now I'm back from Berlin.
     
  10. sdleidel

    sdleidel Member Licensed User

    How i can change the Color from the Waiting_Style Circle ?
     
  11. Erel

    Erel Administrator Staff Member Licensed User

    Based on the timed dialog example:
    Code:
    Dim sf As Object = TimedDialog.ShowAsync("""OK""CANCEL"""False)
    Dim no As NativeObject = sf
    Dim v As View = no.GetField("circleView")
    v.Color = 
    Colors.Red
    TimedDialog.GetButton(TimedDialog.RESULT_POSITIVE).Color = 
    Colors.Red
    TimedDialog.GetButton(TimedDialog.RESULT_CANCEL).Color = 
    Colors.Red
     
  12. fox96

    fox96 Member Licensed User

    Hi Erel,

    I'm trying the example but arrived at this line in debugging the app closes without errors.

    Code:
    DetailsDialog.Initialize(p)
    Also trying with try closes. Even B4i-Bridge closes.
    IPAD 4 iOS 8.3
    B4i 4.81
    Code:
    Try
            DetailsDialog.Initialize(p)
        
    Catch
            
    Log(LastException)
        
    End Try
     
  13. Erel

    Erel Administrator Staff Member Licensed User

    Do you have a different device with a more recent version of iOS? Can you try it?
     
  14. fox96

    fox96 Member Licensed User

    Work on iphone 6S
     
  15. Erel

    Erel Administrator Staff Member Licensed User

    It works on iPhone 4S running iOS 9. It is possible that it fails on older versions of iOS. Set the #MinVersion to 9.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice