几年前写了个在文本中插入图像显示 类,当时比较懒,没有任何说明和Demo,代码中一些用到的类也没提供,只是单纯地想记录下如何解决,以至于直接复制代码保存。所以之前的代码也是无法直接拿去用。
现在由于需要,刚开始找不到之前的代码,只能复制文章中的代码,发现改起来还挺费劲的,还好后来找到了完整的代码。坑了别人也把自己给坑了。
现在我把坑填上,还是先贴核心类的代码,代码中写了些注释虽然可能不是很详细。另外附上项目文件,项目中包含需要用到的其它类和简单的使用Demo,下载地址:http://pan.baidu.com/s/1nt8ClN7
package { import flash.display.Bitmap; public class ImgObject { public var src:String; public var id:String; public var imgWidth:Number; public var imgHeight:Number; public var imgXml:XML; public var image:Bitmap; public var index:int; //图像所在文本中的位置 public function ImgObject() { } } }
package
{
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import flash.text.AntiAliasType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.text.TextLineMetrics;
/**
* 文本容器类
* 该类主要处理在文本中包含显示图像,使文本与图像支持混合排列
* 只支持显示,不支持编辑
* 显示图像的格式为<img id='' width='20' height='20' src='图像地址'/>
* 如:
* var text:String = "这个一个图文混排的容器类<img width='20',height='20' src='/data/index.jpg'/>
* var tc:TextContainer = new TextContainer(200,new TextFormat("微软雅黑"));
* tc.setText(text);
*
* 如文本是HTMLText时:
* var text:String = <P><FONT COLOR='#979797' >这个一个图文混排的容器类</FONT><img width='20',height='20' src='/data/index.jpg'/><br/><FONT COLOR='#babec2' >支持HTML格式文本</FONT><P>
* var tc:TextContainer = new TextContainer(200);
* tc.setHtmlText(text);
*
* 如果要获取TextContainer的高度,需要等处理显示完成后才能更新到正确的宽高,所以需要监听SETTEXTCOMPLETED事件
* tc.addEventListener(TextContainer.SETTEXTCOMPLE,onSetTextCompleted,false,0,false);
* function onSetTextCompleted(e:Event):void{
* var w:Number = tc.width;
* var h:Number = tc.height;
* updateSize();
* }
*
*/
public class TextContainer extends Sprite
{
private var _textFormat:TextFormat; //文本格式
private var _maxWidth:Number; //容器的宽
private var textStr:String;
private var imgObjectArr:Array=new Array();
private var textArr:Array=new Array();
private var tempTf:TextField;
private var _placeholder:String;
private var _placeholderColor:uint;
private var _placeholderMarginH:int;
private var _placeholderMarginV:int;
private var _formatCalculator:TextField;
private var loader:Loader;
private var loadImgComplete:Function;
private var loadIoError:Function;
private var textLineHeight:Number;
private var originalText:String;
public static const SETTEXTCOMPLETED:String="SetTextCompleted";
private const margins:int=5;
private var _Number;
private var _height:Number;
private var isHtml:Boolean = false;
private static var DEFAULT_FONT:String = "微软雅黑,Microsoft YaHei";
/**
*
* @param maxWidth 文本容器最大宽度
* @param format 默认文本
*
*/
public function TextContainer(maxWidth:Number=100,format:TextFormat=null)
{
this.mouseEnabled = this.mouseChildren = false;
_textFormat=format;
if(format!=null){
_textFormat=format;
}else{
_textFormat=new TextFormat();
_textFormat.font=DEFAULT_FONT;
}
_maxWidth = maxWidth;
_placeholder=" ";
_placeholder=StringUtil.DecodingAscIIStr(_placeholder);
_placeholderColor = 0x000000;
_placeholderMarginH = 1;
_placeholderMarginV = 0;
_formatCalculator = new TextField();
_formatCalculator.text = _placeholder;
textLineHeight=Number(_textFormat.size);
}
/**
* 设置HTML格式的文本
* @param htmlText
*
*/
public function setHtmlText(htmlText:String):void{
isHtml = true;
setText(htmlText);
}
/**
* 重置
*
*/
private function reset():void{
this.removeChildren();
if(originalText != null)
imgObjectArr.length=0;
originalText = "";
}
/**
* 设置文本
* @param text
*
*/
public function setText(text:String):void{
reset();
originalText=text;
if(text==null||text.length<1){
trace("the text is has nothing");
return;
}
textStr=StringUtil.DecodingAscIIStr(text);
StringUtil.regExp_allMark.lastIndex=0;
//判断是否纯文本
if(!StringUtil.regExp_allMark.test(textStr)){
//纯文本
isHtml = false;
showText(textStr);
}else{
//判断是否有图片标签
if(!StringUtil.hasImgTag(textStr)){
showText(textStr);
}else{
//截取图片标签
catchImgTag(textStr);
textStr=textArr.join("");
if(imgObjectArr.length<=0){
showText(textStr);
}else{
showText(textStr,imgObjectArr);
}
}
}
}
/**
* 获取文本
* @return
*
*/
public function getText():String{
return originalText;
}
/**
* 显示文本
* @param text 显示的文本
* @param SpritesArr 插入文本中的图像信息数组
*
*/
private function showText(text:String,SpritesArr:Array=null):void{
if(text == null || text.length <1)return;
var textLength:int=0;
if(tempTf == null){
tempTf=createTextField();
}
if(isHtml){
tempTf.htmlText = text;
}else{
if(text) text=text.split("\r").join("\n");
tempTf.text=text;
if(this._textFormat==null){
_textFormat = new TextFormat();
_textFormat.font = DEFAULT_FONT
_textFormat.font=DEFAULT_FONT;
}
tempTf.setTextFormat(this._textFormat,0,tempTf.length);
}
textLength = tempTf.length;
if(SpritesArr!=null){
insertSpritesPlaceholder(SpritesArr,textLength);
loadImages(SpritesArr);
}else{
this.addChild(tempTf);
_width=tempTf.width;
_height=tempTf.height;
this.dispatchEvent(new Event(TextContainer.SETTEXTCOMPLETED));
}
}
/**
*将sprites数组中的显示元素的宽度占位符插入到指定文本的位置,生成一个有占位符的String
* @param Sprites
* @param maxIndex 文本最大长度
*
*/
private function insertSpritesPlaceholder(Sprites:Array,maxIndex:int):void{
if(Sprites==null)return;
Sprites.sortOn("index",Array.NUMERIC);
if(textLineHeight<=0) textLineHeight=10;
for (var i:int=0;i<Sprites.length;i++){
var obj:ImgObject=Sprites[i] as ImgObject;
if(obj.index<0||obj.index>maxIndex){
obj.index=maxIndex;
Sprites.splice(i,1);
Sprites.push(obj);
i--;
continue;
}
var ai:int=insertASPlaceholder(obj);
if(ai>0){
for(var j:int=i+1;j<Sprites.length;j++){
Sprites[j].index+=1;
}
maxIndex+=1;
}
maxIndex+=1;
}
}
/**
*生成一个obj位置的占位符
* @param obj
*
*/
private function insertASPlaceholder(obj:Object):int{
if(obj==null ||!(obj is ImgObject))
throw Error("The object is not ImgObject");
var imgObj:ImgObject=obj as ImgObject;
if(imgObj.imgWidth>this._maxWidth){
var whRate:Number=imgObj.imgWidth/imgObj.imgHeight;
imgObj.imgWidth=this._maxWidth-margins;
imgObj.imgHeight=Math.round(imgObj.imgWidth/whRate);
}
var index:int=imgObj.index;
var format:TextFormat=CalcPlaceholderFormat(imgObj.imgWidth,textLineHeight);
var tpindex:Number=0;
var ct:TextField= createTextField();
var addIndex:int=0;
ct.defaultTextFormat=tempTf.defaultTextFormat;
for(var i:int=0;i<tempTf.numLines;i++){
if(tempTf.getLineOffset(i)<=index&&index<=tempTf.getLineLength(i)+tempTf.getLineOffset(i)){
ct.text=tempTf.getLineText(i).slice(index-tempTf.getLineOffset(i)+1,tempTf.getLineLength(i));
if((Number(format.letterSpacing)+tempTf.getLineMetrics(i).width-ct.getLineMetrics(0).width)>tempTf.width){
tempTf.replaceText(index,index,"\r");
addIndex=1;
index+=addIndex;
}
break;
}
}
imgObj.index=index;
tempTf.replaceText(index,index,_placeholder);
tempTf.setTextFormat(format,index,index+1);
return addIndex;
}
/**
* 计算显示元素的占位符的文本格式(若使用不同的占位符,可重写此方法)。
* @param width 宽度。
* @param height 高度。
* @return
*/
private function CalcPlaceholderFormat(Number, height:Number):TextFormat
{
var format:TextFormat = new TextFormat();
format.font = "Tahoma";
format.color = _placeholderColor;
format.size =Math.round( height + 2 * _placeholderMarginV);
_formatCalculator.setTextFormat(format);
var metrics:TextLineMetrics = _formatCalculator.getLineMetrics(0);
format.letterSpacing =Math.ceil( width - metrics.width + 2 * _placeholderMarginH);
format.underline = format.italic = format.bold = false;
return format;
}
/**
* 将图像<img>html代码从文本中分离出来,将其存进一个imgObject中,
* 在插入图像时从imgObject获取它在文本中的位置
*/
private function catchImgTag(text:String):void{
var imgTagArr:Array;
imgObjectArr.length=0;
textArr.length=0;
if(StringUtil.hasImgTag(text)){
imgTagArr=text.match(StringUtil.regExp_IMG);
textArr=text.split(StringUtil.regExp_IMG);
if(isHtml){
//如果是html文本,需要先将其转成普通文本
//否则html标签都会被当成字符,影响字符位置的计算
//同时要将<img>标签转成非html标签
for(var i:int=0;i<imgTagArr.length;i++){
text=text.replace(imgTagArr[i],"[IMG]");
}
var temp:TextField = createTextField();
temp.htmlText = text;
text = temp.text;
}
//创建图像信息对象
for(var i:int=0;i<imgTagArr.length;i++){
var imgObj:ImgObject=new ImgObject();
imgObj.imgXml=XML(imgTagArr[i]);
imgObj.id=imgObj.imgXml.@id;
imgObj.imgWidth=imgObj.imgXml.@width;
imgObj.imgHeight=imgObj.imgXml.@height;
imgObj.src=imgObj.imgXml.@src;
//计算图像在文本中的位置,用于之后的插入图像
if(isHtml){
imgObj.index = text.indexOf("[IMG]")+i
text=text.replace("[IMG]","");
}else{
imgObj.index=text.indexOf(imgTagArr[i])+i;
text=text.replace(imgTagArr[i],"");
}
imgObjectArr.push(imgObj);
}
}
}
//加载图像数据
private function loadImages(SpritesArr:Array):void{
loadOtImages(SpritesArr,0);
}
/**
* 循环加载图像数组
* @param SpritesArr 图像信息数组
* @param index 加载数组中的项索引
*
*/
private function loadOtImages(SpritesArr:Array,index:int):void{
if(index<0||index>SpritesArr.length-1){
//这里要调用另一个方法,在加载完成后调用
replacePlaceholderToImg(SpritesArr);
return;
}
var imgObj:ImgObject=SpritesArr[index] as ImgObject;
loadImgComplete=function(dobj:DisplayObject):void{OnCompleteHander(dobj,imgObj,SpritesArr,index)};
loadIoError=function (){OnIOErrorHandler(SpritesArr,index)};
LoaderPool.getInstance().load(imgObj.src,loadImgComplete,loadIoError);
}
private function OnCompleteHander(dobj:DisplayObject,imgObj:ImgObject,SpritesArr:Array,index:int):void{
if(imgObj!=null && dobj != null && (dobj is Bitmap)){
//imgObj.image=e.target.content as Bitmap;
imgObj.image = cloneBMP(dobj as Bitmap);
if(imgObj.image!=null){
if(imgObj.imgWidth<imgObj.image.width||imgObj.imgHeight<imgObj.image.height){
imgObj.image.width=imgObj.imgWidth;
imgObj.image.height=imgObj.imgHeight;
}
}
index++;
loadOtImages(SpritesArr,index);
}
}
private function cloneBMP(bmp:Bitmap):Bitmap{
if(bmp == null) return null;
var bmp:Bitmap = new Bitmap(bmp.bitmapData,bmp.pixelSnapping,bmp.smoothing);
return bmp;
}
private function OnIOErrorHandler(SpritesArr:Array,index:int):void{
ImgObject(SpritesArr[index]).image=null;
index++;
loadOtImages(SpritesArr,index);
}
/**
* 该方法要实现的功能就是从tempTf中分离出有图片所在的那一行文本,从新调整当行的高度和图片的位置,然后再将其插入之前文本所在的位置
* 根据textField获取每一行的长度(getLineLength)和每行第一个字符索引(getLineOffset)来确定图片所在的行,再用getLineText获取该行
* 的文本保存到一个新的textField中,该textField的format要与原来的相同。
*
* @return
*
*/
private function replacePlaceholderToImg(sprites:Array):void{
var currentLine:int=0; //当前行
var currentLineStarIndex:int=0; //当前行第一个索引
var currentLineEndIndex:int=0; //当前行最后一个索引
var imgLine:int=0;//图片所在文本行
var tfLineInfo:Object=new Object();
var imgObj:ImgObject;
var flag:Boolean=false;
var tempSprite:Sprite;
var currentImgs:Array=new Array();
var heightPos:Number;
sprites.sortOn("index",Array.NUMERIC);
//创建一个textfield
var tfpa:TextField=createTextField();
tfpa.defaultTextFormat=tempTf.defaultTextFormat;
heightPos=0;
var htmlList:Array;
htmlList= tempTf.htmlText.match(StringUtil.regExp_P);
currentLineStarIndex = 0;
for(var i:int=0;i<htmlList.length;i++){
currentLine=i;
var tfitem:TextField=createTextField();
tfitem.htmlText = htmlList[i];
currentLineStarIndex = currentLineEndIndex + (i==0?0:1);
currentLineEndIndex= currentLineStarIndex + tfitem.length-1;
currentImgs.length=0;
for(var j:int=0;j<sprites.length;j++){
imgObj=(sprites[j] as ImgObject);
if(currentLineStarIndex<=imgObj.index&¤tLineEndIndex>=imgObj.index){
//如果该行有图片,创建一个sprite,该sprite的高是图片的高度,宽度是textfield的宽
if(imgObj.image!=null){
tfitem.setTextFormat(tempTf.getTextFormat(imgObj.index,imgObj.index+1),imgObj.index-currentLineStarIndex,imgObj.index-currentLineStarIndex+1);
currentImgs.push(imgObj);
flag=true;
}else{
//trace(tfitem.text);
//tfitem.replaceText(imgObj.index-currentLineStarIndex,imgObj.index-currentLineStarIndex+1,"");
//trace(tfitem.text)
//tempTf.replaceText(index,index,"\r");
}
}
}
//如果该行有图片再创建一个新的textfield继续下一个循环
var spriteHeight:Number;
if(tfpa != null){
tfpa.defaultTextFormat=tempTf.defaultTextFormat;
}
if(flag){
currentImgs.sortOn("imgHeight",Array.NUMERIC);
tempSprite=new Sprite();
spriteHeight=currentImgs[currentImgs.length-1].imgHeight>tfitem.textHeight?currentImgs[currentImgs.length-1].imgHeight:tfitem.textHeight;
spriteHeight=spriteHeight;
currentImgs.sortOn("index",Array.NUMERIC);
tempSprite.addChild(tfitem);
tfitem.x=0;
tfitem.y=spriteHeight-tfitem.height+tfitem.getLineMetrics(0).leading;
for(var k:int=0;k<currentImgs.length;k++){
var rect:Rectangle =tfitem.getCharBoundaries(currentImgs[k].index-currentLineStarIndex);
if (rect != null)
{
currentImgs[k].image.x = (rect.x + (rect.width - currentImgs[k].image.width) * 0.5 + 0.5) >> 0;
currentImgs[k].image.y=spriteHeight-currentImgs[k].imgHeight;
tempSprite.addChild(currentImgs[k].image);
}
}
tempSprite.x=0;
tempSprite.y=heightPos;
heightPos=tempSprite.y+tempSprite.height;
this.addChild(tempSprite);
tfpa=createTextField();
flag=false;
}
else if(!this.contains(tfpa)){
tfpa.htmlText = tfpa.htmlText +tfitem.htmlText;
tfpa.x=0;
tfpa.y=heightPos;
this.addChild(tfpa);
heightPos=tfpa.y+tfpa.height;
}else{
tfpa.htmlText = tfpa.htmlText +tfitem.htmlText;
heightPos=tfpa.y+tfpa.height;
}
if(i>0){
_width=maxWidth;
}else{
_width=tfitem.width;
}
_height=super.height;
}
this.dispatchEvent(new Event(TextContainer.SETTEXTCOMPLETED));
}
public function update():void{
if(originalText!=null&&(originalText!=""||originalText.length>0)){
setText(originalText);
}
}
/**
* 创建新的TextField对象
* @return
*
*/
private function createTextField():TextField{
var tf:TextField=new TextField();
tf.width=_maxWidth;
tf.autoSize=TextFieldAutoSize.LEFT;
tf.multiline=true;
tf.wordWrap=true;
if(_textFormat!=null){
tf.defaultTextFormat=_textFormat;
}else{
_textFormat=new TextFormat();
_textFormat.font=DEFAULT_FONT;
tf.defaultTextFormat=_textFormat;
}
return tf;
}
/**
* 获取默认的文本格式
* @return
*
*/
public function get defalutFormat():TextFormat
{
return _textFormat;
}
/**
* 设置默认的文本格式
* @return
*
*/
public function set defalutFormat(value:TextFormat):void
{
_textFormat = value;
update();
}
/**
* 获取宽度最大值
* @param value
*
*/
public function get maxWidth():Number
{
return _maxWidth;
}
/**
* 设置宽度最大值
* @param value
*
*/
public function set maxWidth(value:Number):void
{
_maxWidth = value;
update();
}
override public function get height():Number
{
return _height;
}
override public function set height(value:Number):void{
//_height = value;
throw new Error("不能直接设置TextContainer的高度");
}
override public function get width():Number
{
return _width;
}
override public function set width(value:Number):void{
//_width = value;
throw new Error("不能直接设置TextContainer的宽度,请用maxWidth设置最大宽度");
}
}
}