在AS3中我们接触到最多的一个类就是Sprite了,该类的名字(Sprite)翻译成中文就是“精灵”的意思(当然,你也可以翻译成“雪碧”,谁让它们同名呢),称该类对精灵自然就称之为精灵的理由,理由之一就是它的很多特性都变化多端,让人难以捉摸。今天我们来揭示其中的一个特性——尺寸。

在一个Sprite对象中,它的尺寸是会自动根据其中的子对象大小来进行调整的,如果你为其中添加一个尺寸为100*100大小的显示对象,则其尺寸就是100*100,若再往里面放入另一个显示对象,则取双方尺寸之和(不包含重叠部分),设这两个显示对象的左边缘和上边缘对齐,第二个显示对象尺寸为50*200,则此时该Sprite对象变成100*200的尺寸:

有时候,我们想把一个Sprite对象约束为某一宽度或者高度,就会显式地设置该Sprite对象的宽度或高度,但是需要注意的是,一旦你手动设置了一个Sprite对象的宽或者高之后,其缩放比scaleX或scaleY就会随之改变:

package
{import flash.display.Sprite;public class Test extends Sprite{private var sp:Sprite = new Sprite();public function Test(){sp.graphics.beginFill(0xff0000);sp.graphics.drawRect(0,0,100,100);sp.graphics.endFill();addChild(sp);sp.width = 50;sp.height = 50;}}
}

结果如图:

我们看到,把原先通过绘图API画出的100*100的矩形显式设置成50*50的尺寸后该Sprite对象的确被缩放到了50*50尺寸,但是其scaleX和scaleY也变成了之前的一半。scaleX和scaleY属性的改变意味着什么?意味着当你往这个Sprite对象中添加进的任何显式对象尺寸都会跟着被“缩放”,这里的缩放为什么要加引号?因为该对象自身的宽、高、缩放比并没有发生改变,但是视觉上看起来它却是被缩放过了。

package
{import flash.display.Shape;import flash.display.Sprite;public class Test extends Sprite{private var sp:Sprite = new Sprite();private var shape:Shape = new Shape();public function Test(){           sp.graphics.beginFill(0xff0000);sp.graphics.drawRect(0,0,100,100);sp.graphics.endFill();addChild(sp);sp.width = 50;sp.height = 50;shape.graphics.beginFill(0x0000ff);shape.graphics.drawRect(0,0,200,50);shape.graphics.endFill();sp.addChild( shape );}}
}

结果如下:

我们看到,虽然sp此时的宽度是50,但是往其中加入一个宽度为200的蓝色矩形后发现该蓝色矩形的宽度并不是我们之前想象中的那样宽度是红色矩形宽的4倍,而只是它的2倍而已,这是因为sp的scaleX为0.5,另一个显示对象被加入进来后宽度就会被“缩放”成原先的一半。但是此“缩放”并非真正缩放了加入sp中的显示对象shape的尺寸,它的尺寸还是200*50,scaleX、scaleY还是1。值得注意的是,sp对象的宽度虽然之前被设置为了50,但是当其中加入了一个超过其原范围的显示对象后,它的宽与高一样是会自动发生改变的。你没有任何办法来阻止一个Sprite对象的“自适应”特性。

这给了我们的启示有两点:

一,在一个缩放过的Sprite对象中,对该对象的所有子显示对象进行的任何位置和尺寸的运算时不需要考虑该Sprite的缩放比。

那么上面这句话是什么意思呢?举个例子吧,若是我们想在一个缩放为原先一半尺寸的Sprite对象sp中添加两个显示对象,一个要把左上角放到sp的中心点,另一个要缩放成sp的四分之一大小。正确的做法如下:

