Found a little handy customization of the Spark Label control that truncates the label in the middle with a (…). However it didn’t show the full label text on roll over when setting the showTruncationTip=”true” property of the control. I added a few little lines of code to fix it.
The code stores the original value in a variable called “_trueText”, so that just needs to be the value you pass to the toolTip when showTruncationTip=”true”. You need to override the mx_internal function to accomplish this.
override mx_internal function setIsTruncated(value:Boolean):void
{
if (_isTruncated != value)
{
_isTruncated = value;
if (showTruncationTip)
toolTip = _isTruncated ? _trueText : null;
dispatchEvent(new Event("isTruncatedChanged"));
}
}
Then you need to add one little bit of code in the truncateTextMiddle method that will tell the control that the text is indeed truncated, setIsTruncated(true); should be at the end of that method around line 153 in the code snippet below:
public function truncateTextMiddle(fullText:String, widthToTruncate:Number) : String
{
if (!(fullText) || fullText.length < 3 || !this.parent)
{
// skip any truncating if no styles (no parent),
// or text is too small
return fullText;
}
// add paddings for some font oversize issues
var paddingWidth:Number =
UITextField.mx_internal::TEXT_WIDTH_PADDING +
this.getStyle("paddingLeft") + this.getStyle("paddingRight");
// Skip if width is too small
if (widthToTruncate < paddingWidth + 10) return fullText;
// Prepare measurement object
// We create new TextField, and copy styles for it from this object
// We cannot re-use internal original text field instance because
// it will cause event firing in process of text measurement
var measurementField:TextField = new TextField();
// Clear so measured text will not get old styles.
measurementField.text = "";
// Copy styles into TextField
var textStyles:UITextFormat = this.determineTextFormatFromStyles();
measurementField.defaultTextFormat = textStyles;
var sm:ISystemManager = this.systemManager;
if (textStyles.font)
{
measurementField.embedFonts = sm != null && sm.isFontFaceEmbedded(textStyles);
}
else
{
measurementField.embedFonts = false;
}
if (textStyles.antiAliasType) {
measurementField.antiAliasType = textStyles.antiAliasType;
}
if (textStyles.gridFitType) {
measurementField.gridFitType = textStyles.gridFitType;
}
if (!isNaN(textStyles.sharpness)) {
measurementField.sharpness = textStyles.sharpness;
}
if (!isNaN(textStyles.thickness)) {
measurementField.thickness = textStyles.thickness;
}
// Perform initial measure of text and check if need truncating at all
// To measure text, we set it to measurement text field
// and get line metrics for first line
measurementField.text = fullText;
var fullTextWidth:Number = measurementField.getLineMetrics(0).width + paddingWidth;
if(fullTextWidth > widthToTruncate){
// get width of ...
measurementField.text = "...";
var dotsWidth:Number = measurementField.getLineMetrics(0).width;
// Find out what is the half of truncated text without ...
var halfWidth : Number = (widthToTruncate - paddingWidth - dotsWidth) / 2;
// Make a rough estimate of how much chars we need to cut out
// This saves steps of character-by-character preocessing
measurementField.text = "s";
var charWidth:Number = measurementField.getLineMetrics(0).width;
var charsToTruncate:int = Math.round(
((fullTextWidth - paddingWidth) / 2 - halfWidth) /
charWidth) + 2;
// allow some distortion to account fractional widths part
halfWidth = halfWidth - 0.5;
// Below algorithm makes rough middle-truncating
// Then it is corrected by adding or removing
// characters for each part until reach required
// width for each half. Algorith does checks
// (min max and loop ciodnitions) so that string
// cannot be less then one character for each half
// see if right part of text approximately fits into half width
var rightPart:String;
var widthWithNextChar:Number;
var len:int = fullText.length;
var currLoc:int = Math.min(len/2 + charsToTruncate + 1, len-1);
measurementField.text = fullText.substr(currLoc);
var rightPartWidth:Number = measurementField.getLineMetrics(0).width;
if (rightPartWidth > halfWidth) {
// throw away characters until fits
currLoc++;
while (rightPartWidth > halfWidth && currLoc < len) {
measurementField.text = fullText.charAt(currLoc);
rightPartWidth -= measurementField.getLineMetrics(0).width;
currLoc++;
}
rightPart = fullText.substr(currLoc - 1);
} else {
// try to add characters one-by-one and
// see if it still fits
widthWithNextChar = 0;
do {
currLoc--;
rightPartWidth += widthWithNextChar;
measurementField.text = fullText.charAt(currLoc);
widthWithNextChar = measurementField.getLineMetrics(0).width;
} while (rightPartWidth + widthWithNextChar <= halfWidth && currLoc > 0);
rightPart = fullText.substr(currLoc + 1);
}
// Do the same with left part, but compare overall string
// Overall is needed because character-by character
// would not give us correct total width of string -
// somehow overall text is measured with sapcers etc. and
// also there are rounding issues.
// This way, and by putting left part calculating as last, we allow
// left part might be larger (may become more than half).
// allow some distortion in widths fractions
widthToTruncate = widthToTruncate - 0.5 - paddingWidth;
currLoc = Math.max(len/2 - charsToTruncate, 1);
measurementField.text = fullText.substr(0, currLoc) +
"..." + rightPart;
var truncatedWidth:Number = measurementField.getLineMetrics(0).width;
if (truncatedWidth > widthToTruncate) {
// throw away characters until fits
currLoc--;
while (truncatedWidth > widthToTruncate && currLoc > 0) {
measurementField.text = fullText.substr(0, currLoc) +
"..." + rightPart;
truncatedWidth = measurementField.getLineMetrics(0).width;
currLoc--;
}
currLoc++;
} else {
// try to add characters one-by-one and
// see if it still fits
do {
currLoc++;
measurementField.text = fullText.substr(0, currLoc) +
"..." + rightPart;
widthWithNextChar = measurementField.getLineMetrics(0).width;
} while (widthWithNextChar <= widthToTruncate &&
currLoc < len-1);
currLoc--;
}
setIsTruncated(true);
return fullText.substr(0, Math.max(currLoc,1)) +
"..." + rightPart;
}
return fullText;
}
The original post can be found here.
-Mr