惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
M
MIT News - Artificial intelligence
S
SegmentFault 最新的问题
博客园 - 叶小钗
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
博客园_首页
U
Unit 42
月光博客
月光博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

博客园 - spoony

Flex4 Skinning 2: 皮肤协议 Flex4 Skinning 1: 自定义一个简单按钮的皮肤 Air应用程序访问本地数据库 [通篇转载]调程序的小女孩 Adobe ColdFusion Reports(5) Adobe ColdFusion Reports(4) Adobe ColdFusion Reports(3) Adobe ColdFusion Reports(2) Adobe ColdFusion Reports(1) Adobe ColdFusion Charts(3) Adobe ColdFusion Charts(2) Adobe ColdFusion Charts(1) Adobe ColdFusion读写Microsoft Office Excel数据(3) Adobe ColdFusion读写Microsoft Office Excel数据(2) Adobe ColdFusion读写Microsoft Office Excel数据(1) Flex与DotNET WebService交互(2) Flex与DotNET WebService交互(1) Ext JS Designer 1.0.5 发布 设置Flex Builder中FlashPlayer调试版本 - spoony - 博客园
Flex4 Skinning 4: 留言板示例
spoony · 2010-11-08 · via 博客园 - spoony

  上一篇随笔讲了skinnable Spark component和skin之间的交互,其实在这些components背后并没有太高深的理论,它们只是通过元数据的方式定义一些skin part和skin state, 并在相关的属性上进行关联。自然有的时候我们需要override一些管理skin part和skin state生命周期的关键方法。本篇随笔试着创建一个skinnable Spart component.

  来看一个简单的类似留言板的示例。首先看一下想要做成的效果,如图5所示。

 Figure 5. 可以在一个面板上粘贴留言条

  仔细观察可以发现每一个留言条都是有一些简单的控件组合而成,单独存在的留言条如图6所示。

 Figure 6. 一个单独的留言条由文本标签和圆形关闭按钮组合而成

  下面我们想新建这个组件,新建一个AS3类,名为NoteCard, 并继承skinnableComponent父类。如下代码所示:

package com.guyue.components
{
	import spark.components.supportClasses.SkinnableComponent;
	
	public class NoteCard extends SkinnableComponent
	{
		public function NoteCard()
		{
			super();
		}
         }
}

  然后为这个类用SkinState元数据方式添加相应的skin state, 一般情况下有两个:normal和disabled. 代码如下:

[SkinState("normal")]
[SkinState("disabled")]

  接下来用SkinPart元数据方式定义需要的skin part, 如前面分析,一个简单的留言条由文本标签和圆形按钮组成,因此这里对其进行分别定义为labelDisplay和closeButton, 类型分别为TextBase和Button. 并注意closeButton的required=false, 代表了labelDisplay必须在skin文件中有对应id的标签,而closeButton则是可选的。元数据声明位于skin part名称也就是NoteCard类属性的上方。代码如下:

	[SkinPart(required="true")]
	public var labelDisplay:TextBase;
	
	[SkinPart(required="true")]
	public var closeButton:Button;

  接下来需要为skin part定义相关的属性。比如labelDisplay的text属性。代码如下:

	private var _text:String;

	public function get text():String
	{
		return _text;
	}

	public function set text(value:String):void
	{
		if(_text == value)
			return;
		
		_text = value;
		
		if(labelDisplay)
			labelDisplay.text = value;
	}

  由于skin可以在运行时加载或者卸载,因此我们在程序刚开始运行时并不能保证component的相关skin文件已经准备完毕。所以需要对相应skin part属性进行动态设置。Flex框架会将skin中声明的skin part与component中的相关属性结合起来,并通过skinning生命周期中相应的方法进行通知。

  这里的NoteCard类用到的相关方法主要有getCurrentSkinState(), partAdded(), partRemoved()这三个。这三个方法都在SkinnableComponent中有定义,因此只需要在子类中进行覆写。

  getCurrentSkinState()方法是返回要要加载skin的component的state名称。比如这里的NoteCard类有disabled, enabled, 实现代码如下:

	
override protected function getCurrentSkinState():String
{
	if(!enabled)
		return "disabled";
	
		return "normal";
}

  partAdded()方法会在skin part添加的时候被调用,因此在这个方法中,我们可以添加这个skin part的相关处理逻辑,比如事件监听等。这里的NoteCard类实现代码如下:

	
