Tooltips are a good way to provide a user with additional information for controls and Flex offers Tooltips out of the box. The default Tooltips are fine but when text gets longer than just a few words usability may suffer.
For a current project, I needed more like a balloon help in place of tooltips and therefore decided not to use Flex default tooltips.
Regarding usability of the tooltips (balloon help) I want to be able to
- Display an optional tooltip title
- Display formatted tooltip text
- Display icons
- Colorize the tooltip based on the semantic of the invoking control
- Consistent Placement
- Have all title, text, styles for the tooltips stored in a central location
- Have the tooltips work in a generic and Flex-compliant way
Flex gives you a few ways to customize tooltips from registering your custom ToolTip class to intercepting Tooltip events where you can hook up the custom tooltip. All of these approaches fall either short of the requirements I had or would add additional overhead so I simply created a custom ToolTipManager that would alter the behaviour of the default ToolTipManager.
Here’s a demo of the final result, the approach is described further down.
Since I like to have all resources centralized, the approach I followed was to interpret the value of the tooltip- or the errorString property on a control not as the tooltip text to display but as a partial key to lookup title, text, styles etc. in a resource bundle. Form this partial key concrete keys would be derived to lookup the values for a controls tooltip.
<s:Button label=”OK” tooltip=”ToolTipBundle.okButton” />
would point to the ResourceBundle named ‘ToolTipBundle’ and within this to all entries of a key starting with tooltip.okButton. Then the values for title, text etc. will be looked up by the custom ToolTipManager implementation and be applied to the tooltip.
The first token in the tooltip property specifies the name of the resource bundle, the second token the partial key for looking up the entries in the resource bundle. If no second token is specified the id (if any) of the component is being used.
Entries in the resource bundle then refer to the partial key submitted and define the concrete values to use for the tooltip.
tooltip.okButton.title=Title of Tooltip tooltip.okButton.text=Text for this tooltip tooltip.okButton.styleName=CSS class to use for this tooltip tooltip.okButton.placement=bottomRight|bottomLeft|topRight|topLeft tooltip.okButton.color=Color of text tooltip.okButton.chromeColor=Color of tooltip
Color and chromeColor are there for convenience but can also be set via the CSS class specified by styleName. If any of the entries are not specified fallbacks to default values are used.
To make this work some methods of the default ToolTipManager need to be overwritten
override mx_internal function initializeTip():void
This is where the custom implementation looks up the values and assigns them to the tooltip.
Additionally there’s the
override mx_internal function positionTip():void
method to position the tooltip in a custom way.
The custom ToolTipManager implementation is registered at loading using a custom preloader class.
The custom Tooltip itself is a simple SkinnableComponent associated with a SparkSkin. There’s a required skin part for the text and a dynamic skin part for the label that only gets added if any value for a title is provided.
For both title and text a RichText component is used within the skin so that formatting the text in a rich way is possible. The associated skin is then responsible to draw the tooltip based on the provided placement. Having set this up, usage of the custom tooltips for any app is simple.
<s:Application preloader="com.hulstkamp.flex.spark.preloaders.CustomMixinPreloader"> </s:Application>
This will register the custom ToolTipManager.
For additional documentation see the source in the demo (view source is enabled).
Update: Using dynamic Text in Tooltips
First note that standard Flex tooltips can be customized and if using the Flex ToolTipManager the value in the tooltip property is interpreted as the string to display in the tooltip. You can set this string any time at runtime - based on your data.
This example of nicer Tooltips uses a custom ToolTipManager to look up title, text, styles etc. in resource bundles. For this, the value in the tooltip property is interpreted as a key to look up the text etc. in the bundles.
If you want to use the nicer Tooltips but change its behaviour regarding dynamic text, then look at assignResourcesToToolTip() of NiceToolTipManagerImpl: You could change the way of how the values are looked up and assigned to the tooltip.
For instance you could introduce further tokens for the value in the tooltip property and parse these tokens as parameters to get a parametrized text from the resource bundle
• Bundle.Key#dynamic text • parse #tokens to use as params in resource bundle lookup • var toolTipText:String = ResourceManager.getInstance().getString(bundleKey, lookupKey + “.text”, params);
For a more OOP approach you could introduce some interface like IToolTipTextOverride that has a get / set toolTipOverride():String function.
Let your components implement this interface (returning a string based on your data) and in NiceToolTipManagerImpl check to see if the currentTarget (the component the tooltip should be shown on) is of type IToolTipTextOverride.
If true get the text from the toolTipOverride property of the currentTarget instead of looking it up from the resource bundle and assign this text to the tooltip text.
updated: I did a quick project showing this approach. Download the project here. Look at NiceToolTipManagerImpl Line #275 and #209 for the code that looks up the text. Look at TextInputWithOverridenDynamicToolTipText for an example that uses the OOP-Approach.