页游聊天模块图文混排解决方案

找了很长时间的聊天模块添加表情的解决方案。综合比较一下,最终选择闪刀浪子的TalkField。

选择它的理由:代码量小,简单易懂,使用方便。可以满足项目需求。

网上提供的其它几种方案,如果不能够熟知其原理,项目出什么问题了,维护起来时比较麻烦的。

预览:

主文档代码:

package
{
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.TextEvent;
    import flash.net.URLRequest;
    import flash.system.ApplicationDomain;
    
    public class Main extends Sprite
    {
        private var _loader:Loader;
        private var _outputText:TalkField;
        private var _inputText:TalkField;
        private var _sendBtn:Button;//发送按钮
        private var _faceBar:MovieClip;
        private var _app:ApplicationDomain;
        
        [Embed(source="face.swf",mimeType="application/octet-stream")]
        public var swfClass:Class;
        
        public function Main()
        {
            _loader = new Loader();
            _loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete);
            //_loader.load(new URLRequest('face.swf'));
            _loader.loadBytes(new swfClass());
            
        }
        
        private function onComplete(evt:Event):void
        {
            _app = (evt.currentTarget as LoaderInfo).applicationDomain;
            var _faceBarClass:Class = _app.getDefinition('faceBar') as Class;
            _faceBar = new _faceBarClass();
            
            initText();
        }
        
        private function initText():void
        {
            _outputText = new TalkField(300,200,_app);
            _outputText.tf.selectable = false;
            this.addChild(_outputText);
            _outputText.x = stage.stageWidth-_outputText.width >> 1;
            _outputText.y = 30;
            _outputText.tf.addEventListener(TextEvent.LINK,onLink);
            
            _inputText = new TalkField(300,26,_app,'input');
            this.addChild(_inputText);
            _inputText.x = stage.stageWidth-_inputText.width >> 1;
            _inputText.y = 280;
            _inputText.setText('输入聊天信息');
            _inputText.tf.restrict = '^/[\u3000]/g';//限制不许输入全角空格
            
            this.addChild(_faceBar);
            _faceBar.x = 220;
            _faceBar.y = _inputText.y - 30;
            _faceBar.addEventListener(MouseEvent.CLICK,onBarClick);
            
            _sendBtn = new Button('发送');
            this.addChild(_sendBtn);
            _sendBtn.x = _inputText.x + _inputText.width + 5;
            _sendBtn.y = _inputText.y;
            _sendBtn.addEventListener(MouseEvent.CLICK,sendMsg);
            
        }
        
        private function onBarClick(evt:MouseEvent):void
        {
            var str:String = evt.target.name.replace(/f/g,'/');
            _inputText.tf.appendText(str);
        }
        
        private function onLink(evt:TextEvent):void
        {
            _inputText.setText(evt.text);
            
        }
        
        private var arr:Array = new Array();
        private function sendMsg(event:MouseEvent):void
        {
            arr.push("/07<a href='event:这是我的姓名'><u>[鬼精灵]</u></a>说:" + _inputText.tf.text + '<br />');
            _outputText.setMultiText(arr);
            _inputText.tf.text = '';
        }
    }
}

闪刀浪子开源类TalkField:

