Android Tutorial Supporting multiple screens - tips and best practices

Discussion in 'Tutorials & Examples' started by Erel, May 8, 2012.

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

    Erel Administrator Staff Member Licensed User

    This is an old tutorial. I recommend to instead watch the visual designer video tutorial: https://www.b4x.com/etp.html

    There are several features in B4A that help you target Android phones and tablets with different screen sizes and resolutions. The purpose of this page is to collect tips and best practices that will help you create flexible layouts.

    If you are not familiar with the designer script feature then please start with this tutorial: Designer Scripts Tutorial

    - 'dip' units
    It is very simple. You should always use 'dip' units when specifying the size or position of a view (control). This way the view's physical position and size will be the same on any device.
    This is correct for both regular code and designer script.
    Code:
    Button1.Width = 100 'WRONG!
    Button1.Width = 100dip 'Good job!
    Note that text size is measured in physical units. So you should not use 'dip' units with text size values.

    - Use few layout variants
    It is easy to create many variants. However it is very difficult to maintain a layout made of many variants. You should use the designer script feature and the anchoring feature to adjust your layout instead of creating many variants.

    - Understand the meaning of scale (dots per inch)
    There are many questions starting with "I have a device with 480x800 screen...". There is no meaning to these dimensions without the scale value.

    A scale of 1.0 means that there are 160 dots (pixels) per inch.
    The scale values can be one of the following values: 0.75, 1.0, 1.33, 1.5 and 2.
    Most phones today have a scale of 1.5 (160 * 1.5 = 240 dots per inch) or 2.0.
    Most tablets have a scale of 1.0.

    - "Normalized" variants
    Normalized variants are variants with a scale of 1.0.
    The layout you create with the designer is scaled (not stretched or resized) automatically. This means that the layout will look exactly the same on two phones with the same physical size. The scale doesn't matter.
    It is highly recommended to work and design your layout with normalized variants only.
    For example a variant of 480x800, scale=1.5 matches the normalized variant: 320x533, scale=1.0 (divide each value by the scale value). Now it is easy to see that this device is slightly longer than the "standard" variant: 320x480, scale=1.0.

    - Scaling strategy

    Use the anchoring feature to anchor the views to their parents.
    See this video example: Designer anchors - Video example
    And: https://www.b4x.com/android/forum/threads/64112

    Decide which views should be anchored and which views should "fill" the available space.

    You can also use the designer script to make a view fill the available space:

    This is done with SetTopAndBottom and SetLeftAndRight methods.
    Code:
    'Make an EditText fill the available height between two buttons:
    EditText1.SetTopAndBottom(Button1.Bottom, Button2.Top)

    'Make a Button fill the entire PARENT panel:
    Button1.SetLeftAndRight(0, Parent1.Width)
    Button1.SetTopAndBottom(
    0, Parent1.Height)
    Starting from v3.20 you can set the vertical or horizontal (or both) anchor to BOTH to achieve the same result.

    - How to change the views size and text size?
    Larger devices offer a lot more available space. The result is that even if the physical size of a view is the same, it just "feel" smaller.
    Some developers use %x and %y to specify the views size. However the result is far from being perfect. The layout will just be stretched.
    The solution is to combine the "dock and fill" strategy with a smart algorithm that increases the views size and text size based on the running device physical size.

    Basic4android v2.20 introduces three new keywords that help with scaling the views size and text size:
    AutoScale - Scales the specified view. The scale size, position and text size will be scaled based on the device physical size compared to the chosen variant size.
    Example:
    Code:
    AutoScale(Button1)
    AutoScaleAll - Scales all layout views.
    AutoScaleRate - Sets the scale rate. This is a number between 0 to 1. The default value is 0.3.
    A value of 0 means no scaling at all.
    Value of 1 means that the scale factor is exactly proportional to the device physical size. The result is a "stretched" UI.

    The recommended process is to first scale all views and then adjust their positions as required.

    If done properly this saves the need to create many variants. Your layout will look good on all devices.

    Test your layout

    You can test your layout with a real device, an emulator, the abstract designer and the UI Cloud service (Tools - Send to UI Cloud).
     
    Last edited: Jul 26, 2018
    Jehoschua and pesquera like this.
  2. MiniDemonic

    MiniDemonic Member Licensed User

    A question:

    Is it wrong to only use %y and %x instead of using dip?

    For all of my applications, which aren't designed to run on tablets because I do not own one, I only use %x and %y when designing the layout, I create a new function that got all of the layout code and then call that in activity_create.

    Once again, none of my apps are designed for tablets, because trying to do that without a tablet would be too much work.
     
    polo likes this.
  3. Erel

    Erel Administrator Staff Member Licensed User

    It is not wrong to only use %x and %y. It is just easier to use the "scaling factor" suggested above in order to target both phones and tablets.
     
  4. moster67

    moster67 Expert Licensed User

    Erel,

    I find the designer-scripts marvellous. The only thing I do is to create a slightly different layout for landscape-layouts with larger devices. I am really a noob what regards scaling and so on but so far thanks to Designer-scripts I am very pleased.

    In this regard: you wrote the following when using larger layouts:

    I have been using the following way instead which you wrote somewhere here in the forum (although I don't find where now). Maybe it is more specific for font-size?:

    Code:
    fontAdjust = ((100%x + 100%y) / (320dip + 480dip) - 1) * 3
    lblMovies.TextSize=lblMovies.TextSize + fontadjust
    Is there any particular difference?

    Finally you wrote:

    Code:
    Button2.SetLeftAndRight(100%x - Button2.Width * scale, 100%x)
    How would I use the formula for instance at the left or somewhere in the middle like this:

    Code:
    lblShortDesc.SetLeftAndRight(0%x20%x)

    'or

    myspinner.SetLeftAndRight(
    20%x,40%x)
    Thanks!
     
    Wappi likes this.
  5. Erel

    Erel Administrator Staff Member Licensed User

    This was my first attempt of properly calculating a "good" scale factor. The one described in the tutorial is better as it correctly treats the current dimension size.


    It depends on what you are trying to achieve. If you have 5 elements that should fit one after another then you should use percentage without applying the scale factor.
     
    M_albrefcani likes this.
  6. corwin42

    corwin42 Expert Licensed User

    I use this method for scaling my views and it works great for Activity.LoadLayout().

    The problem is that I have a few panels where I use Panel.LoadLayout(). Here %x and %y are not the device dimensions but the panel dimensions so the delta is not calculated correctly. Is there any chance to fix this?

    Perhaps some special characters like 100%dx and 100%dy can be added for device dimensions?

    Another great addition would be the ability to access process global variables from within designer scripts. So it would be possible to calculate the scale factor and store it in a global variable and all scripts could access it without making the calculation every time.
     
    metrick likes this.
  7. Erel

    Erel Administrator Staff Member Licensed User

    Currently when working with panels you should change 320dip and 480dip with the target panel width and height.
    For example if the panel dimensions are: 100x200:
    Code:
    delta = ((100%x + 100%y) / (100dip + 200dip) - 1)
     
    M_albrefcani likes this.
  8. corwin42

    corwin42 Expert Licensed User

    The problem is that in my program the panel size is variable and so I have to adjust it from outside the script. I think there is currently no perfect solution for this.

    Gesendet von meinem LG-P500 mit Tapatalk 2
     
    M_albrefcani likes this.
  9. Dominex

    Dominex Active Member Licensed User

    With this function you can get the scale of the display. For now, it worked fine with all devices that I've got to try.
    Code:
    Sub Activity_Create(FirstTime As Boolean)
       
    Msgbox(DisplayScala,"")
    End Sub

    Sub DisplayScala As Float
       
    Dim c As Canvas
       c.Initialize(
    Activity)
       
    Return Round((c.MeasureStringHeight("X,_"Typeface.SANS_SERIF, 10)/10+0.15)/0.25)*0.25
    End Sub
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    This code is not related. You will not be able to use it with the designer scripts.
     
  11. Dominex

    Dominex Active Member Licensed User

    Is true, and frankly I wonder why did not I think of it before because there is an easier way to get the scale of a display.
    Code:
    Sub Scala As Float
       
    Return 100dip/100
    End Sub
    Used in the designer so I think.

    Code:
    label1.TextSize = label1.TextSize * (100dip/100)
    ;)
     
  12. Erel

    Erel Administrator Staff Member Licensed User

    Code:
    100dip/100 = 1dip
    It is wrong to scale the TextSize based on the device scale. I recommend readers to follow the tips in my first post.
     
  13. jaminben

    jaminben Member Licensed User

    Hi,

    I've been reading this tutorial to try and work out the best way to set some text labels to the far right of any screen no matter what size the screen is and come up with the below:

    Code:
    Sub setLabelTextRight(TextString As String, TextType As Typeface, TextSize As Int, RightMargin As Int)

       
    Dim Canvas As Canvas
       
    Dim Result As Int
                
       
    Canvas.Initialize(Activity)
       Result = ((
    Activity.Width - RightMargin) - Canvas.MeasureStringWidth(TextString, TextType, TextSize))

       
    Return Result

    End Sub
    And then used like this:

    Code:
    lbl_SomeText.Left = setLabelTextRight(lbl_SomeText, Typeface.DEFAULT, 1410)
    This seems to work ok but I'm wondering how I can apply the dip to the end result?

    Any ideas? or am I going about it in the wrong manner?

    Thanks
     
    Last edited: Jun 17, 2012
  14. Erel

    Erel Administrator Staff Member Licensed User

    Why not use the following designer script:
    Code:
    lbl_SomeText.Right = 100%y
    Set the label's horizontal alignment to RIGHT.
     
  15. jaminben

    jaminben Member Licensed User

    I need to set it at after something else has occured... so it starts on the left then it gets moved to the right once its completed its task. So the designer script wont work for me will it?

    If the designer script wont work can I point you back to the original question of how to assign dip to the end result of the below code?

    Thanks

    Ben
     
  16. JonPM

    JonPM Well-Known Member Licensed User

    You can use Activity.RerunDesignerScript in your code as needed.
     
  17. jaminben

    jaminben Member Licensed User

    Ah, thats pretty cool.... but it would set it back to its starting position (left) which is the default designerscript layout. I guess I could set my starting position in the main code then Rerun.RerunDesignerScript to set it right but that kinda seems backwards.

    I'd still like to know if theirs a way to set dip to the result from my above code... if its possible or if dip is required.

    Thanks

    Ben
     
  18. JonPM

    JonPM Well-Known Member Licensed User

    Posted THIS just for you, hope its what you need :)
     
  19. jaminben

    jaminben Member Licensed User

    Sweet, I'll take a look

    Thanks
     
  20. salmander

    salmander Active Member Licensed User

    Hi erel how can I resize the font size based on text length so that it all fits in views width. help please.
     
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