package
{import flash.display.Shape;import flash.display.Sprite;public class Test2 extends Sprite{private var sp:Sprite = new Sprite();private var shape1:Shape;private var shape2:Shape;public function Test2(){sp.graphics.beginFill(0x000000);sp.graphics.drawRect(0,0,600,600);sp.graphics.endFill();addChild(sp);sp.width = 300;sp.height = 300;shape1 = getRectShape(0x0000ff, 100, 100);sp.addChild( shape1 );//将shape1左上角置于sp的中心位置时以其未缩放前的宽高进行计算shape1.x = 300;shape1.y = 300;shape2 = getRectShape(0xff0000, 100, 100);sp.addChild( shape2 );//将shape2缩放为sp的一半的时候以其未缩放前的宽高进行计算shape2.width = 300;shape2.height = 300;}private function getRectShape(color:uint, width:Number, height:Number):Shape{var shape:Shape = new Shape();shape.graphics.beginFill(color);shape.graphics.drawRect(0,0,width,height);shape.graphics.endFill();return shape;}}
}

容易犯的错误是将sp的缩放比加入到运算过程中,将shape1的x,y或者shape2的width和height设置成 150,150就不对了。当对一个scaleX、scaleY不为1的Sprite对象中的子对象进行位置、尺寸运算的时候需要把该Sprite当成未缩放的尺寸来进行计算,切记,切记!最后再考考大家:当把shape2(它原先的x,y都为0)对象的x增加300后,它的左边缘会跑到sp中的什么位置?不给你直接看到答案,先思考一下,若想看到答案,请按住鼠标然后拖动以选中箭头对中的文字。→在sp的中心点←

需要注意的是,虽然shape1,shape2在sp中的x,y位置都可以假设成sp的scaleX、scaleY为1的情况进行计算,但也仅仅是在sp对象内可以这么干,如果需要把shape1,shape2放到屏幕中某个精确位置,就需要使用globalToLocal方法进行坐标系转换:

public class Test2 extends Sprite
{private var sp:Sprite = new Sprite();private var shape1:Shape;private var shape2:Shape;public function Test2(){……sp.addEventListener(MouseEvent.CLICK, onClick);}……private function onClick( e:MouseEvent ):void{var localPos:Point = sp.globalToLocal(new Point(e.stageX, e.stageY));shape1.x = localPos.x;shape1.y = localPos.y;}
}

二,若要固定住一个Sprite对象的大小,必须时刻控制其内部子显示元件的尺寸

对于上面这句话相信应该比较容易理解,介于Sprite对象的”自适应“特性,为了让某个Sprite对象保持固定尺寸的话就不能让其中的某个子对象超出其范围,否则该Sprite对象的宽或者高会发生改变。

比如,我现在要写一个物品视图类ItemView,我想把它的尺寸固定在50 * 50这个样子。在ItemView里面,它的外观是由一个位图对象Bitmap决定的,外部可以通过一个 view 的 set 方法来定义ItemView的外观:

package
{import flash.display.Bitmap;import flash.display.BitmapData;import flash.display.Sprite;public class ItemView extends Sprite{private var _viewBM:Bitmap;public function ItemView(){super();_viewBM = new Bitmap();addChild( _viewBM );}/** 设置外观 */public function set view(value:BitmapData):void{_viewBM.bitmapData = value;_viewBM.width = this.width;_viewBM.height = this.height;}}
}

我不说100%,起码80% - 90%的人会这么写,当外部通过 view = bitmapData 这样的语句传入一个BitmapData对象作为ItemView的外观后会使用this.width和this.height来将_viewBM缩放成固定大小(如50 * 50)。但在实际应用后发现,我传入的位图数据原先是多少大,ItemView就是多少大(比如我传了一个100 * 100的位图数据给ItemView,ItemView就变成了 100 * 100 的大小了),并没有像我预期中的那样让ItemView固定在50 * 50的尺寸。这是为什么呢?首先,让我们加两条trace语句来调试一下,看看数据发生了变化,问题出在哪里:

public function set view(value:BitmapData):void
{trace(this.width, this.height);//输出 50 * 50_viewBM.bitmapData = value;trace(this.width, this.height);//输出 100 * 100_viewBM.width = this.width;_viewBM.height = this.height;
}

很多人一看这两条trace语句的输出结果后就知道了问题的所在,是的,当我改变Sprite对象中的其中一个子显示对象的尺寸之后该Sprite对象自身尺寸也会自动跟着进行调整,这使得我在设置了_viewBM.bitmapData之后,当前Sprite对象的尺寸马上发生了改变,此时的宽高已经与_viewBM的宽高一致,因此你再使用this的宽高来缩放_viewBM的宽高已经无法让_viewBM的尺寸发生改变的了。

那么我们应该怎么做才能抑制住Sprite对象的自适应功能呢(这功能还真TMD让人又爱又恨啊,有没有?!)。像我,习惯在代码中重载Sprite类的width和height的 set 方法来实现固定宽高的控制,我先把外部设置的宽度和高度记录下来,用以在该Sprite对象内部子显示对象尺寸发生改变时用我记录下来的尺寸对其进行缩放:

package
{import flash.display.Bitmap;import flash.display.BitmapData;import flash.display.Sprite;public class ItemView extends Sprite{private var _viewBM:Bitmap;/** 固定宽 */private var _viewW:Number;/** 固定高 */private var _viewH:Number;public function ItemView(){super();_viewBM = new Bitmap();addChild( _viewBM );}/** 设置外观 */public function set view(value:BitmapData):void{_viewBM.bitmapData = value;_viewBM.width = _viewW;_viewBM.height = _viewH;}override public function set width(value:Number):void{_viewW = value;_viewBM.width = value;}override public function set height(value:Number):void{_viewH = value;_viewBM.height = value;}}
}

可以看到,当外部设置的该Sprite对象的width/height时我将其设置的值保存于两个变量_viewW/_viewH当中,之后,每次外部设置了ItemView的外观后尽管_viewBM.bitmapData = value;这句会让Sprite对象自动调整尺寸,但是之后我又取出之前保存的固定长、宽_viewW/_viewH来将它再缩放回来,这样就保证了不管你将ItemView的view属性设置为什么位图数据,它的尺寸始终为一个固定的值。这招对于需要外部加载的素材产生了极大的便利:

package
{import flash.display.Bitmap;import flash.display.Loader;import flash.display.LoaderInfo;import flash.display.Sprite;import flash.events.Event;import flash.net.URLRequest;public class ItemView extends Sprite{private var _viewBM:Bitmap;/** 固定宽 */private var _viewW:Number;/** 固定高 */private var _viewH:Number;public function ItemView(){super();_viewBM = new Bitmap();addChild( _viewBM );}/** 设置外观 */public function loadImg( url:String ):void{var loader:Loader = new Loader();loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);loader.load( new URLRequest( url ) );}private function onComplete( event:Event ):void{_viewBM.bitmapData = ( (event.currentTarget as LoaderInfo).content as Bitmap ).bitmapData;_viewBM.width = _viewW;_viewBM.height = _viewH;}override public function set width(value:Number):void{_viewW = value;_viewBM.width = value;}override public function set height(value:Number):void{_viewH = value;_viewBM.height = value;}}
}

如果你为一个ItemView设置了width和height为一个定值,那么之后你只需要把ItemView所需要使用的图片路径作为参数传入到loadImg方法中去,当素材加载完毕后该素材就会自动被缩放为你之前为ItemView设置的固定尺寸。

Sprite的自适应特性中还有一个不得不注意的隐藏特性,那就是当一个Sprite中没有任何子对象时你设置了它的width或height的话,这个Sprite对象的width、height、scaleX、scaleY都会变成0:

var sp:Sprite = new Sprite();
sp.width = sp.height = 50;
trace(sp.width, sp.height, sp.scaleX, sp.scaleY)//输出:0,0,0,0

光是width和height变成0也就算了,还把scaleX和scaleY给牵扯了进来,这两个缩放值属性一旦变成0,后果可想而知,往该Sprite对象中添加的任何子对象都会看不见了,因为它们被它们的老爸一起带走了 - -!

所以最后提醒一句,不要在Sprite对象中没有东西的时候设置它的尺寸,这样会玩火自焚的,除非你像我上面的代码中写的那样,重载一下Sprite对象的width和height的 set 方法,不是立即改变该Sprite的尺寸,而是把设置的宽、高值保存在一个变量里面,待里面有东西后再进行缩放。

AS3隐藏特性—Sprite对象的尺寸相关推荐

  1. 《Adobe Illustrator CC 2014中文版经典教程(彩色版)》—第2课2.6节隐藏和锁定对象...

    本节书摘来自异步社区<Adobe Illustrator CC 2014中文版经典教程(彩色版)>一书中的第2课2.6节隐藏和锁定对象,作者[美]Brian Wood,更多章节内容可以访问 ...

  2. .NET 5 中的隐藏特性

    转自:hez2010 cnblogs.com/hez2010/p/13963803.html 前言 双十一当天,个人觉得非常香,并且花了 10 分钟时间就把自己的 4 个 .NET Core 3.1 ...

  3. 实例:使用纹理对象创建Sprite对象

    精灵类是Sprite,它的类图如下图所示: Sprite类直接继承了Node类,具有Node基本特征.此外,我们还可以看到Sprite类的派生类有:PhysicsSprite和Skin.Physics ...

  4. JS-面向对象-对象的特性-禁止对象扩展 / 对象的特性-封印对象 / 对象的特性-冻结对象

    对象的特性-禁止对象扩展 <!DOCTYPE html> <html lang="zh"><head><meta charset=&quo ...

  5. CAD编辑器中怎么隐藏图纸中标注的尺寸?

    我们在编辑绘制CAD图纸的时候,通常会对CAD图纸中的内容进行尺寸标注.但是在我们传输CAD图纸的时候,可能为了CAD图纸的简洁明了,而选择隐藏CAD图纸中的标注尺寸.该怎么隐藏CAD图纸中标注的尺寸 ...

  6. EMI/EMC设计讲座--PCB被动组件的隐藏特性解析

    EMI/EMC设计讲座–PCB被动组件的隐藏特性解析 (注,原文档是中国台湾的,经由繁体转简体存在理解误差,请见谅) 传统上,EMC一直被视为"黑色魔术(black magic)" ...

  7. AS3游戏中可视对象上限及位图相关的内存消耗实测

    前些天连续做了一些测试,以加深对AS3的掌握和在项目中对 游戏 性能.效率优化方面的一些处理,有很多测试实际意义不大,都不过是证明一些猜想是正确的,除此没有什么. 但前天进行的一系列测试中,有一些对游 ...

  8. python对象的特性_Python对象的思想和特性,python

    一.面向对象思想 面向对象编程(Object Oriented Programming,简称OOP),是利用"类"和"对象"来创建各种模型来实现对真实世界的描述 ...

  9. HTML5 之 新特性 + 新对象

    HTML5的十大新特性 https://www.cnblogs.com/vicky1018/p/7705223.html Html5--File.FileReader.Blob.Fromdata对象 ...

最新文章

  1. 从Zygote孵化frameworks进程,分析StartActivity流程中intent传递数据的最大值。
  2. java大作业私人管家系统_重庆管家婆软件丨管家婆工贸PRO的E-MES管理详解
  3. 基于Rainbond开发Python云原生应用
  4. 在Visual Studio中一次运行两个项目
  5. 【数据结构】--章节2.3----线性表的链式表示和实现
  6. VS2003项目转VS2008项目
  7. 差分约束——vijos1589
  8. 共享文件夹没有权限访问
  9. 增量式光电编码器原理及其结构
  10. JS 模拟手机页面文件的下拉刷新
  11. 数字图像处理:图像几何变换(Matlab实现几何变换+原理解析
  12. 八月暑期福利,10本Python热门书籍免费送!
  13. mysql内核架构_热血江湖mysql内核技术之门派数据库表结构说明
  14. PyQt5 的textedit下的setPlainText()和setText区别
  15. 离散数学:用python实现关系闭包的计算,即自反、对称与传递
  16. 免费的人事管理软件?好用的人事管理软件有哪些呢?
  17. python3 scrapy爬取智联招聘存mongodb
  18. 【linux驱动】USB子系统分析
  19. Java基础-GUI入门-AWT详解
  20. 构建统一监管制度 加快数据要素立法修法

热门文章

  1. Flipper TR膜张力传感器——简化了测定方法
  2. 北风设计模式课程---解释器模式(Interpreter Pattern)
  3. PHP程序员适合创业吗?
  4. 【算法题解】 Day1 前缀和
  5. Python 数据匹配(dict、map函数)
  6. 华为离职副总裁徐家骏的工作感悟
  7. X-Ways Forensics v20.1
  8. js中Json对象与Json字符串互转(4种转换方式)
  9. 脑力风暴之小毛驴历险记(2)---谁敢动我的金币(下)
  10. 反恐精英永恒python_你知道哪些反常识的知识?