用egret也有一段时间了,记录一下遇到的bug和流水账。
BUG类
1 Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
egret 2.5 里面将WebImageLoader的crossOrigin默认值设置为anonymous就可以了
心得:
1 关闭列表的滚动:比较hack的做法
var skin = this.list.skin; var scroller:egret.gui.Scroller = skin._elementsContent[0]; if( scroller != null) scroller.verticalScrollPolicy = "off";
2 监听列表的滚动事件:
这个找了很久
this.list.dataGroup.addEventListener(egret.gui.PropertyChangeEvent.PROPERTY_CHANGE,this.onListTouchEnd, this); private onListTouchEnd(evt:egret.gui.PropertyChangeEvent){ var newPos:number = evt.newValue; var referPos:number = this.list.dataGroup.scrollRect.bottom-this.list.dataGroup.height; if( evt.property == "verticalScrollPosition" && referPos - newPos <= 10){ //todo dosomething } }
工具:
1 抽屉效果
原理: Tween + mask实现
例如对显示对象d实现抽屉效果:
var tw:egret.Tween = egret.Tween.get(this.d,{onChange:this.updateMask,onChangeObj:this},null,true); this.maskForD = new egret.Rectangle(0,0,0,60);
private updateMask(){ var showWidth:number; if( this.isLeft){ showWidth = 420-(this.itemGroup.x-20); }else{ showWidth = 420 - this.itemGroup.x; } this.maskForD.width = showWidth; this.d.mask = this.maskForItemGroup; }
2 帧事件的管理
沿用as的习惯,全局只有一个帧事件。
/** * Created by DukeCrushIt on 2015/8/5. */ module game { export class FrameMgr extends egret.HashObject { public constructor() { super(); this.items = []; this.itemMap = {}; } public itemMap:Object; private items:FrameItem[]; private stage:egret.Stage; public referTime:number; public initStage(stage:egret.Stage){ this.stage = stage; this.stage.addEventListener(egret.Event.ENTER_FRAME,this.update, this); this.referTime = egret.getTimer(); } public update(evt:egret.Event){ var temp:number = egret.getTimer(); var delta:number = temp - this.referTime; var len:number = this.items.length; var item:FrameItem; for(var idx = len-1; idx >= 0; idx--){ item = this.items[idx]; item.callFun.call(item.callObj,delta); } this.referTime = temp; Model.SYSTIME += delta; } public addControll(item:FrameItem){ if( this.items.indexOf(item) == -1){ this.items.push(item); this.itemMap[item.callObj.name] = item; } } public delController(name:string){ if( this.items.length == 0 ) return; var item:FrameItem = this.itemMap[name]; if( item != null && item != undefined){ var idx:number = this.items.indexOf(item); if(idx != -1){ this.items.splice(idx,1); } } delete this.itemMap[name]; } public isUnderControl(name:string):boolean{ return this.itemMap[name] != undefined && this.itemMap[name] != null; } public pause(){ this.stage.removeEventListener(egret.Event.ENTER_FRAME,this.update, this); } public resume(){ this.referTime = egret.getTimer(); this.stage.addEventListener(egret.Event.ENTER_FRAME,this.update, this); } private static _instance:FrameMgr; public static getInstance():FrameMgr{ if( FrameMgr._instance == null) FrameMgr._instance = new game.FrameMgr(); return FrameMgr._instance; } } }
配合这个使用:
/** * Created by DukeCrushIt on 2015/8/5. */ module game { export class FrameItem extends egret.HashObject { public callObj:any; public callFun:Function; public constructor() { super(); } } }
3 简单的位移补间
用自带的Tween效率不是很好,于是自己实现了一个,如下:
/** * Created by DukeCrushIt on 2015/8/5. */ module game{ export class MoveMgr extends egret.HashObject{ public name:string; public frameItem:FrameItem; public constructor(){ super(); this.items = []; this.name = "movemgr"; this.frameItem = new game.FrameItem(); this.frameItem.callObj = this; this.frameItem.callFun = this.update; FrameMgr.getInstance().addControll(this.frameItem); } private items:MoveItem[]; private spareTime:number = 10; public update(deltaTime:number){ if( this.items.length == 0) return; var itemLen:number = this.items.length - 1; var item:MoveItem; var startTime = egret.getTimer(); var gap:number; for(var i = itemLen; i >= 0 ; i--){ item = this.items[i]; item.update(deltaTime); gap = egret.getTimer() - startTime; if( gap >= this.spareTime) break; } } public addItem(item:MoveItem){ if( this.items.indexOf(item) == -1){ this.items.push(item); } } public delItem(item:MoveItem){ var idx:number = this.items.indexOf(item); if( idx != -1){ this.items.splice(idx, 1); } MoveMgr.reclaim(item); } public removeAllHairItems(){ var len:number = this.items.length; var item:MoveItem; var disObj:egret.DisplayObject; for( var idx = len - 1; idx >=0 ; idx--){ item = this.items[idx]; disObj = item.disObject; if( disObj instanceof Hair){ item.finish(); } } } public finish(){ var itemLen:number = this.items.length - 1; if( itemLen == -1 ) return; var item:MoveItem; for(var i = itemLen; i >= 0 ; i--){ item = this.items[i]; item.finish(); } } private static _cache:MoveItem[]=[]; public static reclaim(item:MoveItem){ if( MoveMgr._cache.indexOf(item) == -1) MoveMgr._cache.push(item); } public static produce():MoveItem{ if(MoveMgr._cache.length!=0) return MoveMgr._cache.pop(); return new MoveItem(); } private static _instance:MoveMgr; public static getInstance():MoveMgr{ if( MoveMgr._instance == null) MoveMgr._instance = new game.MoveMgr(); return MoveMgr._instance; } } }
需要配合这个使用:
/** * Created by DukeCrushIt on 2015/8/5. */ module game{ export class MoveItem extends egret.HashObject{ public disObject:egret.DisplayObject; private gapX:number; private gapY:number; public targetX:number; public targetY:number; public duration:number; public past:number; private roll:boolean=false; public callBackObj:any; public callBackFun:Function; public constructor(){ super(); } public init(disObject:egret.DisplayObject,targetX:number,targetY:number,duration:number,cbObj:any=null,cbFun:Function=null,roll:boolean=false){ this.disObject = disObject; this.targetX = targetX; this.gapX = targetX - disObject.x; this.targetY = targetY; this.gapY = targetY - disObject.y; this.duration = duration; this.past = 0; this.callBackObj = cbObj; this.callBackFun = cbFun; this.roll = roll; } public update(deltaTime:number){ this.past += deltaTime; if( this.past < this.duration){ var refer:number = deltaTime/this.duration; this.disObject.x += this.gapX*refer; this.disObject.y += this.gapY*refer; if( this.roll){ this.disObject.rotation += this.gapX > 0 ? 3 : -3; } }else{ this.disObject.x = this.targetX; this.disObject.y = this.targetY; if( this.callBackObj!= null && this.callBackObj != null) this.callBackFun.call(this.callBackObj); MoveMgr.getInstance().delItem(this); } if( this.disObject.parent == null){ MoveMgr.getInstance().delItem(this); } } public finish(){ if(this.disObject != null){ this.disObject.x = this.targetX; this.disObject.y = this.targetY; } this.roll = false; MoveMgr.getInstance().delItem(this); } } }
4 做了一个简单的重力系统,如下:
/** * Created by DukeCrushIt on 2015/7/30. */ module dukeutil{ export class GravitySystem extends egret.HashObject { public gravity:number = 0.98; private items:GravityItem[] = []; private itemMap:Object = {}; private frameItem:game.FrameItem; public name:string; public constructor(){ super(); this.name = "gravitysystem"; this.frameItem = new game.FrameItem(); this.frameItem.callFun = this.update; this.frameItem.callObj = this; game.FrameMgr.getInstance().addControll(this.frameItem); } public addItem(item:GravityItem){ if( this.items.indexOf(item) == -1 ){ this.items.push(item); this.itemMap[item.displayObject.name] = item; } } public contains(name:string):boolean{ return this.itemMap[name] != undefined; } private spareTime:number = 10; private update(delata:number){ var startTime = egret.getTimer(); var gap:number; var len:number = this.items.length; var idx:number; var item:GravityItem; var displayObject:egret.DisplayObject; for(idx = len-1; idx >= 0; idx--){ item = this.items[idx]; displayObject = item.displayObject; if( item.phase == 0){ displayObject.x+=item.currentSpeedX; item.currentSpeedY += this.gravity; displayObject.y += item.currentSpeedY; if( item.doublePhase && displayObject.y >= item.targetY){ item.phase = 1; item.currentSpeedX = item.currentSpeedX*0.8; }else if( !item.doublePhase && (item.currentSpeedY < 1 && item.currentSpeedY > -1)){ delete this.itemMap[item.displayObject.name]; this.items.splice(idx,1); if( item.overCall != null && item.overCallObj != null) item.overCall.call(item.overCallObj); item.reset(); GravitySystem.reclaim(item); } }else{ item.step++; item.currentSpeedX = item.currentSpeedX*0.9; displayObject.x+=item.currentSpeedX; //if( item.currentSpeedX > 0){ // displayObject.rotation+=2; //}else{ // displayObject.rotation-=2; //} if( item.step >= 30){ delete this.itemMap[item.displayObject.name]; this.items.splice(idx,1); if( item.overCall != null && item.overCallObj != null) item.overCall.call(item.overCallObj); item.reset(); GravitySystem.reclaim(item); } } if( displayObject.x <= 0 || displayObject.x >= game.GameConst.StageW){ item.currentSpeedX = -item.currentSpeedX; } gap = egret.getTimer() - startTime; if( gap >= this.spareTime) break; } } private static _itemCache:GravityItem[] = []; public static produce():GravityItem{ if( GravitySystem._itemCache.length != 0) return GravitySystem._itemCache.pop(); return new GravityItem(); } public static reclaim(item:GravityItem){ if( GravitySystem._itemCache.indexOf(item) == -1) GravitySystem._itemCache.push(item); } private static _instance:GravitySystem; public static getInstance():GravitySystem{ if( GravitySystem._instance == null ) GravitySystem._instance = new dukeutil.GravitySystem(); return GravitySystem._instance; } } }
配合使用的类:
/** * Created by DukeCrushIt on 2015/7/30. */ module dukeutil{ export class GravityItem extends egret.HashObject{ public phase:number=0;//0 gravity 1 roll to public doublePhase:boolean = true; public displayObject:egret.DisplayObject; public targetY:number; public currentSpeedX:number; public currentSpeedY:number; public step:number=0; public overCallObj:any; public overCall:Function; public constructor(){ super(); } public reset(){ this.phase = 0; this.step = 0; this.doublePhase = true; this.overCall = null; this.overCallObj = null; } } }
2016-1-8:
egret.gui.BitmapLabel自定义font不能居中问题
在egret wing里面设置textAlign是通过setStyle去生效的,这个没有附加到BitmapLabel._bitmapText上去,因为BitmapLabel._bitmapText是通过_addToDisplayList()的方式去加上去的,这是官方比较hack的方式去将非UIComponent的元件加到gui显示列表里面去,所以这个style是无法生效的,我的解决方法很简单,直接给BitmapLabel加textAlign的setter和getter,然后在commiteProperties()里面判断textAlign是否有变更,有的话就赋值给BitmapLabel._bitmapText.textAlign,这个方法只能在程序里面手动去设置,egret wing里面的设置还是无效的,问题解决,修改后的BitmapLabel.ts如下:
1 ////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2014-2015, Egret Technology Inc. 4 // All rights reserved. 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of the Egret nor the 14 // names of its contributors may be used to endorse or promote products 15 // derived from this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 18 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 // IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, 23 // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 // 28 ////////////////////////////////////////////////////////////////////////////////////// 29 30 31 module egret.gui { 32 33 /** 34 * @class egret.gui.BitmapLabel 35 * @classdesc 36 * 一行或多行不可编辑的位图文本控件 37 * @extends egret.gui.UIComponent 38 */ 39 export class BitmapLabel extends UIComponent implements IDisplayText { 40 41 private _bitmapText:BitmapText = null; 42 43 /** 44 * @method egret.gui.Label#constructor 45 */ 46 public constructor() { 47 super(); 48 this.addEventListener(UIEvent.UPDATE_COMPLETE, this.updateCompleteHandler, this); 49 } 50 51 /** 52 * 一个验证阶段完成 53 */ 54 private updateCompleteHandler(event:UIEvent):void { 55 this.lastUnscaledWidth = NaN; 56 } 57 58 private _textChanged:boolean = false; 59 private _text:string = ""; 60 /** 61 * @member egret.gui.BitmapLabel#text 62 * 设置或获取显示文本 63 */ 64 public set text(value:string) { 65 if (this._text == value) 66 return; 67 this._text = value; 68 this._textChanged = true; 69 this.invalidateProperties(); 70 this.invalidateSize(); 71 this.invalidateDisplayList(); 72 } 73 74 public get text():string { 75 return this._text; 76 } 77 78 private fontChanged:boolean = false; 79 80 public _font:any; 81 /** 82 * 位图字体标识符,可以是BitmapFont对象或者在资源表中的key。 83 * @member egret.gui.BitmapLabel#font 84 */ 85 public get font():any { 86 return this._font; 87 } 88 89 public set font(value:any) { 90 if (this._font == value) 91 return; 92 this._font = value; 93 if (this.createChildrenCalled) { 94 this.parseFont(); 95 } 96 else { 97 this.fontChanged = true; 98 } 99 this.invalidateProperties(); 100 this.invalidateSize(); 101 this.invalidateDisplayList(); 102 } 103 104 private _isLetterSpacingChanged:boolean = false; 105 public _letterSpacing:number = 0; 106 /** 107 * 字符之间的距离 108 * @default 0 109 * @param value 110 */ 111 public set letterSpacing(value:number) { 112 this._setLetterSpacing(value); 113 } 114 115 public _setLetterSpacing(value:number):void { 116 this._letterSpacing = value; 117 118 this._isLetterSpacingChanged = true; 119 this.invalidateProperties(); 120 this.invalidateSize(); 121 this.invalidateDisplayList(); 122 } 123 124 public get letterSpacing():number { 125 return this._letterSpacing; 126 } 127 128 private _isTextAlignChanged:boolean = false; 129 public _textAlign:string = "left"; 130 /** 131 * 字符之间的距离 132 * @default 0 133 * @param value 134 */ 135 public set textAlign(value:string) { 136 this._settextAlign(value); 137 } 138 139 public _settextAlign(value:string):void { 140 this._textAlign = value; 141 142 this._isTextAlignChanged = true; 143 this.invalidateProperties(); 144 this.invalidateSize(); 145 this.invalidateDisplayList(); 146 } 147 148 public get textAlign():string { 149 return this._textAlign; 150 } 151 152 private _isLineSpacingChanged:boolean = false; 153 public _lineSpacing:number = 0; 154 /** 155 * 行与行之间的距离 156 * @default 0 157 * @param value 158 */ 159 public set lineSpacing(value:number) { 160 this._setLineSpacing(value); 161 } 162 163 public _setLineSpacing(value:number):void { 164 this._lineSpacing = value; 165 166 this._isLineSpacingChanged = true; 167 this.invalidateProperties(); 168 this.invalidateSize(); 169 this.invalidateDisplayList(); 170 } 171 172 public get lineSpacing():number { 173 return this._lineSpacing; 174 } 175 176 private createChildrenCalled:boolean = false; 177 178 /** 179 * 创建子对象 180 */ 181 public createChildren():void { 182 super.createChildren(); 183 if (!this._bitmapText) { 184 this.checkBitmapText(); 185 } 186 if (this.fontChanged) { 187 this.parseFont(); 188 } 189 this.createChildrenCalled = true; 190 } 191 192 /** 193 * 皮肤解析适配器 194 */ 195 private static assetAdapter:IAssetAdapter; 196 197 /** 198 * 解析source 199 */ 200 private parseFont():void { 201 this.fontChanged = false; 202 var adapter:IAssetAdapter = BitmapLabel.assetAdapter; 203 if (!adapter) { 204 adapter = this.getAdapter(); 205 } 206 if (!this._font) { 207 this.onFontChanged(null, null); 208 } 209 else { 210 adapter.getAsset(this._font, this.onFontChanged, this, null); 211 } 212 } 213 214 /** 215 * 获取资源适配器 216 */ 217 private getAdapter():IAssetAdapter { 218 var adapter:IAssetAdapter; 219 try { 220 adapter = $getAdapter("egret.gui.IAssetAdapter"); 221 } 222 catch (e) { 223 adapter = new DefaultAssetAdapter(); 224 } 225 BitmapLabel.assetAdapter = adapter; 226 return adapter; 227 } 228 229 /** 230 * 皮肤发生改变 231 */ 232 private onFontChanged(bitmapFont:any, font:any):void { 233 if (font !== this._font) 234 return; 235 this._bitmapText.font = bitmapFont; 236 this.invalidateSize(); 237 this.invalidateDisplayList(); 238 } 239 240 241 /** 242 * 上一次测量的宽度 243 */ 244 private lastUnscaledWidth:number = NaN; 245 246 private _padding:number = 0; 247 /** 248 * 四个边缘的共同内边距。若单独设置了任一边缘的内边距,则该边缘的内边距以单独设置的值为准。 249 * 此属性主要用于快速设置多个边缘的相同内边距。默认值:0。 250 * @member egret.gui.BitmapLabel#padding 251 */ 252 public get padding():number { 253 return this._padding; 254 } 255 256 public set padding(value:number) { 257 if (this._padding == value) 258 return; 259 this._padding = value; 260 this.invalidateSize(); 261 this.invalidateDisplayList(); 262 } 263 264 private _paddingLeft:number = NaN; 265 /** 266 * 文字距离左边缘的空白像素,若为NaN将使用padding的值,默认值:NaN。 267 * @member egret.gui.BitmapLabel#paddingLeft 268 */ 269 public get paddingLeft():number { 270 return this._paddingLeft; 271 } 272 273 public set paddingLeft(value:number) { 274 if (this._paddingLeft == value) 275 return; 276 277 this._paddingLeft = value; 278 this.invalidateSize(); 279 this.invalidateDisplayList(); 280 } 281 282 /** 283 * 284 * @type {number} 285 * @private 286 */ 287 private _paddingRight:number = NaN; 288 /** 289 * 文字距离右边缘的空白像素,若为NaN将使用padding的值,默认值:NaN。 290 * @member egret.gui.BitmapLabel#paddingRight 291 */ 292 public get paddingRight():number { 293 return this._paddingRight; 294 } 295 296 public set paddingRight(value:number) { 297 if (this._paddingRight == value) 298 return; 299 300 this._paddingRight = value; 301 this.invalidateSize(); 302 this.invalidateDisplayList(); 303 } 304 305 /** 306 * 307 * @type {number} 308 * @private 309 */ 310 private _paddingTop:number = NaN; 311 /** 312 * 文字距离顶部边缘的空白像素,若为NaN将使用padding的值,默认值:NaN。 313 * @member egret.gui.BitmapLabel#paddingTop 314 */ 315 public get paddingTop():number { 316 return this._paddingTop; 317 } 318 319 public set paddingTop(value:number) { 320 if (this._paddingTop == value) 321 return; 322 323 this._paddingTop = value; 324 this.invalidateSize(); 325 this.invalidateDisplayList(); 326 } 327 328 /** 329 * 330 * @type {number} 331 * @private 332 */ 333 private _paddingBottom:number = NaN; 334 /** 335 * 文字距离底部边缘的空白像素,若为NaN将使用padding的值,默认值:NaN。 336 * @member egret.gui.BitmapLabel#paddingBottom 337 */ 338 public get paddingBottom():number { 339 return this._paddingBottom; 340 } 341 342 public set paddingBottom(value:number) { 343 if (this._paddingBottom == value) 344 return; 345 346 this._paddingBottom = value; 347 this.invalidateSize(); 348 this.invalidateDisplayList(); 349 } 350 351 /** 352 * 计算 容器默认大小的最小值和最大值 353 * @method egret.gui.BitmapLabel#measure 354 */ 355 public measure():void { 356 //先提交属性,防止样式发生改变导致的测量不准确问题。 357 if (this._UIC_Props_._invalidatePropertiesFlag) 358 this.validateProperties(); 359 if (this.isSpecialCase()) { 360 if (isNaN(this.lastUnscaledWidth)) { 361 this._UIC_Props_._oldPreferWidth = NaN; 362 this._UIC_Props_._oldPreferHeight = NaN; 363 } 364 else { 365 this.measureUsingWidth(this.lastUnscaledWidth); 366 return; 367 } 368 } 369 370 var availableWidth:number; 371 372 if (!isNaN(this.$getExplicitWidth())) { 373 availableWidth = this.$getExplicitWidth(); 374 } 375 else if (this.maxWidth != 10000) 376 availableWidth = this.maxWidth; 377 378 this.measureUsingWidth(availableWidth); 379 } 380 381 /** 382 * 特殊情况,组件尺寸由父级决定,要等到父级UpdateDisplayList的阶段才能测量 383 */ 384 private isSpecialCase():boolean { 385 return (!isNaN(this.percentWidth) || (!isNaN(this.left) && !isNaN(this.right))) && 386 isNaN(this.$getExplicitWidth()) && 387 isNaN(this.percentHeight); 388 } 389 390 /** 391 * 使用指定的宽度进行测量 392 */ 393 private measureUsingWidth(w:number):void { 394 if (this._textChanged) { 395 this._bitmapText.text = this._text; 396 } 397 398 if (this._isLetterSpacingChanged) { 399 this._bitmapText.letterSpacing = this._letterSpacing; 400 } 401 if (this._isLineSpacingChanged) { 402 this._bitmapText.lineSpacing = this._lineSpacing; 403 } 404 if( this._isTextAlignChanged){ 405 this._bitmapText.textAlign = this._textAlign; 406 } 407 408 var padding:number = isNaN(this._padding) ? 0 : this._padding; 409 var paddingL:number = isNaN(this._paddingLeft) ? padding : this._paddingLeft; 410 var paddingR:number = isNaN(this._paddingRight) ? padding : this._paddingRight; 411 var paddingT:number = isNaN(this._paddingTop) ? padding : this._paddingTop; 412 var paddingB:number = isNaN(this._paddingBottom) ? padding : this._paddingBottom; 413 414 this._bitmapText.width = NaN; 415 this._bitmapText.height = NaN; 416 if (!isNaN(w)) { 417 this._bitmapText.width = w - paddingL - paddingR; 418 this.measuredWidth = Math.ceil(this._bitmapText.width); 419 this.measuredHeight = Math.ceil(this._bitmapText.height); 420 } 421 else { 422 this.measuredWidth = Math.ceil(this._bitmapText.width); 423 this.measuredHeight = Math.ceil(this._bitmapText.height); 424 } 425 this.measuredWidth += paddingL + paddingR; 426 this.measuredHeight += paddingT + paddingB; 427 428 } 429 430 /** 431 * 通过设置此容器子项的位置和大小来响应大小更改 432 * @method egret.gui.BitmapLabel#updateDisplayList 433 * @param unscaledWidth {number} 434 * @param unscaledHeight {number} 435 */ 436 public updateDisplayList(unscaledWidth:number, unscaledHeight:number):void { 437 super.updateDisplayList(unscaledWidth, unscaledHeight); 438 if (!this._bitmapText) 439 return; 440 var padding:number = isNaN(this._padding) ? 0 : this._padding; 441 var paddingL:number = isNaN(this._paddingLeft) ? padding : this._paddingLeft; 442 var paddingR:number = isNaN(this._paddingRight) ? padding : this._paddingRight; 443 var paddingT:number = isNaN(this._paddingTop) ? padding : this._paddingTop; 444 var paddingB:number = isNaN(this._paddingBottom) ? padding : this._paddingBottom; 445 446 this._bitmapText.x = paddingL; 447 this._bitmapText.y = paddingT; 448 if (this.isSpecialCase()) { 449 var firstTime:boolean = isNaN(this.lastUnscaledWidth) || 450 this.lastUnscaledWidth != unscaledWidth; 451 this.lastUnscaledWidth = unscaledWidth; 452 if (firstTime) { 453 this._UIC_Props_._oldPreferWidth = NaN; 454 this._UIC_Props_._oldPreferHeight = NaN; 455 this.invalidateSize(); 456 return; 457 } 458 } 459 //防止在父级validateDisplayList()阶段改变的text属性值, 460 //接下来直接调用自身的updateDisplayList()而没有经过measure(),使用的测量尺寸是上一次的错误值。 461 if (this._UIC_Props_._invalidateSizeFlag) 462 this.validateSize(); 463 464 if (!this._bitmapText.visible)//解决初始化时文本闪烁问题 465 this._bitmapText.visible = true; 466 467 this._bitmapText.width = unscaledWidth - paddingL - paddingR; 468 var unscaledTextHeight:number = unscaledHeight - paddingT - paddingB; 469 this._bitmapText.height = unscaledTextHeight; 470 471 } 472 473 private checkBitmapText() { 474 if (this._bitmapText) 475 return; 476 this._bitmapText = new BitmapText(); 477 this._bitmapText.text = this._text; 478 this._bitmapText.letterSpacing = this._letterSpacing; 479 this._bitmapText.lineSpacing = this._lineSpacing; 480 this._bitmapText.textAlign = this._textAlign; 481 this._textChanged = false; 482 this._isLetterSpacingChanged = false; 483 this._isLineSpacingChanged = false; 484 this._isTextAlignChanged = false; 485 this._addToDisplayList(this._bitmapText); 486 } 487 488 /** 489 * 处理对组件设置的属性 490 */ 491 public commitProperties():void { 492 super.commitProperties(); 493 494 if (!this._bitmapText) { 495 this.checkBitmapText(); 496 } 497 if (this._textChanged) { 498 this._bitmapText.text = this._text; 499 this._textChanged = false; 500 } 501 if (this._isLetterSpacingChanged) { 502 this._bitmapText.letterSpacing = this._letterSpacing; 503 this._isLetterSpacingChanged = false; 504 } 505 if (this._isLineSpacingChanged) { 506 this._bitmapText.lineSpacing = this._lineSpacing; 507 this._isLineSpacingChanged = false; 508 } 509 if (this._isTextAlignChanged) { 510 this._bitmapText.textAlign = this._textAlign; 511 this._isTextAlignChanged = false; 512 } 513 } 514 515 } 516 }
Sound.play()循环播放导致声音重复加载的问题
产生的原因是HtmlSoundChannel.ts在播放完成的时候,判断到loops的时候,直接重新this.audio.load(),然后浏览器去进行了加载,至于浏览器为什么不是从缓存里面去加载而是去服务器上加载,我就不知道了,我只知道,判断一下然后去确定是否要去加载,治愈官方说的有的手机会播放不了,对于大型游戏,例如我们项目来说,其实声音在大部分机型上能播放就可以了,最起码我是这么认为的:
1 ////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2014-2015, Egret Technology Inc. 4 // All rights reserved. 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of the Egret nor the 14 // names of its contributors may be used to endorse or promote products 15 // derived from this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 18 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 // IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, 23 // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 // 28 ////////////////////////////////////////////////////////////////////////////////////// 29 30 module egret.web { 31 32 /** 33 * @private 34 * @inheritDoc 35 */ 36 export class HtmlSoundChannel extends egret.EventDispatcher implements egret.SoundChannel { 37 38 39 /** 40 * @private 41 */ 42 $url:string; 43 /** 44 * @private 45 */ 46 $loops:number; 47 /** 48 * @private 49 */ 50 $startTime:number = 0; 51 /** 52 * @private 53 */ 54 private audio:HTMLAudioElement = null; 55 56 //声音是否已经播放完成 57 private isStopped:boolean = false; 58 59 /** 60 * @private 61 */ 62 constructor(audio:HTMLAudioElement) { 63 super(); 64 audio.addEventListener("ended", this.onPlayEnd); 65 this.audio = audio; 66 } 67 68 $play():void { 69 if (this.isStopped) { 70 egret.$error(1036); 71 return; 72 } 73 74 try { 75 this.audio.currentTime = this.$startTime; 76 } 77 catch (e) { 78 79 } 80 finally { 81 this.audio.play(); 82 } 83 } 84 85 /** 86 * @private 87 */ 88 private onPlayEnd = () => { 89 if (this.$loops == 1) { 90 this.stop(); 91 92 this.dispatchEventWith(egret.Event.SOUND_COMPLETE); 93 return; 94 } 95 96 if (this.$loops > 0) { 97 this.$loops--; 98 } 99 100 ///////////// 101 if( !this.audio.ended) 102 this.audio.load(); 103 this.$play(); 104 }; 105 106 /** 107 * @private 108 * @inheritDoc 109 */ 110 public stop() { 111 if (!this.audio) 112 return; 113 var audio = this.audio; 114 audio.pause(); 115 audio.removeEventListener("ended", this.onPlayEnd); 116 this.audio = null; 117 118 HtmlSound.$recycle(this.$url, audio); 119 } 120 121 /** 122 * @private 123 * @inheritDoc 124 */ 125 public get volume():number { 126 if (!this.audio) 127 return 1; 128 return this.audio.volume; 129 } 130 131 /** 132 * @inheritDoc 133 */ 134 public set volume(value:number) { 135 if (this.isStopped) { 136 egret.$error(1036); 137 return; 138 } 139 140 if (!this.audio) 141 return; 142 this.audio.volume = value; 143 } 144 145 /** 146 * @private 147 * @inheritDoc 148 */ 149 public get position():number { 150 if (!this.audio) 151 return 0; 152 return this.audio.currentTime; 153 } 154 } 155 }
QQ玩吧声音加载和播放问题:
Android QQ玩吧的页面如果有嵌入jsbridge.js的话,egret会判断是否是玩吧,时候有jsbridge里面的接口,有的话会强制使用相对路径,详见HtmlCapbility搜索"wanba"就可以看到了,此时玩吧会使用他们的audio播放程序去加载和播放audio,cdn以及绝对路径都会没有用,resource一定要存放在代码的相对根目录下才能用。
所有细节可以参考:HtmlCapability以及QQSound中参考
解决方法很简单,去掉页面里面的jsbridge.js的嵌入,其实这个js文件没有什么用,去掉后android上QQ玩吧会默认使用egret.HtmlSound去播放声音