Android Tutorial Custom View with Designer Support

Discussion in 'Tutorials & Examples' started by Erel, May 6, 2013.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Starting from v2.70, the visual designer supports custom views.

    Note that the WYSIWYG designer (which runs on a real device / emulator) shows a place-holder instead of the custom view.

    Adding the custom views with the designer is simpler and allows the developer to build and maintain the complete UI with the visual designer and designer script.

    Custom views with designer support can be implemented as a class or inside a library.

    Using custom views

    1. Add the class or library to your project.
    2. In the designer add a CustomView:

    [​IMG]

    3. Set the custom type property:

    [​IMG]

    4. You can now set the view properties and also treat it like any other view in the designer script.

    5. Add the required declarations and events:

    [​IMG]

    Note that the view's runtime appearance depends on the implementation. It might ignore some of the properties.

    Implementing a custom view with designer support

    There are two ways to implement a custom view. It can be implemented as a class (which can also be compiled to a library) or it can be implemented in Java. A tutorial about Java implementation will be available in the "libraries developers forum".

    The following two subs are required in order to be supported by the designer:
    Code:
    Sub Initialize (TargetModule As Object, EventName As String)

    Sub DesignerCreateView(Base As Panel, Lbl As Label, Props As Map)
    When a layout file is loaded the Initialize method will be called followed by a call to DesignerCreateView.

    Initialize sub parameters:

    TargetModule - references the module that loads the layout file.
    EventName - the events name property.

    These two parameters allow you to later raise events like all standard views.

    DesignerCreateView parameters:

    Base - a panel that will be the parent for your custom view. The panel background and layout will be based on the values from the designer. Note that you are free to do whatever you need with this panel.

    Lbl - the purpose of the label is to hold all the text related properties. The label will not appear (unless you explicitly add it).

    Props - a Map with additional entries. Currently the only entry is an "activity" key that holds a reference to the parent Activity object.

    The following example creates a button that supports double click and single click events. Note that this example is a bit simplistic.
    Code:
    'Events declaration
    #Event: DoubleClick
    #Event: SingleClick
    'Class module
    Sub Class_Globals
       
    Private mTarget As Object
       
    Private mEventName As String
       
    Private btn As Button
       
    Private topPanel As Panel
       
    Private downTime As Long
       
    Private timer1 As Timer
    End Sub

    Public Sub Initialize (TargetModule As Object, EventName As String)
       mTarget = TargetModule
       mEventName = EventName
       timer1.Initialize(
    "timer1"300)
    End Sub


    Public Sub DesignerCreateView(Base As Panel, Lbl As Label, Props As Map)
       btn.Initialize(
    "")
       
    'create a button and add it to the Base panel.
       Base.AddView(btn, 00, Base.Width, Base.Height)
       btn.TextSize = Lbl.TextSize
       btn.TextColor = Lbl.TextColor
       btn.Gravity = Lbl.Gravity
       btn.Text = Lbl.Text
       btn.Typeface = Lbl.Typeface
       topPanel.Initialize(
    "topPanel")
       
    'Add a transparent panel over the button.
       'the panel will handle the touch event.
       Base.AddView(topPanel, 00, Base.Width, Base.Height)
    End Sub

    Private Sub topPanel_Touch (Action As Int, X As Float, Y As Float)
       
    If Action = topPanel.ACTION_DOWN Then
          
    If downTime + timer1.Interval > DateTime.Now Then
             timer1.Enabled = 
    False
             
    'raise the DoubleClick event
             CallSub(mTarget, mEventName & "_" & "DoubleClick")
          
    Else
             downTime = 
    DateTime.Now
             timer1.Enabled = 
    True
          
    End If
       
    End If
    End Sub

    Private Sub Timer1_Tick
       timer1.Enabled = 
    False
       
    'raise the event
       CallSub(mTarget, mEventName & "_" & "SingleClick")
    End Sub
     
  2. laviniut

    laviniut Active Member Licensed User

    I must create for my PhD an application for blind users. so i created an interface with buttons as customview. the blind user put a finger on screen and with TTS i can speak what button is. when he get wanted button he can doubleclick on it to start proper activity. till now all is fine.
    but if the blind user is moving the finger on the screen without lifting the finger, when he get another customview button the method singleclick is not fired to use TTS, only if the finger is lift and put again on the screen.
    can you create another method for customview like touch for a button (in addition to singleclick and doubleclick) ?
     
  3. stevel05

    stevel05 Expert Licensed User

    @laviniut
    This question is in the wrong forum, I have replied here.
     
  4. juanomoran

    juanomoran Member Licensed User

    Question about customView and existing TableView class

    First of all, congratulations for this excelent product! It only took me 1 week to decide about buying a license. :sign0098:
    Now, I have a question. I want to use the Designer's support for custom views and don't really get what should I do to "register" the "tableView" class (here).

    If I got it right, I just need to add the DesignerCreateView method, since the class already has an Initialize method with a reference to the parent object. Once I create the DesignerCreateView method (only leaving the reference to the Base panel), I can select Table as a custom type in the customView properties' page in the designer.

    However, when I run the application it stops on the setHeaders sub within the class. It keeps saying that the Header panel should be first initialized.

    Any clues on that?

    Thank you very much.

    Juan
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    It is not possible to make the Table class a "custom view" without breaking existing code. Currently custom views miss a feature which is support for custom fields. I believe that this feature will be added in the next version. For the Table view I think that it is better to wait for that feature and only then modify it to be a custom view.
     
    icefairy333 likes this.
  6. derez

    derez Expert Licensed User

    Props

    I made my Vseekbar a cusom view, but how do I add the Max Value to the props map ? I had to cheat and put it as lbl.text and then use it...
    The "Currently" means it is not included or it is in the example ?

    Edit: I have found the answer here http://www.basic4ppc.com/forum/libr...designer-support-java-library.html#post168144
     
    Last edited: Jun 3, 2013
  7. juanomoran

    juanomoran Member Licensed User

    Thank you Erel. The problem is how to handle different screen configurations and rotation with a tableView. However, I think that falls a little off-topic here. I will open the question in another thread. Thank you.
     
  8. corwin42

    corwin42 Well-Known Member Licensed User

    Is it possible to call Base.LoadLayout("xxx") in DesignerCreateView sub?

    I have a simple layout with a seekbar and a label I want to load. If I try to load the layout in DesignerCreateView I get a Classcastexception

     
  9. stevel05

    stevel05 Expert Licensed User

    I had a similar problem, I don't think you can do it directly in the DesignerCreateView sub, presumably because when that is running, a layout is still being loaded so you would be nesting loadlayouts and all the required layout details may not have yet been calculated .

    I put it in a separate sub and used callsubdelayed from within DesignerCreateView.
     
    Last edited: Jun 4, 2013
  10. Erel

    Erel Administrator Staff Member Licensed User

  11. klaus

    klaus Expert Licensed User

    Hi Erel,
    Could you please add in the Props - Map also the Parent view of a CustomView.
    Props.Get("activity") returns the Activity.
    When a CustomView is on a Panel I would like to get the Panel object with something like Props.Get("parent")

    Best regards.
     
  12. Erel

    Erel Administrator Staff Member Licensed User

    For now you can use this code:
    Code:
    Dim parent As Panel 'will work with both activities and panels.
    Dim r As Reflector
    r.Target = base
    parent = r.RunMethod(
    "getParent")
     
    laviniut likes this.
  13. klaus

    klaus Expert Licensed User

    Thank you Erel.
    That's exactly what I am already doing.

    Best regards.
     
  14. kiki78

    kiki78 Active Member Licensed User

    Hi Erel,

    Is there a way to show and adjust properties of my CustomView in designer ?

    Best Regards,
     
  15. Erel

    Erel Administrator Staff Member Licensed User

    The user can change the standard properties and the text properties. You should then get these properties from the Panel and Label passed to the DesignerCreateView sub.
     
  16. kiki78

    kiki78 Active Member Licensed User

    So, for now custom properties must be set in code.
    Do you think you can in the future add something, for example #something marker, on property to expose it in designer ?

    Best Regards,
     
  17. Erel

    Erel Administrator Staff Member Licensed User

    I believe that it will be added in the future.

    For custom properties you can now use the Tag property (for example with a comma separated values).
     
  18. kiki78

    kiki78 Active Member Licensed User

    Ok Erel,
    Thank you for your support.

    Regards,
     
  19. andrewj

    andrewj Active Member Licensed User

    Hi,
    I have used this example to create my custom view class, but two things don't work as expected:
    1. I don't seem to be able to add the view from code and add it straight to the parent view in the activity (the Designer approach isn't appropriate for my project). I want to be able to write code like:
    Code:
    MyCustomView.Initialize("Main""TabStrip")
    pnlMain.AddView(MyCustomView.SlidingTabStripPanel, 
    00100%x40dip)
    That doesn't work because B4A doesn't recognise my class as a subtype of View. Instead I have to expose the base view from the class and use that instead.

    2. B4A doesn't recognise my event signatures with the standard "sub<space><tab>" approach. I have to hand code them in the activity module.

    Any ideas?
    Thanks
    Andrew
     
  20. Erel

    Erel Administrator Staff Member Licensed User

    Note that if you don't intend to add the view with the designer then there is no need to use this feature. The only reason for adding the DesignerCreateView method is to make it compatible with the designer.

    1. This is how it works. Another option is to create an "AddToPanel" sub in your class and then add the views to the panel from your class code. You can also pass an Activity instead of a Panel.

    2. The events will only be recognized if you compile your class into a library (which is a very simple step) and reference the library.
     
Loading...