Skip to content
This repository was archived by the owner on Sep 30, 2025. It is now read-only.

tremho/nativescript-dynamic-label

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nativescript-dynamic-label

Build Status NPM version Downloads TotalDownloads Twitter Follow

Features

  • Text Measurement
  • Text Fitting
  • Label control that dynamically sizes text to fit
  • Android and iOS

Installation

To get started, install the plugin, per normal methods:

tns plugin add nativescript-dynamic-label

Usage

Generally, DynamicLabel can be used in either XML markup or in code much the same way as a normal Label control.

Use via XML markup

Use pretty much the same as a regular Label.

Import the plugin into the namespace

In your page declaration, include a reference to the DynamicLabel module, like this:

<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo"
      xmlns:dl="nativescript-dynamic-label"
      class="page"

the xmlns:dl="nativescript-dynamic-label" is the part you want to add, and it sets the namespace dl as relating to the DynamicLabel module.

Then, invoke a DynamicLabel within your markup like so..

<StackLayout> <!-- or whatever layout container you are using... -->
    <dl:DynamicLabel text="Hello, World!"></dl:DynamicLabel>
</StackLayout>

You can use all the properties of <Label> for the dynamic label also. The most relevant of these being width and textWrap. Note that these properties can also be set via CSS.

Use via code

You may create and use a DynamicLabel in the same ways as a normal Label.
You may create one with new DynamicLabel() or retrieve an existing one from the page with page.getViewById('your-D-Label-ID) from there, set or get the properties you would of a normal label, e.g. dlabel.text = 'Hello, World'. Do not set a font size to the dynamic label for display, as it will find its own. The text fitting is triggered on any new text change.

Like the normal NativeScript <Label> and other Nativescript controls, text may be set via the Observable class and changes made to the bound Observable property.

Of course, you can create a DynamicLabel directly with new DynamicLabel() as well.

Using to measure text

To use this class to measure text, but not necessarily display it, you can call the getTextExtent method of the class.

Note that the label must be placed in a layout container on a page before it can be used for measurement.

To use this, pass the text, the font size, and the maximum width and height you are attempting to fit text for to getTextExtent, and it will return the bounds of the text, as well as an indication of whether or not the text will fit in this space without being truncated, and also the text per-line as determined by the internal layout algorithm.

Note that the line layout may not necessarily match what will be displayed by the actual control, since each platform handles its word wrapping and fitting in subtle but often significantly different ways.
However, it should be reasonably representative of what likely would display if set to a Label control at this font size (assuming text wrap is enabled). This information may be more useful for any do-it-yourself layout tasks than for actual representation of what the dynamic label itself control renders.

let computedWidth, computedHeight;
let maxWidth = 100; // constrain to this width
let maxHeight = 1000; // let it find the height < this
let myDLabel = page.getViewById('myDLabel');
let textSize = 20; // let's compute for this font size
let bounds = myDLabel.getTextExtent(myText, textSize, maxWidth, maxHeight);
if(bounds.wasCut) {
    console.error("Text doesn't fit in these bounds at this size!")
} else {
    computedWidth = bounds.width;
    computedHeight = bounds.height;
}
// computed width,height can now inform how big to make
// a display that can hold this text at this size.

// Additional information we get from this about the 
// text per lines (according to internal layout) can be
// retrieved like this:
for (let i = 0; i< bounds.lines.length; i++) {
    let t = bounds.lines[i].text;
    // let y = bounds.lines[i].top; // if we wanted to draw it
    console.log(t)
}

API

DynamicLabel inherits from Label and so has all of the characteristics of that class.

Properties specifically important to DynamicLabel are listed here.

Property Default Description
textWrap inherits from Label turn this on to wrap text. Changes the choices made by the text measurer / formatter.
width inherits from Label must be set (direct or CSS) for sizing to be effective
public getTextExtent(
       text : string, 
       textSize: number, 
       maxWidth : number, 
       maxHeight: number) : FitResults`

Use to measure text as it will appear in the current typeface in the given font size (textSize) constrained to the bounds (maxWidth, maxHeight). The returned FitResults object looks like this:

{  
   width: number,  // width of text extent bounds
   height: number, // height of text extent bounds
   lines: LineInfo[], // array of line info, see below
   wasCut: boolean // true if text was truncated at this size
 }

each entry in the lines property above will be an object in this format (LineInfo):

 {  
  text: string, // text that appears on this line
  top: number // y offset to start drawing text
  }
public fitText() : void

may be called explicitly to force a recompute/redisplay of text. Normally not needed, as this is called after any text or layout changes to the DynamicLabel control.

Tips and Caveats

Multiline displays

If the property textWrap is false (the default), a font size will be picked that allows all of the text to appear in one line according to the width of the control, regardless of the control height. If textWrap is true, the control is enabled for wrapping. This is done according to the algorithms of the underlying platform as has been implemented for Label.
To assist its predictions, DynamicLabel computes the word breaks and line spans itself and uses these for measurement.

A paradox of the multiline scenario is that the fitter is working to find measurements that fit first in width, and selecting a smaller font if this is not acheived, but with multiline text, the new font size may change the layout and collapse to fewer lines -- which creates a wider width rather than a smaller one, and so the tendency is to result in a smaller font choice than one might be able to manually choose.

You can avoid this if you have text that you already know is multiline, and placing hard breaks (\n) in the string to force a specific layout. You still must set 'textWrap=true' to allow this to display multiple lines, but it should honor your layout and find a size that is reasonable for your control size.

Known Issues

Still early in development!

As of 2/14/2020 this is the first version released for testing.

As issues arise, they will be recorded in this space.

Version 1.0.0
  • crash found when instantiating control in certain containers
  • sizing computed with incorrect scaling

Problems above fixed with release 1.0.1

Source code and Contributing

The source for this package is maintained on GitHub at: https://github.com/tremho/nativescript-dynamic-label

Structure of the project is based on the templates generated with the Nativescript Plugin Seed project.

Comments and contributions welcome! Please submit your Pull Requests, with as much explanation and examples you can provide to support your changes.

Feel free to email me at [email protected] to start a discussion for other suggestions.

License

Apache License Version 2.0, January 2004

About

Text Extent measurement and dynamically sized text Label variant support for NativeScript

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published