override protected function partAdded(partName:String, instance:Object):void
{
	super.partAdded(partName, instance);
	
	if(instance == labelDisplay)
		labelDisplay.text = _text;
	
	if(instance == closeButton)
		closeButton.addEventListener(MouseEvent.CLICK, closeButton_clickHandler);
}

  partRemoved()方法会在skin part移除的时候被调用,因此在这个方法中,我们可以将添加在这个skin part的相关处理逻辑进行移除,比如事件监听等。这里的NoteCard类实现代码如下:

override protected function partRemoved(partName:String, instance:Object):void
{
	super.partRemoved(partName, instance);
	
	if(instance == closeButton)
		closeButton.removeEventListener(MouseEvent.CLICK, closeButton_clickHandler);
}

  可以看出partAdded()方法与partRemoved()方法是相对应的,其中用到的closeButton_clickHandler事件主要是将先前添加的留言条进行移除,实现方法如下:

	
protected function closeButton_clickHandler(event:MouseEvent):void
{
	event.stopPropagation();
	
	IVisualElementContainer(parent).removeElement(this);
}

  以上只是建立了SkinnableComponent, 接下来需要为它定义相关的皮肤才能达到想要的效果。在skins包中新建一个MXML Skin文件NoteCardSkin, 定义其HostComponent元数据属性为刚刚建立的NoteCard类。代码如下:

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" 
		xmlns:mx="library://ns.adobe.com/flex/mx">
	<!-- host component -->
	<fx:Metadata>
		[HostComponent("com.guyue.components.NoteCard")]
	</fx:Metadata>
</s:Skin>

  接下来定义与NoteCard类中对应的states, 代码如下:

<s:states>
	<s:State name="normal"/>
	<s:State name="disabled"/>
</s:states>

  接下来是界面的组成部分,包括一个矩形,一个矩形中的文本标签和一个圆形按钮。最后NoteCardSkin皮肤的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" 
		xmlns:mx="library://ns.adobe.com/flex/mx">
	<!-- host component -->
	<fx:Metadata>
		[HostComponent("com.guyue.components.NoteCard")]
	</fx:Metadata>
	<!-- states -->
	<s:states>
		<s:State name="normal"/>
		<s:State name="disabled"/>
	</s:states>
	<!--  -->
	<s:Rect width="300" height="200">
		<s:stroke>
			<s:SolidColorStroke color="0xAA8E5E" weight="4"/>
		</s:stroke>
		<s:fill>
			<s:LinearGradient>
				<s:GradientEntry color="0x60c2fe"/>
				<s:GradientEntry color="0x70b2ee"/>
			</s:LinearGradient>
		</s:fill>
	</s:Rect>
	<s:Label id="labelDisplay" left="10" top="10" width="280" height="180" color="0xFFF3E9" lineBreak="toFit" fontSize="18" fontFamily="Chalkboard"/>
	<s:Button id="closeButton" skinClass="com.guyue.skins.NoteCardCloseButtonSkin" top="5" right="5"/>
</s:Skin>

  注意观察一下Label和Button的id属性,可以发现与NoteCard类中的SkinPart是对应的,这样在将skin应用到component上时,Flex会自动匹配。

  另外圆形按钮closeButton也使用了一个自定义皮肤,使用这个皮肤会将Flex4自带的默认皮肤覆盖,这里我们需要再建立这个新的皮肤文件NoteCardCloseButtonSkin, 具体方法与上大同小异,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" 
		xmlns:mx="library://ns.adobe.com/flex/mx">
	<!-- host component -->
	<fx:Metadata>
		[HostComponent("spark.components.Button")]
	</fx:Metadata>
	
	<!-- states -->
	<s:states>
		<s:State name="disabled" />
		<s:State name="down" />
		<s:State name="over" />
		<s:State name="up" />
	</s:states>
	
	<s:Ellipse width="16" height="16">
		<s:stroke>
			<s:SolidColorStroke color="0x131313" weight="1" />
		</s:stroke>
		<s:fill>
			<s:LinearGradient>
				<s:GradientEntry color="0xAA8E5E" color.over="0x9A7E4E" color.down="0x7A5E2E" />
				<s:GradientEntry color="0xCCBBAA" color.over="0xBCAB9A" color.down="0x9C8B7A"/>
			</s:LinearGradient>
		</s:fill>
	</s:Ellipse>
	
	<s:Label text="X" horizontalCenter="0" verticalCenter="0" />
	
</s:Skin>

  以上就是一个简单skinnable Spark component实现的示例。Flex强大的skinning机制使得它的实现非常容易。我们可以随时定义新的皮肤来完全改变这个component的外观。