Android Tutorial CharSequence / CSBuilder Tutorial

Discussion in 'Tutorials & Examples' started by Erel, Feb 15, 2017.

Thread Status:
Not open for further replies.
  1. Erel

    Erel Administrator Staff Member Licensed User

    B4A v6.80 adds several new features related to the ability to format rich strings.

    [​IMG]

    CharSequence is a native interface in Android SDK. A String is one implementation of CharSequence.
    There are other implementations of CharSequence that provide more features and allow us to format the string, add images and even make parts of the text clickable.

    Starting from B4A v6.80 many methods accept CharSequence instead of String. Existing code will work properly as you can pass regular strings. However you can now also pass more interesting CharSequences.

    Note to library developers, if your library makes calls to APIs that work with CharSequences then you should change your method signatures to expect CharSequence instead of String. This will allow developers to format the text.

    There are two ways to create CharSequences: agraham's RichString library or the new CSBuilder object.

    This tutorial covers the new CSBuilder object.
    CSBuilder is similar to StringBuilder. Instead of building strings, it builds CharSequences that include style information.

    Using it is quite simple.
    Code:
    Dim cs As CSBuilder
    Label1.Text = cs.Initialize.Color(
    Colors.Red).Append("Hello World!").PopAll
    [​IMG]

    Almost all methods of CSBuilder return the object itself. This allows us to chain the method calls.
    Text is always appended with the Append method.
    There are various attributes that can be set. Setting an attribute marks the beginning of a style span.
    Calling Pop ends the last span that was added (and not ended yet).
    Calling PopAll ends all open spans. It is convenient to always call PopAll at the end to ensure that all spans are closed.

    Code:
    'example of explicitly popping an attribute:
    Label1.Text = cs.Initialize.Color(Colors.Red).Append("Hello ").Pop.Append("World!").PopAll
    [​IMG]

    Code:
    'It doesn't matter whether the methods are chained or split into several lines:
    Dim cs As CSBuilder
    cs.Initialize.Color(
    Colors.Red).Append("Hello ")
    cs.Bold.Color(
    Colors.Green).Append("Colorful ").Pop.Pop 'two pops: the first removes the green color and the second removes the bold style
    cs.Append("World!").PopAll
    Label1.Text = cs
    'can also be set as the activity title
    Activity.Title = cs
    'and Toast messages and in other places...
    ToastMessageShow(cs, True)
    [​IMG]

    Using the new Typeface.FONTAWESOME and MATERIALICONS

    Code:
    Dim cs As CSBuilder
    Label1.Text = cs.Initialize.Append(
    "Text with FontAwesome: ").Typeface(Typeface.FONTAWESOME).Append(Chr(0xF209)).PopAll
    'Using the same builder multiple times. Note that it is initialized each time.
    'Note that we vertically align the material icon character.
    cs.Initialize.Append("Text with MaterialIcons: ").Typeface(Typeface.MATERIALICONS).VerticalAlign(5dip).Append(Chr(0xE531)).PopAll
    Activity.Title = cs
    [​IMG]

    Images

    Code:
    Dim cs As CSBuilder
    cs.Initialize.Size(
    30).Typeface(Typeface.MONOSPACE)
    cs.Append(
    "B4A: ").Image(LoadBitmap(File.DirAssets, "b4a.png"), 40dip40dipFalse).Append(CRLF)
    cs.Append(
    "B4i: ").Image(LoadBitmap(File.DirAssets, "b4i.png"), 40dip40dipFalse).Append(CRLF)
    cs.Append(
    "B4J: ").Image(LoadBitmap(File.DirAssets, "b4j.png"), 40dip40dipFalse).Append(CRLF)
    cs.Append(
    "B4R: ").Image(LoadBitmap(File.DirAssets, "b4r.png"), 40dip40dipFalse).Append(CRLF)
    cs.PopAll
    Label1.Text = cs
    Activity.Title = cs
    [​IMG]

    The last parameter sets the image alignment. If it is true then the image will be aligned to the baseline, otherwise it is aligned to the bottom.

    Clickable text

    The Clickable method creates clickable text. For the event to be raised you must call cs.EnableClickEvents.
    The Append method accepts a CharSequence. In the following code the CreateClickableWord sub returns a CharSequence that is then appended to the other CharSqeuence.
    Code:
    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("1")
       
    Dim cs As CSBuilder
       cs.Initialize.Size(
    30).Append("Some ").Append(CreateClickableWord("words"))
       cs.Append(
    " are ").Append(CreateClickableWord("clickable")).Append(".").PopAll
       Label1.Text = cs
       cs.EnableClickEvents(Label1)
    End Sub

    Sub CreateClickableWord(Text As StringAs CSBuilder
       
    Dim cs As CSBuilder
       
    Return cs.Initialize.Underline.Color(0xFF00D0FF).Clickable("word", Text).Append(Text).PopAll
    End Sub

    Sub Word_Click (Tag As Object)
       
    Log($"You have clicked on word: ${Tag}"$)
    End Sub
    [​IMG]

    ListView also supports CharSequence items

    Code:
    For i = 1 To 100
       ListView1.AddSingleLine(cs.Initialize.Color(
    Rnd(0xFF000000, -1)).Alignment("ALIGN_CENTER").Append($"Item #${i}"$).PopAll)
    Next
    [​IMG]

    This allows us to highlight the search term in SearchView:

    [​IMG]

    Center aligned text

    Code:
    Msgbox(cs.Initialize.Alignment("ALIGN_CENTER").Append($"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Nam tristique metus eget sem sollicitudin, vel pulvinar nisl interdum. In sed ullamcorper lacus.
    Duis ultricies urna eget faucibus ullamcorper. Donec maximus egestas tortor, vitae suscipit est varius in
    Donec at arcu ut odio hendrerit molestie. Curabitur molestie felis enim, ac sodales sapien posuere sit amet."$
    ).PopAll, _
    cs.Initialize.Typeface(
    Typeface.FONTAWESOME).Color(0xFF01FF20).Size(40).Append(Chr(0xF17B) & " " & Chr(0xF17B) & " "Chr(0xF17B)).PopAll)
    [​IMG]
     
    Last edited: May 4, 2017
  2. Claudio Oliveira

    Claudio Oliveira Active Member Licensed User

  3. DonManfred

    DonManfred Expert Licensed User

    Awesome; Typeface is extended! :D
     
    Jeffrey Cameron and Erel like this.
  4. KZero

    KZero Active Member Licensed User

    WOW!
    will it work with any android API version ?
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    Yes.
     
  6. LucaMs

    LucaMs Expert Licensed User

    Nice & useful.

    Unfortunately, now Anywhere Software should create a graphic tool to generate a complex CSBuilder statement.
    :)
     
    Last edited: Feb 15, 2017
    victormedranop and MarcoRome like this.
  7. MarcoRome

    MarcoRome Expert Licensed User

    Wowowow... i like very very much. Great :D:D:D
    When it is released the BETA version ?
     
  8. DonManfred

    DonManfred Expert Licensed User

    1-3 Weeks as far as i know (release, not beta i guess)
     
    MarcoRome likes this.
  9. Filippo

    Filippo Expert Licensed User

    Thank you Erel!
    But you're too fast, I'm not coming with your changes. ;)
     
    MarcoRome and DonManfred like this.
  10. Jaames

    Jaames Active Member Licensed User

    Nice :) Thanks!
     
  11. Beja

    Beja Expert Licensed User

    Thank you Erel, that's great addition for RichEidt view, we owe you a lot!
     
  12. Widget

    Widget Well-Known Member Licensed User

    Erel, you're making it too easy! :rolleyes:
     
  13. Widget

    Widget Well-Known Member Licensed User

    Erel,

    Is this possible with CS? (You've got my little grey cells working overtime with CS and I'm just thinking out loud here, so a simple yes or no will do)

    1) In Delphi we could align the icon to the Left, Top, Right, Bottom of a button. Will this be possible with CS if there is one icon with multiple lines of text?

    Example. If the icon is left aligned to the button then the lines will always appear to the right of the icon. If there are several lines of text, the lines of text should always appear to the right of the icon's right edge regardless of how many lines there are, as if there were two "panels" on the button. Icon "panel" on the left and text "panel" on the right. This means the left edges of the lines will all line up, and the lowest lines if they exceed the height of the icon, will NOT wrap underneath the icon to the left edge of the button. (This makes the button look ugly because the left edge of the text does not line up.)​

    2) If #1 is not possible, it should be easy enough to write a component that draws the icon on the button's canvas and the text to the right of the button using two different positions. Can I assume DrawText() will draw the CS onto a canvas and it displays the attributes like color & typeface ok?

    3) If #2 & #3 are not possible, then I'll create a custom view from a panel and just put 2 panels on it (icon panel and text panel) and have a label for each. This may be the best solution because the text can now have its own alignment. I can then use CS to control the color and style of each panel's label.

    TIA
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    You cannot change the image alignment. The image appears in the place you add it, inside the text.

    Canvas.DrawText works with strings not CharSequences.
     
  15. corwin42

    corwin42 Expert Licensed User

    Great feature.

    Will there be a new CharSequence datatype ?

    I think most of my older libraries already support CharSequences where possible. The newer ones do not because there was no native support for CharSequence in B4A until now. I will check my libraries if they support CharSequences.

    Will RemoteViews.SetText() support CharSequences directly? Currently I use a dirty hack together with agrahams RichText library to colorize a text in a widget:

    Code:
    Public Sub SetColorLabel(pName As String, pRv As RemoteViews, pText As RichString)
        
    Dim Obj1 As Reflector
        
    Dim args(2As Object
        
    Dim types(2As String
        Obj1.Target = pRv 
    ' a RemoteViewsWrapper

        
    ' first we need the Id of the view
        args(0) = Obj1.GetProcessBA("Widget4x1")
        types(
    0) = "anywheresoftware.b4a.BA"
        args(
    1) = pName
        types(
    1) = "java.lang.String"
        args(
    0) = Obj1.RunMethod4("getIdForView", args, types) ' get the view Id
        types(0) = "java.lang.int"
        
    ' now the RichText charSequence
        args(1) = pText ' CharSequence
        types(1) = "java.lang.CharSequence" 
        
    ' now do the dirty work
        Obj1.RunMethod("checkNull"'does some internal checking and may set current
        Obj1.Target = Obj1.GetField("current"' a RemoteViews - get this after checkNull
        Obj1.RunMethod4("setTextViewText", args, types) 
    End Sub
    Hopefully this can be done easier in the future.
     
  16. Erel

    Erel Administrator Staff Member Licensed User

    CSBuilder is a wrapper for CharSequence (like RichString).

    Yes.

    The change required is trivial. You just need to change the String type to CharSequence (assuming that CharSequence is indeed supported).
     
    corwin42 likes this.
  17. tufanv

    tufanv Expert Licensed User

    PErfect update !
     
  18. tufanv

    tufanv Expert Licensed User

    Will we have this for b4i also?
     
  19. Erel

    Erel Administrator Staff Member Licensed User

    I do plan to add a similar feature to B4i and B4J. There will be some differences due to the way rich text is supported on each platform.
     
  20. Cebuvi

    Cebuvi Member Licensed User

    Is possible ScaleY or RelativeSize?

    Thanks
     
Thread Status:
Not open for further replies.
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