package
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
    import flash.geom.Rectangle;
    import flash.system.ApplicationDomain;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    
    /**
     * 图文显示框
     * @author 闪刀浪子
     * 使用方法:
     */
    public class TalkField extends Sprite
    {
        private var _tf:TextField;
        private var _type:String;
        private var _tfMask:Sprite;
        private var _faceContainer:Sprite;
        
        private var _maskWidth:Number;
        private var _maskHeight:Number;
        
        private var _textFormat:TextFormat;
        private var _leading:Number
        private var _textColor:uint;
        
        private var _appDomain:ApplicationDomain;
        
        /**
         * 构造函数
         * @param    width    图文宽度
         * @param    height  图文框高度
         * @param    leading  显示的文本行的行间距
         * @param    appDomain  包含"facexx"的程序域
         * @param    textColor    默认文本的颜色,如果没有用<font>标签定义颜色,则使用此颜色
         * @param    alpha  图文框的背景透明度
         */
        public function TalkField(Number, height:Number, 
                                  appDomain:ApplicationDomain = null,textType:String = 'dynamic',
                                    leading:Number=2,textColor:uint=0xffffff) 
        {
            trace(TextFieldType.DYNAMIC);
            _maskWidth = width;
            _maskHeight = height;
            _leading = leading;
            _textColor = textColor
            _type = textType;
            _appDomain = appDomain==null?ApplicationDomain.currentDomain:appDomain;
            
            initView()
            initEvent();
        }
        
        private function initView():void
        {
            createBK();
            createMask();
            createTF();
            createFaceContainer();
        }
        
        private function initEvent():void
        {
            addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheelHandler);
        }
        
        private function onMouseWheelHandler(e:MouseEvent):void 
        {
            maskY -= (e.delta * 4.0);
            dispatchEvent(new Event("scroll"));
        }
        
        private function createBK():void
        {
            graphics.beginFill(0, 0.3);
            graphics.drawRect( 0, 0, _maskWidth + 10, _maskHeight + 14);
            graphics.endFill();
        }
        
        private function createMask():void
        {
            _tfMask = new Sprite();
            _tfMask.graphics.beginFill(0x000000);
            _tfMask.graphics.drawRect(0, 0, _maskWidth, _maskHeight);
            _tfMask.graphics.endFill();
            addChild(_tfMask);
        }
        
        private function createTF():void
        {
            _textFormat = new TextFormat;
            _textFormat.color=_textColor;
            _textFormat.size = 12;
            _textFormat.letterSpacing = 0.75;
            _textFormat.leading = _leading;
            
            _tf = new TextField();
            _tf.textColor = 0xffffff;
            _tf.width = _maskWidth;
            _tf.defaultTextFormat = _textFormat;
//            _tf.selectable = false;
            _tf.multiline = true;
            _tf.wordWrap = true;
            _tf.autoSize = "left";
            _tf.type = _type;
            _tf.filters = [new GlowFilter(0x000000, 0.95, 2, 2, 10)];
            _tf.mouseWheelEnabled = false;
            addChild(_tf);
            _tf.mask = _tfMask;
        }
        
        private function createFaceContainer():void
        {
            _faceContainer = new Sprite();
            _faceContainer.scrollRect = new Rectangle(0, 0, _maskWidth, _maskHeight);
            addChild(_faceContainer);
        }
        
        private function clearFaceContain():void
        {
            while (_faceContainer.numChildren > 0)
            {
                _faceContainer.removeChildAt(0);
            }
        }
        
        /**
         * 聊天显示框
         * @param    str 必须为htmlText格式
         */
        public function setText(str:String):void
        {
            _tf.text = "";
            _tf.defaultTextFormat = _textFormat;
            var faceArr:Array = [];
            clearFaceContain();
            
            //保存表情符的编号并替换为空格,此处可以根据你的表情数量来修改正则表达式
            //表情素材的导出类名规则为——face01-face05
            var face:Array = str.match(/\/(0[1-7])/g);
            if (face != null)
            {
                faceArr = faceArr.concat(face);
            }
            //注意这里是将表情编号替换为全角的空格,所以记住你的输入框要禁止玩家输入全角空格
            //需要替换的内容是:*01 - *09
            str = str.replace(/\/(0[1-7])/g, "<font size='24'> </font>");
            _tf.htmlText = str;
            _tf.height;
            
            //记录空格的索引号
            var text:String = _tf.text;
            var indexArr:Array = [];
            for (var index:int = 0; index < text.length; index++)
            {
                if (text.charAt(index) == " ")
                {
                    indexArr.push(index);
                }
            }
            _tf.height;
            for (var j:uint = 0; j < indexArr.length; j++)
            {
                var tempPos:Rectangle = _tf.getCharBoundaries(indexArr[j]);
                var linkClass:Class = _appDomain.getDefinition("face" + faceArr[j].substr(1, 2)) as Class;
                if (linkClass != null&&tempPos!=null)
                {
                    var mc:MovieClip = new linkClass as MovieClip;
                    _faceContainer.addChild(mc);
                    mc.x = tempPos.x;
                    mc.y = tempPos.y+3;
                }
            }
            dispatchEvent(new Event(Event.CHANGE));
        }
        
        /**
         * 设置文本
         * @param    arr 频道数组
         */
        public function setMultiText(arr:Array):void
        {
            if (arr == null) return;
            _tf.text = "";
            _tf.defaultTextFormat = _textFormat;
            var faceArr:Array = [];
            clearFaceContain();
            
            var allStr:String=""
            for (var i:uint = 0; i < arr.length; i++)
            {
                var str:String = arr[i];
                var face:Array = str.match(/\/(0[1-7])/g);
                if (face != null)
                {
                    faceArr = faceArr.concat(face);
                }
                str = str.replace(/\/(0[1-7])/g, "<font size='24'> </font>");
                allStr += str;
            }
            _tf.htmlText = allStr;
            _tf.height;
            
            //记录空格的索引号
            var text:String = _tf.text;
            var indexArr:Array = [];
            for (var index:int = 0; index < text.length; index++)
            {
                if (text.charAt(index) == " ")
                {
                    indexArr.push(index);
                }
            }
            _tf.height;
            for (var j:uint = 0; j < indexArr.length; j++)
            {
                var tempPos:Rectangle = _tf.getCharBoundaries(indexArr[j]);
                var linkClass:Class = _appDomain.getDefinition("face" + faceArr[j].substr(1, 2)) as Class;
                if (linkClass != null&&tempPos!=null)
                {
                    var mc:MovieClip = new linkClass as MovieClip;
                    _faceContainer.addChild(mc);
                    mc.x = tempPos.x;
                    mc.y = tempPos.y+3;
                }
            }
            dispatchEvent(new Event(Event.CHANGE));
        }
        
        /* INTERFACE game.ui.list.IScrollElement */
        
        public function get maskX():Number 
        {
            return _faceContainer.scrollRect.x;
        }
        
        public function set maskX(val:Number):void
        {
            var rec:Rectangle = _faceContainer.scrollRect;
            rec.x = val;
            _tf.x = -val;
            _faceContainer.scrollRect = rec;
        }
        
        public function get maskY():Number 
        {
            return _faceContainer.scrollRect.y;
        }
        
        public function set maskY(val:Number):void
        {
            var rec:Rectangle = _faceContainer.scrollRect;
            if (val < 0) val = 0;
            else if (val > maxScroll) val = maxScroll;
            _tf.y = -val;
            rec.y = val;
            _faceContainer.scrollRect = rec;
        }
        
        public function get minScroll():Number 
        {
            return 0;
        }
        
        public function get maxScroll():Number 
        {
            if (_tf.height <= _tfMask.height) return 0;
            else return _tf.height - _tfMask.height;
        }
        
        public function get tf():TextField
        {
            return _tf;
        }
    }
}
原文地址:https://www.cnblogs.com/louissong/p/LouisSong.html