在TWaver Flex中实现垂直文字布局
? ? ?最近有客户提到如何让Network上网元的标签垂直显示,首先想到的就是每个字符之间插入一个回车。这个用Network#labelFunction就能达到目的:
network.labelFunction = function (element:IElement):String {var name:String = element.name;if(element.getClient('vertical')) {var result:String = '';for(var i:int=0,n:int=name.length; i<n; i++) {result += name.charAt(i) + '\n';}result = result.substr(0, result.length-1);return result;} else {return name;}};
? ??来段代码测试看看:
<?xml version="1.0" encoding="utf-8"?><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"xmlns:twaver="http://www.servasoftware.com/2009/twaver/flex"layout="absolute" width="100%" height="100%"creationComplete="init()" backgroundColor="#FFFFFF" ><mx:Script><![CDATA[import twaver.Consts;import twaver.ElementBox;import twaver.IElement;import twaver.Node;import twaver.Styles;private var box:ElementBox = new ElementBox();private function init():void {network.labelFunction = function (element:IElement):String {var name:String = element.name;if(element.getClient('vertical')) {var result:String = '';for(var i:int=0,n:int=name.length; i<n; i++) {result += name.charAt(i) + '\n';}result = result.substr(0, result.length-1);return result;} else {return name;}};var node1:Node = new Node();node1.location = new Point(100, 100);node1.setStyle(Styles.LABEL_POSITION, Consts.POSITION_LEFT_LEFT);node1.setClient('vertical', true);node1.name = '竖向文字Vertical Text';box.add(node1);network.elementBox = box;}]]></mx:Script><twaver:Network id="network" width="100%" height="100%" /></mx:Application>
?
? ? ? 运行效果如下:
? ? ?上面的方法很容易让文字垂直显示,但效果不是很理想,中英文混合时,英文也被一个字母一个字母地分开了。有没有更好的方案?答案是肯定的,借助于Flex的Flash Text Engine (FTE)和Text Layout Framework (TLF),可以很容易的让文字从上到下显示。
? ? ? 先来看看一个小例子,设置TextLayoutFormat的blockProgression属性为BlockProgression.RL即可:
package {import flash.display.Sprite;import flashx.textLayout.container.ContainerController;import flashx.textLayout.conversion.TextConverter;import flashx.textLayout.elements.TextFlow;import flashx.textLayout.formats.BlockProgression;import flashx.textLayout.formats.TextLayoutFormat;public class StaticHelloWorld extends Sprite {public function StaticHelloWorld() {var textLayoutFormat:TextLayoutFormat = new TextLayoutFormat();textLayoutFormat.lineHeight = 30;textLayoutFormat.locale = 'zh';textLayoutFormat.blockProgression = BlockProgression.RL;var text:String = "测试竖向文字,再看看English如何?";var textFlow:TextFlow = TextConverter.importToFlow(text, TextConverter.PLAIN_TEXT_FORMAT);textFlow.hostFormat = textLayoutFormat;textFlow.flowComposer.addController(new ContainerController(this, 25, 200));textFlow.flowComposer.updateAllControllers();}}}
?
运行效果如下:
? ? ? ?的确这样效果就好多了,英文不会被一个字母一个字母地打断,然后我们自定义一个Attachment:
package {import flash.display.Sprite;import flash.text.engine.FontPosture;import flash.text.engine.FontWeight;import flashx.textLayout.container.ContainerController;import flashx.textLayout.elements.ParagraphElement;import flashx.textLayout.elements.SpanElement;import flashx.textLayout.elements.TextFlow;import flashx.textLayout.formats.BlockProgression;import flashx.textLayout.formats.TextDecoration;import flashx.textLayout.formats.TextLayoutFormat;import twaver.Styles;import twaver.network.ui.BasicAttachment;import twaver.network.ui.ElementUI;public class FTELabelAttachment extends BasicAttachment {private var textLayoutFormat:TextLayoutFormat = new TextLayoutFormat();public function FTELabelAttachment(elementUI:ElementUI, showInAttachmentCanvas:Boolean=false) {super(elementUI, showInAttachmentCanvas);this.textLayoutFormat.locale = 'zh';this.textLayoutFormat.blockProgression = BlockProgression.RL;}override public function updateProperties():void {super.updateProperties();this.textLayoutFormat.fontFamily = element.getStyle(Styles.LABEL_FONT);this.textLayoutFormat.color = element.getStyle(Styles.LABEL_COLOR);this.textLayoutFormat.fontSize = element.getStyle(Styles.LABEL_SIZE);this.textLayoutFormat.fontStyle = element.getStyle(Styles.LABEL_ITALIC) ? FontPosture.ITALIC : FontPosture.NORMAL;this.textLayoutFormat.fontWeight = element.getStyle(Styles.LABEL_BOLD) ? FontWeight.BOLD : FontWeight.NORMAL;this.textLayoutFormat.textDecoration = element.getStyle(Styles.LABEL_UNDERLINE ? TextDecoration.UNDERLINE : TextDecoration.NONE);var textFlow:TextFlow = new TextFlow();textFlow.hostFormat = this.textLayoutFormat;var p:ParagraphElement = new ParagraphElement();textFlow.addChild(p);var span:SpanElement = new SpanElement();span.text = network.getLabel(element);p.addChild(span);var fteLabel:Sprite = new Sprite();this.content = fteLabel;var containerController:ContainerController = new ContainerController(fteLabel, this.textLayoutFormat.fontSize, 1000);textFlow.flowComposer.addController(containerController);textFlow.flowComposer.updateAllControllers();}override public function get position():String {return element.getStyle(Styles.LABEL_POSITION);}override public function get xOffset():Number {return element.getStyle(Styles.LABEL_XOFFSET);}override public function get yOffset():Number {return element.getStyle(Styles.LABEL_YOFFSET);}override public function get padding():Number {return element.getStyle(Styles.LABEL_PADDING);}override public function get paddingLeft():Number {return element.getStyle(Styles.LABEL_PADDING_LEFT);}override public function get paddingRight():Number {return element.getStyle(Styles.LABEL_PADDING_RIGHT);}override public function get paddingTop():Number {return element.getStyle(Styles.LABEL_PADDING_TOP);}override public function get paddingBottom():Number {return element.getStyle(Styles.LABEL_PADDING_BOTTOM);}override public function get cornerRadius():Number {return element.getStyle(Styles.LABEL_CORNER_RADIUS);}override public function get pointerLength():Number {return element.getStyle(Styles.LABEL_POINTER_LENGTH);}override public function get pointerWidth():Number {return element.getStyle(Styles.LABEL_POINTER_WIDTH);}override public function get direction():String {return element.getStyle(Styles.LABEL_DIRECTION);}override public function get fill():Boolean {return element.getStyle(Styles.LABEL_FILL);}override public function get fillColor():Number {return element.getStyle(Styles.LABEL_FILL_COLOR);}override public function get fillAlpha():Number {return element.getStyle(Styles.LABEL_FILL_ALPHA);}override public function get gradient():String {return element.getStyle(Styles.LABEL_GRADIENT);}override public function get gradientColor():Number {return element.getStyle(Styles.LABEL_GRADIENT_COLOR);}override public function get gradientAlpha():Number {return element.getStyle(Styles.LABEL_GRADIENT_ALPHA);}override public function get contentXScale():Number {return element.getStyle(Styles.LABEL_CONTENT_XSCALE);}override public function get contentYScale():Number {return element.getStyle(Styles.LABEL_CONTENT_YSCALE);}override public function get outlineWidth():Number {return element.getStyle(Styles.LABEL_OUTLINE_WIDTH);}override public function get outlineColor():Number {return element.getStyle(Styles.LABEL_OUTLINE_COLOR);}override public function get outlineAlpha():Number {return element.getStyle(Styles.LABEL_OUTLINE_ALPHA);}}}
?
? ? ? 再自定义Node和NodeUI,使用这个Attachment代替TWaver自带的LabelAttachment:
自定义Node:
package {import twaver.Node;public class FTELabelNode extends Node {public function FTELabelNode(id:Object=null) {super(id);}public override function get elementUIClass():Class {return FTELabelNodeUI;}}}
? ? ?自定义NodeUI:
package {import twaver.Node;import twaver.network.Network;import twaver.network.ui.NodeUI;public class FTELabelNodeUI extends NodeUI {private var _labelAttachment:FTELabelAttachment = null;public function FTELabelNodeUI(network:Network, node:Node) {super(network, node);}override protected function checkLabelAttachment():void{var label:String = this.network.getLabel(element);if(label != null && label != ""){if(this._labelAttachment == null){this._labelAttachment = new FTELabelAttachment(this, false);this.addAttachment(this._labelAttachment);}}else{if(this._labelAttachment != null){this.removeAttachment(this._labelAttachment);this._labelAttachment = null;}}}}}
?
最后,写个例子看看效果:
<?xml version="1.0" encoding="utf-8"?><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"xmlns:twaver="http://www.servasoftware.com/2009/twaver/flex"layout="absolute" width="100%" height="100%"creationComplete="init()" backgroundColor="#FFFFFF" ><mx:Script><![CDATA[import twaver.Consts;import twaver.ElementBox;import twaver.IElement;import twaver.Node;import twaver.Styles;private var box:ElementBox = new ElementBox();private function init():void {network.labelFunction = function (element:IElement):String {var name:String = element.name;if(element.getClient('vertical')) {var result:String = '';for(var i:int=0,n:int=name.length; i<n; i++) {result += name.charAt(i) + '\n';}result = result.substr(0, result.length-1);return result;} else {return name;}};var node1:Node = new Node();node1.location = new Point(100, 100);node1.setStyle(Styles.LABEL_POSITION, Consts.POSITION_LEFT_LEFT);node1.setClient('vertical', true);node1.name = '竖向文字Vertical Text';box.add(node1);var node2:Node = new FTELabelNode();node2.location = new Point(300, 100);node2.setStyle(Styles.LABEL_POSITION, Consts.POSITION_LEFT_LEFT);node2.name = '竖向文字Vertical Text';box.add(node2);network.elementBox = box;}private function changeFontSize():void {box.forEach(function (element:IElement):void {element.setStyle(Styles.LABEL_SIZE, element.getStyle(Styles.LABEL_SIZE) + 2);});}]]></mx:Script><mx:VBox width="100%" height="100%"><mx:HBox width="100%" height="20"><mx:Button label="Change Font Size" click="changeFontSize()"/></mx:HBox><twaver:Network id="network" width="100%" height="100%" /></mx:VBox></mx:Application>
?
恩,这就是我想要的效果:
更多关于FTE和TLF的信息,请参考Adobe官方文档:
TextLayoutFormat
TextFlow
Textlayout
本文完整代码见附件:FTELabelAttachment