Android Example Add border to Views and change Checkbox graphic

stevel05

Expert
Licensed User
Here are a couple of routines that may come in handy.

The first adds a background to a view which can have a fill color, rounded corners and a border color. This is useful for picking out views against a background where they may otherwise not be too visible.

If you want a decorative border then it would be better to use a dedicated graphic, but this will have some uses. And you haven't got to find a graphic.


B4X:
'Add a border to a view. Adds Fillcolor, StrokeColor(Border color), rx,ry (rounded corners) SWidth(Border width)
'and padding which is only applied to Labels
Sub SetBorderDrawable (V As View, FillColor As Int, StrokeColor As Int, rx As Float, ry As Float, SWidth As Float, Padding As Int)

    Dim BM As Bitmap
    Dim BMD As BitmapDrawable
    Dim Cnv As Canvas
    'We need to draw on the bitmap with a canvas
    BM.InitializeMutable(V.Width,V.Height)
    Cnv.Initialize2(BM)
    'Sizing Variables need to be floats to enable the constructor to be found.
    Dim l,t,r,b As Float
    l = 0
    t = 0
    r = V.Width
    b = V.Height
    'Needs a RectF (Float) object not just a Rect
    Dim rect1 As JavaObject
    rect1.InitializeNewInstance("android.graphics.RectF",Array As Object(l,t,r,b))
    'Create a Paint.Style object
    Dim PS As JavaObject
    PS.InitializeStatic("android.graphics.Paint.Style")
    'Create and setup a Paint object
    Dim Paint,Paint1 As JavaObject
    Paint.InitializeNewInstance("android.graphics.Paint",Null)
    Paint.RunMethod("setStrokeWidth",Array As Object(SWidth))
    Paint.RunMethod("setColor",Array As Object(StrokeColor))
    Paint.RunMethod("setStyle",Array As Object(PS.GetField("STROKE")))
    Paint.RunMethod("setAntiAlias",Array As Object(True))

    Paint1.InitializeNewInstance("android.graphics.Paint",Null)
    Paint1.RunMethod("setColor",Array As Object(FillColor))
    Paint1.RunMethod("setAntiAlias",Array As Object(True))
    Paint1.RunMethod("setStyle",Array As Object(PS.GetField("FILL")))

    'Get the canvas object from the wrapper
    Dim CnvJO As JavaObject = Cnv
    CnvJO = CnvJO.GetField("canvas")
    'Draw the filled round rect on the bitmap using the canvas
    CnvJO.RunMethod("drawRoundRect",Array As Object(rect1,rx,ry,Paint1))
    'Draw the border round rect on the bitmap using the canvas
    CnvJO.RunMethod("drawRoundRect",Array As Object(rect1,rx,ry,Paint))
    'Cast the Bitmap to a BitmapDrawable
    BMD.Initialize(BM)
    'Add padding if needed and requested
    If Padding <> -1 AND GetType(V) = "android.widget.TextView" Then
        Dim VJO As JavaObject = V
        VJO.RunMethod("setPadding",Array As Object(Padding,Padding,Padding,Padding))
    End If
    'Add the BitmapDrawable to the view
    V.Background = BMD
End Sub
The second routine allows changing the graphic for a checkbox, on some backgrounds it's difficult to see the checkbox in default color. You can change the size and color of the tickbox.

In addition you can specify a text character and color to use as the check and if you pass "Fill", the checked state will be the box filled with the TickColor.

It would be fairly straight forward to change the routine to use a graphic instead of a character if you prefer or change the shape of the checkbox for a circle or star graphic maybe.

