读书人

[转]自持Flash表情聊天

发布时间: 2012-12-22 12:05:07 作者: rapoo

[转]自制Flash表情聊天
http://blog.163.com/caty_nuaa/blog/static/90390720103811359879/




因为项目需要,自己仿照其他flash游戏中的聊天写了一个带表情的聊天,思路还是基于网上的使用多个TextField来组织聊天信息的显示,每个TextField上再摆放一层用于显示表情的图层,这样做效率还是不错的,不过不可以一次选择多行了,目前也没有做表情的复制功能,所以选中复制的时候只能复制占位符

点此下载工程

ChatTextField.as

package com.lx.chat{    import fl.containers.ScrollPane;    import fl.controls.ScrollBarDirection;    import fl.controls.ScrollPolicy;    import fl.events.ScrollEvent;        import flash.display.DisplayObject;    import flash.display.Sprite;    import flash.events.TextEvent;        public class ChatTextField extends Sprite    {        private var _textContainer:Sprite;        private var _scroll:ScrollPane;        private var _maxLines:uint;        private var _msgArr:Array;                public function ChatTextField(w:uint = 300, h:uint = 200):void        {            _msgArr = new Array();            _textContainer = new Sprite();            _scroll = new ScrollPane();            //_scroll.verticalScrollPolicy = ScrollPolicy.ON;            _scroll.horizontalScrollPolicy = ScrollPolicy.OFF;            _scroll.focusEnabled = false; // 此设置可以解决text不能选择的问题,也可以解决多个选择的问题            _scroll.source = _textContainer;            _scroll.setSize(w, h);            _scroll.addEventListener(ScrollEvent.SCROLL, onScroll);            //_scroll.useBitmapScrolling = true;            addChild(_scroll);            maxLines = 30;        }                public function appendMessage(channel:String, srcName:String, dstName:String, id:uint, content:String, bSelf:Boolean):void        {            var tf:FaceTextField = new FaceTextField(_scroll.width - _scroll.verticalScrollBar.width);            tf.appendChatText(channel, srcName, dstName, id, content, bSelf);            _msgArr.push(tf);            tf.x = 0;            tf.y = _textContainer.height;            _textContainer.addChild(tf);            if (_msgArr.length > _maxLines)            {                var obj:DisplayObject = _msgArr.shift();                if (obj)                {                    _textContainer.removeChild(obj);                    for each (var item:FaceTextField in _msgArr)                    {                        item.y = item.y - obj.height;                    }                }            }            if (_textContainer.height > _scroll.height)            {                _scroll.update();                _scroll.verticalScrollPosition = _scroll.maxVerticalScrollPosition;            }            else                _scroll.refreshPane();            tf._txtField.addEventListener(TextEvent.LINK, onLink);        }                private function onScroll(e:ScrollEvent):void        {            if (e.direction == ScrollBarDirection.VERTICAL)            {                for each(var item:FaceTextField in _msgArr)                {                    if (item.y + item.height < _scroll.verticalScrollPosition ||                         item.y > _scroll.verticalScrollPosition + this.height)                    {                        item.visible = false;                    }                    else                    {                        item.visible = true;                    }                }             }        }                private function onLink(e:TextEvent):void        {            this.dispatchEvent(e);        }                public function set maxLines(n:uint):void        {            _maxLines = n;        }                public function get maxLines():uint        {            return _maxLines;        }    }}



FaceTextField.as

package com.lx.chat{    import com.lx.sprites.Animation;        import flash.display.Bitmap;    import flash.display.Sprite;    import flash.geom.Rectangle;    import flash.text.TextField;    import flash.text.TextFormat;    import flash.text.TextFormatAlign;    import flash.utils.*;    public class FaceTextField extends Sprite    {        //the text format        private var _fmtName:TextFormat;        private var _fmtMsg:TextFormat;        //the instance of textfield        public var _txtField:TextField;        //indicates line height.        public var lineHeight:Number;        //only contain sprites which are inserted in _textfield        public var _spriteContainer:Sprite;        //the default textformat of _textfield        private var _defaultTextFormat:TextFormat;        //the length of the _textfield.text        private var _length:int;        //specify the sprite&39;s vspace/hspace in _textfield        private var _spriteVspace:int;        private var _spriteHspace:int;        //save the selection begin/end indexes of _textfield        private var _selectBegin:int;        private var _selectEnd:int;        //use it to mark the TextField.replaceText() time during addSprite        private var _replacing:Boolean;        //regular expression for the chat face        private static var _reg:RegExp;        //width of the textfield        private var _widthTxt:uint;        //the text align is center?        private var _bCenter:Boolean;                /**         * trick, a sprite&39;s placeholder         * special character:  unicode is 65106         * special font: Arial         */        private var PLACEHOLDER:String = "○";        private var PLACEHOLDER_FONT:String = "Arial";        private var PLACEHOLDER_COLOR:uint = 0x000000;        private static const _lt:String="/:";        //dictionary of the emote        public static var _dict:Dictionary;        public function FaceTextField(width:Number, center:Boolean = false)        {            _fmtName = new TextFormat("Arial", 12, 0xFF0000, true);                _fmtMsg = new TextFormat("Courier New", 12, 0xFFFFFF, false);            _bCenter = center;            if (center)            {                _fmtName.align = TextFormatAlign.CENTER;                _fmtMsg.align = TextFormatAlign.CENTER;            }            //initTextField(width);                        _spriteContainer = new Sprite();                            //default lineHeight is 0(ignore)            lineHeight = 0;            //default sprite vspace/hspace is 2 (changes to 1, 2009-3-3)            _spriteHspace = _spriteVspace = 1;                    _widthTxt = width;        }                public static function buildRegExp(arrExpress:Array):void         {            var strReg:String = "";            var arrReg:Array = new Array();            var last:String = arrExpress[arrExpress.length - 1];            for each(var item:* in arrExpress)            {                arrReg.push(_lt);                arrReg.push(item);                if (item != last)                    arrReg.push("|");            }            strReg = arrReg.join("");            _reg = new RegExp(strReg, "g");        }                /**         * initialize the _textfield         * @param    width         */        private function initTextField(width:Number):void        {            _txtField = new TextField();                        _txtField.width = width;            _txtField.height = 400;            _txtField.multiline = true;            _txtField.wordWrap = true;            //_txtField.filters = [GlobalFunction.getGlowFilter()];        }                 /**         * 将加工过的字符串转换为包含表情的内容.         * @param str         * */        public function convertStringToRich(str:String):Object         {            var array:Array = [];            var arrExp:Array = str.match(_reg);            var faceObj:Object = {src:null, index:null};            for (var i:int = 0; i < arrExp.length; ++i)            {                try                {                    var className:String = arrExp[i].slice(_lt.length, arrExp[i].length);                    var idx:int = str.indexOf(arrExp[i]);                    faceObj = {src:className, index:idx};                    str = str.substring(0, idx) + str.substring(idx + arrExp[i].length, str.length);                }                catch (err:Error)                {                    continue;                }                array.push(faceObj);            }                        var result:Object = {mess:str, faces:array};            return result;        }                public function get numSprite():int        {            return _spriteContainer.numChildren;        }                public function getSpriteIndexAt(depth:int):int        {                        var sprite:Bitmap = getSpriteAt(depth);            if (sprite)                 return int(sprite.name);            else                 return -1;        }                public function getSpriteAt(depth:int):Bitmap        {            if (depth >= _spriteContainer.numChildren)                 return null;            return _spriteContainer.getChildAt(depth) as Bitmap;        }                    public function getSpriteByName(name:String):Bitmap        {            return _spriteContainer.getChildByName(name) as Bitmap;                    }                public function removeSpriteByName(name:String):void        {            var sp:Bitmap = _spriteContainer.getChildByName(name) as Bitmap;            if (sp)            {                _spriteContainer.removeChild(sp);            }        }                public function set spriteVspace(value:int):void        {            _spriteVspace = value;        }                public function set spriteHspace(value:int):void        {            _spriteHspace = value;        }                public function set defaultTextFormat(format:TextFormat):void        {            //set the default textformat and effect immediately            if (format.letterSpacing == null)                 format.letterSpacing = 0;            _defaultTextFormat = format;            _txtField.defaultTextFormat = format;        }                public function get defaultTextFormat():TextFormat        {            return _defaultTextFormat;        }                public function set placeholderColor(value:uint):void        {            PLACEHOLDER_COLOR = value;        }                /**         * clear all properties, back to original status.         */        public function clear():void        {            _txtField.text = "";            recoverDefaultTextFormat();            _spriteContainer.y = 0;            while (_spriteContainer.numChildren > 0)                _spriteContainer.removeChildAt(0);        }                public function appendChatText(channel:String, srcName:String, dstName:String, id:uint,             content:String, bSelf:Boolean = false, autoWordWrap:Boolean = true):void        {            if (_txtField)            {                clear();                removeChild(_txtField);            }            initTextField(_widthTxt);            var obj:Object = convertStringToRich(content);            appendText(channel, srcName, dstName, id, obj.mess, bSelf, _fmtName, _fmtMsg);                            if (obj.faces)            {                var _arrEmote:Array = new Array();                for (var i:int = 0; i < obj.faces.length; i++)                {                    var index:int = obj.faces[i].index;                    if (index == -1)                         index = obj.mess.length;                    else if (autoWordWrap)                         index -= 1;                    index += _txtField.length - obj.mess.length;                                        //trace("addSprite", object[i].src, index, _textfield.length);                    //the last sprite should be added before newline character(\n).                    //if (autoWordWrap && index == _textfield.length) index --;                    //modified at 12-05-2008                    if (autoWordWrap && index >= _txtField.length)                         index = _txtField.length - 1;                    //if specify lineHeight(>0), all lines will be same height.                    index = addPlaceHolder(index);                    _arrEmote.push({cname:obj.faces[i].src, idx:index});                    //addSprite(obj.faces[i].src, index, 0, lineHeight);                }                for each(var item:Object in _arrEmote)                {                    addSprite(item.cname, item.idx, 0, lineHeight);                }            }            _txtField.height = (int)(_txtField.textHeight) + 5;            addChild(_txtField);            addChild(_spriteContainer);        }                private function addPlaceHolder(caretIndex:int):int        {            //insert a placeholder for target and format it            if (caretIndex == -1)                 caretIndex = _txtField.caretIndex;            //fix the bug that supplied index is out of bound, 11-24-2008            //if caretIndex is out of bound, add sprite to the end.                        if (caretIndex > _txtField.length)             {                caretIndex = _txtField.length;            }            var format:TextFormat = getPlaceholderFormat();                                _txtField.replaceText(caretIndex, caretIndex, PLACEHOLDER);            _txtField.setTextFormat(format, caretIndex);            return caretIndex;        }                /**         * add a sprite with a placeholder to the right place         * @param    target Class or Sprite instance         * @param    width         * @param    height         * @param    caretIndex         */        private function addSprite(target:String, caretIndex:int = -1, width:Number = -1, height:Number = -1):void        {                        //create a target sprite            var targetClass:Class;            var ani:Animation;            if (target != null && target != "")            {                var arrBmp:Array;                var str:String = target.toUpperCase();                arrBmp = _dict[str];                ani = new Animation();                ani.fps = 250;                                            var rectPlaceholder:Rectangle = getCharBoundaries(caretIndex);                //var h:int = target.height;                var x:int = _spriteContainer.x + rectPlaceholder.left - _spriteHspace;                var y:int = rectPlaceholder.top + rectPlaceholder.height - arrBmp[0].height - _spriteVspace;                for each (var item:* in arrBmp)                {                    ani.push(new Bitmap(item), x, y);                }                ani.name = String(caretIndex);                _spriteContainer.addChild(ani);            }        }                private function appendText(channel:String, srcName:String, dstName:String, id:uint, text:String, bSelf:Boolean, formatName:TextFormat = null, formatText:TextFormat = null):void        {            recoverDefaultTextFormat();            if (channel)            {                channel = channel.replace(/</g, "<");                channel = channel.replace(/>/g, ">");            }            if (srcName)            {                srcName = srcName.replace(/</g, "<");                srcName = srcName.replace(/>/g, ">");            }            if (dstName)            {                dstName = dstName.replace(/</g, "<");                dstName = dstName.replace(/>/g, ">");            }            if (text)            {                text = text.replace(/</g, "<");                text = text.replace(/>/g, ">");            }            var arrStr:Array = new Array();            if (_bCenter)                arrStr.push("<P ALIGN=\"CENTER\">");            else                arrStr.push("<P ALIGN=\"LEFT\">");            var addText:String = "";            if ((channel && channel.length > 0) || (srcName && srcName.length > 0))            {                if (formatName)                {                    arrStr.push("<FONT FACE=\"");                    arrStr.push(formatName.font as String);                    arrStr.push("\" SIZE=\"");                    arrStr.push(formatName.size.toString());                    arrStr.push("\" COLOR=\"#");                    arrStr.push((formatName.color as int).toString(16));                    arrStr.push("\">");                }                if (channel && channel.length > 0)                    arrStr.push(channel);                if (srcName && srcName.length > 0)                {                    if (!bSelf)                    {                        arrStr.push("<A HREF=\"event:");                        arrStr.push(srcName + "$" + id);                        arrStr.push("\">");                        arrStr.push(srcName);                        arrStr.push("</A>");                    }                    else                    {                        arrStr.push(srcName);                    }                }                if (dstName && dstName.length > 0)                {                    arrStr.push("悄悄地对");                    if (dstName != "你")                    {                        arrStr.push("<A HREF=\"event:");                        arrStr.push(dstName + "$" + id);                        arrStr.push("\">");                        arrStr.push(dstName);                        arrStr.push("</A>");                    }                    else                        arrStr.push(dstName);                    arrStr.push("说");                }                if (srcName && srcName.length > 0)                    arrStr.push(":");                if (formatName)                    arrStr.push("</FONT>");            }                        if (text)            {                if (formatText)                {                    arrStr.push("<FONT FACE=\"");                    arrStr.push(formatText.font as String);                    arrStr.push("\" SIZE=\"");                    arrStr.push(formatText.size.toString());                    arrStr.push("\" COLOR=\"#");                    arrStr.push((formatText.color as int).toString(16));                    arrStr.push("\">");                }                arrStr.push(text);                if (formatText)                    arrStr.push("</FONT>");            }            arrStr.push("</P>");            //because the carriage return escape character(\r) has some bug in text copying            //so change all of them to newline escape character(\n)                    addText = arrStr.join("");            //addText = addText.split("\r").join("\n");                        var arrHtml:Array = new Array();            arrHtml.push(_txtField.htmlText);            arrHtml.push(addText);            _txtField.htmlText = arrHtml.join("");        }                /**         * replace the textfield&39;s getCharBoundaries method         * get char boundaries in the specify char index         * @param    charIndex         * @return         */        private function getCharBoundaries(charIndex:int):Rectangle        {            var rect:Rectangle = _txtField.getCharBoundaries(charIndex);            return rect;        }                        /**         * recover the default textformat         */        private function recoverDefaultTextFormat():void        {            if (_defaultTextFormat)                 defaultTextFormat = _defaultTextFormat;                    }                /**         * return a textformat for placeholder corresponding to the given width and height.         * @param    width         * @param    height         * @return         */        private function getPlaceholderFormat():TextFormat        {            var format:TextFormat = new TextFormat();            format.font = PLACEHOLDER_FONT;            format.color = PLACEHOLDER_COLOR;            //format.size = height + 2 * _spriteVspace;            format.size = 22;            format.underline = false;                if (_bCenter)                format.align = TextFormatAlign.CENTER;            //format.letterSpacing = 1;                    //format.letterSpacing = width - height - _spriteVspace + _spriteHspace;            return format;        }            }}


?


读书人网 >Flash

热点推荐