使用滤镜时要记住几个导致混淆或问题的潜在根源。
滤镜和位图缓存
若要对显示对象应用滤镜,必须启用该对象的位图缓存。对其
cacheAsBitmap
属性设置为
false
的显示对象应用滤镜时,该对象的
cacheAsBitmap
属性会自动设置为
true
。如果稍后删除了显示对象的所有滤镜,则
cacheAsBitmap
属性会重置为最后设置的值。
在运行时更改滤镜
如果显示对象已应用了一个或多个滤镜,则不能通过在
filters
属性数组中添加或删除滤镜来更改滤镜组。若要添加或更改要应用的滤镜组,必须对单独的数组进行更改,然后将该数组分配给显示对象的 filters 属性以对该对象应用滤镜。执行此操作最简单方法是将
filters
属性数组读入 Array 变量,然后对此临时数组进行修改。然后,将此数组重新分配回显示对象的
filters
属性。在较复杂的情况下,可能需要保留一个单独的主滤镜数组。可以对该主滤镜数组进行任何更改,并在每次更改后将该主数组重新分配给显示对象的
filters
属性。
添加其他滤镜
下面的代码演示向已应用一个或多个滤镜的显示对象添加其他滤镜的过程。首先,对名为
myDisplayObject
的显示对象应用发光滤镜,然后,在单击该显示对象时,调用
addFilters()
函数。在此函数中,另有两个滤镜应用于
myDisplayObject
:
import flash.events.MouseEvent;
import flash.filters.*;
myDisplayObject.filters = [new GlowFilter()];
function addFilters(event:MouseEvent):void
{
// Make a copy of the filters array.
var filtersCopy:Array = myDisplayObject.filters;
// Make desired changes to the filters (in this case, adding filters).
filtersCopy.push(new BlurFilter());
filtersCopy.push(new DropShadowFilter());
// Apply the changes by reassigning the array to the filters property.
myDisplayObject.filters = filtersCopy;
}
myDisplayObject.addEventListener(MouseEvent.CLICK, addFilters);
从一组滤镜中删除一个滤镜
如果显示对象已经应用了多个滤镜,您希望删除其中的一个滤镜并希望其他滤镜继续应用于该对象,请将这些滤镜复制到一个临时数组中,从该数组中删除不需要的滤镜,然后将该临时数组重新分配给该显示对象的
filters
属性。
检索值和删除数组元素
一节介绍了从任意数组删除一个或多个元素的几种方法。
最简单的情况是删除对象上最顶层的滤镜(最后一个应用于对象的滤镜)。可以使用 Array 类的
pop()
方法从数组中删除滤镜:
// Example of removing the top-most filter from a display object
// named "filteredObject".
var tempFilters:Array = filteredObject.filters;
// Remove the last element from the Array (the top-most filter).
tempFilters.pop();
// Apply the new set of filters to the display object.
filteredObject.filters = tempFilters;
同样,若要删除最底层的滤镜(第一个应用于对象的滤镜),也可以使用相同的代码,不过需要用 Array 类的
shift()
方法替换
pop()
方法。
若要从滤镜数组的中间删除滤镜(假定该数组有两个以上的滤镜),则可以使用
splice()
方法。您必须知道要删除的滤镜的索引(在数组中的位置)。例如,下面的代码从显示对象中删除第二个滤镜(索引 1 处的滤镜):
// Example of removing a filter from the middle of a stack of filters
// applied to a display object named "filteredObject".
var tempFilters:Array = filteredObject.filters;
// Remove the second filter from the array. It's the item at index 1
// because Array indexes start from 0.
// The first "1" indicates the index of the filter to remove; the
// second "1" indicates how many elements to remove.
tempFilters.splice(1, 1);
// Apply the new set of filters to the display object.
filteredObject.filters = tempFilters;
确定滤镜索引
您需要知道要从数组中删除哪个滤镜,才能确定该滤镜的索引。您必须知道(根据应用程序的设计方式)或计算出要删除的滤镜的索引。
最佳方法是通过设计应用程序,确保要删除的滤镜始终位于滤镜组中的同一位置。例如,如果有一个显示对象先后应用了卷积滤镜和投影滤镜,您希望删除投影滤镜而保留卷积滤镜,由于滤镜位于已知位置(最顶层的滤镜),因此您可以提前知道应使用哪种 Array 方法(在本例中,使用
Array.pop()
删除投影滤镜)。
如果您要删除的滤镜始终属于某个特定类型,但不一定总在滤镜组中的同一位置,那么您可以检查该数组中每个滤镜的数据类型,从而确定将要删除哪个滤镜。例如,下面的代码确定滤镜组中的哪个滤镜是发光滤镜,然后从该组中删除该滤镜。
// Example of removing a glow filter from a set of filters, where the
//filter you want to remove is the only GlowFilter instance applied
// to the filtered object.
var tempFilters:Array = filteredObject.filters;
// Loop through the filters to find the index of the GlowFilter instance.
var glowIndex:int;
var numFilters:int = tempFilters.length;
for (var i:int = 0; i < numFilters; i++)
{
if (tempFilters[i] is GlowFilter)
{
glowIndex = i;
break;
}
}
// Remove the glow filter from the array.
tempFilters.splice(glowIndex, 1);
// Apply the new set of filters to the display object.
filteredObject.filters = tempFilters;
在更为复杂的情况下(比如要删除的滤镜是在运行时选定的),最好为滤镜数组保留一个单独的永久副本,用作主滤镜列表。不论何时对滤镜组进行更改,均需更改主列表,然后按照显示对象的
filters
属性应用该滤镜数组。
例如,在下面的代码清单中,多个卷积滤镜应用于一个显示对象,以制造不同的视觉效果,随后在应用程序中删除其中一个滤镜而保留其余滤镜。在本例中,代码保留滤镜数组的主副本以及对于要删除的滤镜的引用。查找并删除特定滤镜的方法与前面的方法类似,但不是创建滤镜数组的临时副本,而是操作主副本,然后将其应用于显示对象。
// Example of removing a filter from a set of
// filters, where there may be more than one
// of that type of filter applied to the filtered
// object, and you only want to remove one.
// A master list of filters is stored in a separate,
// persistent Array variable.
var masterFilterList:Array;
// At some point, you store a reference to the filter you
// want to remove.
var filterToRemove:ConvolutionFilter;
// ... assume the filters have been added to masterFilterList,
// which is then assigned as the filteredObject.filters:
filteredObject.filters = masterFilterList;
// ... later, when it's time to remove the filter, this code gets called:
// Loop through the filters to find the index of masterFilterList.
var removeIndex:int = -1;
var numFilters:int = masterFilterList.length;
for (var i:int = 0; i < numFilters; i++)
{
if (masterFilterList[i] == filterToRemove)
{
removeIndex = i;
break;
}
}
if (removeIndex >= 0)
{
// Remove the filter from the array.
masterFilterList.splice(removeIndex, 1);
// Apply the new set of filters to the display object.
filteredObject.filters = masterFilterList;
}
在此方法(将存储的滤镜引用与滤镜数组中的项目进行比较以确定要删除哪个滤镜)中,
必须
为滤镜数组保留一个单独的副本 — 如果将存储的滤镜引用与从显示对象的
filters
属性复制的临时数组中的元素进行比较,则代码将不起作用。这是因为在内部将数组分配给
filters
属性时,运行时会为数组中的每个滤镜对象创建副本。这些副本(而非原始对象)将应用于显示对象,而在将
filters
属性读入临时数组时,临时数组包含对复制的滤镜对象的引用,而不是对原始滤镜对象的引用。因此,如果在上一示例中尝试通过将
filterToRemove
与临时滤镜数组中的滤镜进行比较来确定其索引,则不会找到匹配的结果。
滤镜和对象变形
显示对象的边框矩形之外的任何过滤区域(例如,投影)都不能视为可进行点击检测(确定实例是否与其他实例重叠或交叉)的表面。由于 DisplayObject 类的点击检测方法是基于矢量的,因此无法对位图结果执行点击检测。例如,如果您对按钮实例应用斜角滤镜,则在该实例的斜角部分,点击检测不可用。
滤镜不支持缩放、旋转和倾斜;如果过滤的显示对象本身进行了缩放(如果
scaleX
和
scaleY
不是 100%),则滤镜效果将不随该实例缩放。这意味着,实例的原始形状将旋转、缩放或倾斜;而滤镜不随实例一起旋转、缩放或倾斜。
可以使用滤镜给实例添加动画,以形成理想的效果,或者嵌套实例并使用 BitmapData 类使滤镜动起来,以获得此效果。
滤镜和位图对象
对 BitmapData 对象应用滤镜时,
cacheAsBitmap
属性会自动设置为
true
。通过这种方式,滤镜实际上是应用于对象的副本而不是原始对象。
之后,会将此副本放在主显示(原始对象)上,尽量接近最近的像素。如果原始位图的边框发生更改,则会从头重新创建过滤的副本位图,而不是被伸展或扭曲。
如果清除了显示对象的所有滤镜,
cacheAsBitmap
属性会重置为应用滤镜之前的值。