B4X:
'Change the size and color of a Checkbox graphic. Set the tick character and color, as well as the box size and color
'and padding (distance from the box to the edge of the graphic) and a disabled fill color
'Pass "Fill" as the TickChar to fill the box with TickColor when selected.
Sub SetCBDrawable(CB As CheckBox,BoxColor As Int,BoxWidth As Int,TickColor As Int,TickChar As String,DisabledColor As Int,Size As Int,Padding As Int)
    Dim SLD As StateListDrawable
    SLD.Initialize

    Dim BMEnabled,BMChecked,BMDisabled As Bitmap
    BMEnabled.InitializeMutable(Size,Size)
    BMChecked.InitializeMutable(Size,Size)
    BMDisabled.InitializeMutable(Size,Size)
    'Draw Enabled State
    Dim CNV As Canvas
    CNV.Initialize2(BMEnabled)
    Dim Rect1 As Rect
    Rect1.Initialize(Padding ,Padding ,Size - Padding ,Size - Padding)
    CNV.DrawRect(Rect1,BoxColor,False,BoxWidth)
    Dim Enabled,Checked,Disabled As BitmapDrawable
    Enabled.Initialize(BMEnabled)
    'Draw Selected state
    Dim CNV1 As Canvas
    CNV1.Initialize2(BMChecked)
    If TickChar = "Fill" Then
        CNV1.DrawRect(Rect1,TickColor,True,BoxWidth)
        CNV1.DrawRect(Rect1,BoxColor,False,BoxWidth)
    Else
        CNV1.DrawRect(Rect1,BoxColor,False,BoxWidth)
        'Start small and find the largest font that allows the tick to fit in the box
        Dim FontSize As Int = 6
        Do While CNV.MeasureStringHeight(TickChar,Typeface.DEFAULT,FontSize) < Size - (BoxWidth * 2) - (Padding * 2)
            FontSize = FontSize + 1
        Loop
        FontSize = FontSize - 1
        'Draw the TickChar centered in the box
        CNV1.DrawText(TickChar,Size/2,(Size + CNV.MeasureStringHeight(TickChar,Typeface.DEFAULT,FontSize))/2,Typeface.DEFAULT,FontSize,TickColor,"CENTER")
    End If
    Checked.Initialize(BMChecked)
    'Draw disabled State
    Dim CNV2 As Canvas
    CNV2.Initialize2(BMDisabled)
    CNV2.DrawRect(Rect1,DisabledColor,True,BoxWidth)
    CNV2.DrawRect(Rect1,BoxColor,False,BoxWidth)
    Disabled.Initialize(BMDisabled)

    'Add to the StateList Drawable
    SLD.AddState(SLD.State_Disabled,Disabled)
    SLD.AddState(SLD.State_Checked,Checked)
    SLD.AddState(SLD.State_Enabled,Enabled)
    SLD.AddCatchAllState(Enabled)
    'Add SLD to the Checkbox
    Dim JO As JavaObject = CB
    JO.RunMethod("setButtonDrawable",Array As Object(SLD))
End Sub
Both are used in the example app attached, which are a bit extreme but you'll get the idea.

Both require the JavaObject Library

I hope you find them useful.

Tags: Border Drawable CheckBox Image Graphic
 

Attachments

Last edited:

notedop

Member
Licensed User
Nice, would you also be able to do something similar with radiobuttons? I really do not like the standard rb and would like to customize it as much as possible,
 

stevel05

Expert
Licensed User
Sorry I didn't reply sooner, I missed your post.

Radiobutton is based on a StateListDrawable the same as Checkbox, so you can used the same code. Just change the type of CB to View or Radiobutton in the signature and you can pass a Radiobutton.

You can then change the drawing elements as you please.
 

Derek Jee

Active Member
Licensed User
Hello.. I have added your sample code to my app and have got it drawing my checkboxes well.. I am having trouble though with my checkboxes which need to be checked and disabled. It does not show the box as checked when the activity shows.. Can you advise if the current code allows you to set the checkbox to be checked and disabled..

Thank you..
 

stevel05

Expert
Licensed User
It's changing the graphic on a standard checkbox, so setting Checkbox1.Checked = True on startup (preferably after setting the graphic) should work.
 

Derek Jee

Active Member
Licensed User
Hi Steve

Thanks for responding. I can get it to check on startup if the value is false but I want some of my values to be true AND disabled.. This is what I am writing..

B4X:
SetCBDrawable(chk2,Colors.DarkGray,2Dip,Colors.Blue,Chr(10004),Colors.LightGray,60Dip,2dip)
chk2.Checked = True
chk2.Enabled = False
I have also placed the checked and disabled properties before drawing the box to no avail..

I am wondering if it is just redrawing after I set the state or am I setting the value in the wrong place? It does seem that setting it disabled is unchecking it..

Thank you,

Derek.
 

luisftv

Member
Licensed User
Thank you for those two routines steve05.

How would you go on putting a border on a check-box that uses a bitmap (png, jpg, etc.) and control it's size?

Also, how do you set the corner ratio for drawables and bitmaps using your code?


Specially for buttons using bitmaps, the corner ration and the border?

I attached here your example with the check box already using a png... but I cannot set a border unless the button becomes a drawable, and I don't want it a drawable. I want the nice png image as background.

Thanks.
 

Attachments

stevel05

Expert
Licensed User
The border is drawn on the background. If you are using an image as a background, then the border would need to be part of that image.
 

luisftv

Member
Licensed User
Thanks steve05.

I hope in the near feature B4A can add that option instead of having to draw it on the image. The disadvantage of doing it to the image is that in Android TVs, the border would be on all buttons using images, therefore, it is the same as not having the border. But, if the image is given a border only when it comes into focus, then you can tell where the cursor is location on those Android TV or phones using a D-Pad. For now, only buttons with drawables (using colors, not images) can be given a border when they come into focus... bummer... I'll figure something in the mean time.

Thanks again.
 

MaFu

Well-Known Member
Licensed User
For now, only buttons with drawables (using colors, not images) can be given a border when they come into focus...
Also with images. Use one bitmapDrawable for normal state and another for focused state.
 

luisftv

Member
Licensed User
Mafu,

Thanks for the suggestion... I'm happy to report that I had figured that one out long ago... see here.

It's just that adjusting the "Focus" image and adding a border to the image itself is not as convenient and time saving as adding it with code, just like you do with gradient images.

But, I know Erel will figure something out in the near future... he always does.
 
Top