移动开发技巧总结

一.CaltrainTimes案列分析:

http://www.adobe.com/cn/devnet/flex/articles/caltrain-times-story.html
1.确定设计分辨率,并由设计师给出相应的PSD档
2.合并图层割图
3.根据缩放导出不同的DPI,及相应的文件夹
4.UI设计,以保证效率、用户体验、不同DPI下正确渲染
5.程序开发,以整合数据和需求,并解决多DPI问题
6.优化,完成MXML到AS的手工转换
7.根据不同的平台导出相应的发布包

//////////////////////////////////////////////////////////////////////////////////////////

二.DPI设计原则

分辨率是像素高度乘宽度得到的数值,即设备支持的像素总数;DPI是每平方英寸的点数,即设备
屏幕上的像素密度。在Flex中利用applicationDPI/runtimeDPI和动态布局的概念来完成对不同的
DPI的设计

多平台适配技巧
1.用矢量图或MultiDPIBitmapSource位图(由runtimeDPI决定),后者利用BitmapImage和Image配合
使用,但是无法显示对特定DPI不显示图像
2.文本的字体大小缩放至分辨率相符的大小
3.使用动态布局,避免使用约束布局,不要手动来缩放(可以使用锚点)
4.使用@media来定义不同OS和DPI下的样式属性,结合and/not/or(,)操作符,对属性os-platform和
application-dpi筛选
5.皮肤使用DPI值来确定资源(switch/case)。由FXG文件定义的皮肤都适用于目标设备
6.不要显式设置应用程序的高和宽,由SystemManager.screen获取其值

方案选择:
1.自动缩放:设置applicationDPI值,并创建针对该DPI值的单组外观和视图/组件布局,对于位图资源,
采用MultiDPIBitmapSource来进行视频,无需考虑矢量资源和文本,不要使用@media规则,反复测试
2.非自动缩放:不设置applicationDPI值(会被设成rumtimeDPI),创建可根据不同DPI动态调整的单组外观和布局,
使用@media规则,反复测试
可以在Application中用runtimeDPI和applicationDPI,或View中用FlexGlobals.topLevelApplication.runtimeDPI
和FlexGlobals.topLevelApplication.applicationDPI计算比例后得到运行时资源目录

重写默认DPI映射
Application类的runtimeDPIProvider属性指向RuntimeDPIProvider类的子类。并在子类中重写runtimeDPI getter并
添加用于提供自定义DPI映射的逻辑

//////////////////////////////////////////////////////////////////////////////////////////

三.移动皮肤

Mobile主题里的皮肤使用一个新的基类MobileSkin,它扩展了UIComponent,
1.状态:MobileSkin不再用State类及子类,而是手工的在代码里处理状态改变,例如SetProperty和AddChild
2.布局:MobileSkin不是一个Group,不能再用约束布局(HorizontalLayout/VerticalLayout/BasicLayout),其内容在
代码中人工的布局,放到layoutContents()中,该函数会在updateDisplayList()中被调用
3.图形:Mobile主题中皮肤的图形由编译过的FXG和用于绘制的ActionScript代码构成
4.文本:使用Label/TextInput/TextArea,对于不使用的MXML情况,采用TextField和StyleableTextField
5.皮肤:由于改变了MXML的状态、布局和图形,故用MXML已经没有什么优势,故最好用ActionScript编写皮肤
6.避免使用的全局样式:rollOverColor/borderAlpha/borderColor/cornerRadius/dropShadowVisible
7.避免使用的组件:ComboBox/DropDownList/NumericStepper/ToggleButton/VideoDisplay/VideoPlayer/VSlider/Panel/TabBar/TitleWindow

//////////////////////////////////////////////////////////////////////////////////////////

四.原生神器

其包括:StageText/StageVideo/StageWebView,具有相同的优点,即拥有原生的性能及功能,但也有一点共同的弱点,它们都不
是DisplayObject;StageText使用viewPort定义及在Stage上的位置,并渲染在顶层,另外,不能滚动控件所在的视图,也不能使用嵌入字体,
不能对基于StageText的控件使用自定义大小调解决方法是调用,不过利用drawViewPortToBitmapData接口来实现类似RenderTarget的功能

//////////////////////////////////////////////////////////////////////////////////////////

五.移动字体

在移动版本中,如果要使用字体应该使用Spark中TextInput/TextArea,它们默认采用的是基于StageText的移动皮肤StageTextInputSkin和
StageTextAreaSkin,但是不支持类似TLF一样的高级特性;不过如果要获得这些特性,可以请将其外观类指向基于TextField的TextInputSkin和
TextAreaSkin;Label控件使用FTE,它的性能不如优化后的文本控件TextInput和TextArea,但是它不使用TLF,性能上又优于RichText和
RichEditableText控件;在创建基于AS的项呈示器时,使用StyleableTextField,对于基于MXML的组件,仍可以使用Label;但是对于嵌入字体,
不能使用基于CFF的Label,而应该采用基于TextField的TextArea,如要一个非交互式多行文本,应将editable属性设为false,举个嵌入式的例子:
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@font-face {
src: url("../assets/MyriadWebPro.ttf");
fontFamily: myFontFamily;
embedAsCFF: false;
}
.customStyle {
fontFamily: myFontFamily;
fontSize: 24;
skinClass: ClassReference("spark.skins.mobile.TextAreaSkin");
}
</fx:Style>
<s:TextArea id="ta1" styleName="customStyle" text="This is a TextArea control that uses an embedded font."/>

//////////////////////////////////////////////////////////////////////////////////////////

六.移动设备过渡效果

通过ViewNavigator容器类,navigator对象来控制过渡效果,目前定制的效果有CrossFadeViewTransition、FlipViewTransition、
SlideViewTransition、CrossFadeViewTransition,常用的方法有pushView/popView/popToFirstView/popAll/replaceView等;
可以给navigator对象defaultPopTransition和defaultPushTransition的默认行为,还可以加入缓动类Bounce/Linear/Sine来给
效果赋值easer和duration属性;其过渡效果的基类有captureStartValues/prepareForPlay/play/captureEndValues由调用者来
触发,如果需要重载即可。


//////////////////////////////////////////////////////////////////////////////////////////

七.闪屏

闪屏很简单而且适用于所有Flex Application类(Application、ViewNavigatorApplication和TabbedViewNavigatorApplication)。要想启用这个
特性,设置splashScreenImage为一个嵌入的图像,设置splashScreenMinimumDisplayTime的时间,设置splashScreenScaleMode的缩放模式(none/
stretch/zoom/letterbox);同时他还支持基于不同DPI来返回不同的闪屏图形文件,只需继承SplashScreen类,并重写getImageClass方法,并将其
类名赋予实现preloader,例子如下:
public class MultiDPISplashScreen extends SplashScreen
{
[Embed(source="assets/splash160.png")]
private var SplashImage160:Class;

[Embed(source="assets/splash240.png")]
private var SplashImage240:Class;

[Embed(source="assets/splash320.png")]
private var SplashImage320:Class;

public function MultiDPISplashScreen()
{
super();
}

override mx_internal function getImageClass(dpi:Number, aspectRatio:String):Class
{
if (dpi == DPIClassification.DPI_160)
return SplashImage160;
else if (dpi == DPIClassification.DPI_240)
return SplashImage240;
else if (dpi == DPIClassification.DPI_320)
return SplashImage320;
return null;
}
}

//////////////////////////////////////////////////////////////////////////////////////////

八.多平台开发

在不同的平台下进行开发,具有显著的平台差异,包括:硬件按钮、可用的屏幕面积、活版印刷、软键盘、文本输入、颜色的深浅,
每个平台供应商都具有其独特的人机接口规范(HIG),称为UI规范:
IOS:https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/index.html
Android:http://developer.android.com/design/index.html
故设计应用程序中很重要的一点是,您必须清楚何时以及如何将特定于平台的不同点考虑在内,在一些特殊情况下需要创建特定平台
的外观和样式
1.使用CSS媒体查询,利用@media及os-platform属性
2.主题的使用,以共享库(frameworks/themes/Mobile/mobile.swc)为基础,覆盖不同平台下的移动主题swc,结合并重写default.css
覆盖原有SDK的的CSS文件(frameworks/projects/mobiletheme/defaults.css)

//////////////////////////////////////////////////////////////////////////////////////////

九.构建同时适合Web和Mobile的应用程序

1.用应用程序框架,将Web和Mobile公用逻辑部分抽象成Basecode
2.采用Spark和Mobile皮肤,并且尽量采用FXG和AS绘图代码,避免使用MXML
3.采用Spark的List和DataGrid创建快速列表,并且不建议使用默认Flex ItemRenderer类,而应该采用优化过的LabelItemRenderer和
IconItemRenderer类,效率更高
4.对于平板,可以使用SplitViewNavigator,内容是两个ViewNavigators。一个用于大纲视图,一个用于细节视图

////////////////////////////////////////////////////////////////////////////////////////// 

十.处理设备朝向

如果要处理朝向问题,要打开属性<autoOrients>true</autoOrients>,并对stage对象注册两种事件类型:StageOrientationEvent.ORIENTATION_CHANGE
和StageOrientationEvent.ORIENTATION_CHANGING,在回调函数中取得StageOrientationEvent对象的deviceOrientation属性,如下:
1.StageOrientation.DEFAULT:默认的舞台朝向
2.StageOrientation.ROTATED_LEFT:向左旋转
3.StageOrientation.ROTATED_RIGHT:向右旋转
4.StageOrientation.UNKNOWN:未知的舞台朝向
5.StageOrientation.UPSIDE_DOWN:上下颠倒

//////////////////////////////////////////////////////////////////////////////////////////

十一.View生命流程

View的生命期的控制是通过destructionPolicy属性来控制的;如果要在View1的基础上激活View2,其正常的流程为:
1.删除View1以响应屏幕变化的removing事件
2.View2添加到display列表的added事件
3.View2的add事件
4.View2的creationComplete事件
5.View1的viewDeactivate事件
6.Display列表中删除View1的removed事件
7.View2的viewActivate事件
还可以覆盖View的createReturnObject方法,从弹出的视图中返回数据:
data = navigator.poppedViewReturnedObject.object;

//////////////////////////////////////////////////////////////////////////////////////////

十二.移动常用技巧

1.如果你要风格化颜色,文本,定位,图标等方面的内容,使用CSS就可以了。
2.如果你想创建一个有更多图像元素的外观,可以使用FXG,自定义皮肤,和画图。
3.如果你想设置不同分辨率的设备上的皮肤,你可以使用CSS媒体过滤器或FXG中装载的支持各种分辨率的特殊皮肤类别
4.如果要隐藏动作条组件或标签组件,可以利用actionBarVisible和tabBarVisible属性
5.如果想要响应tabbedNavigator的按钮切换事件,可以注册IndexChangeEvent.CHANGE事件
6.如果你想要修改标签组件,显示在上部,可首先从相应SDK版本的frameworks/projects/mobiletheme/src/spark/skins/mobile
找到相应的类型的皮肤,比如TabbedViewNavigatorSkin.as,将其拷贝到我们的资源路径并改名,再结合修改后的路径名修改皮肤
文件中的package,并声明CSS样式s|TabbedViewNavigator,其skinClass属性为修改好的路径名和文件名,最后修改皮肤文件中的
layoutContents来重新进行布局

//////////////////////////////////////////////////////////////////////////////////////////

十三.持久化

View容器通过使用View.data属性来支持内存持久化机制。当切换所新视图,会自动保存现有视图的data属性。当重新回到该视图时,将恢复该视图的data属性,
故该机制可以在运行时维护视图的状态信息;可在ViewNavigatorApplication和TabbedViewNavigatorApplication中,将persistNavigatorState属性设置为true,
会使用PersistenceManager往FxAppCache的本地共享对象中,写入applicationVersion和navigatorState属性,前者对应于application.xml中的应用程序版本,
后者对应于当前ViewNavigator的堆栈;在persistNavigatorState属性为false时,可以调用load方法以初始化PeristenceManager,用setProperty和getProperty
方法实现属性的设置和获取,并用save方法以将数据写入磁盘,来实现自己的持久化机制,此时在navigatorStateSaving事件的处理函数中调用preventDefault()
方法,来取消将应用程序状态保存至磁盘的操作。在navigatorStateLoading事件的处理函数中调用preventDefault()方法可以取消在重新启动应用程序时加载状态,
具体如下:
1.重写View类的serializeData和deserializeData方法
2.使用支持的数据类型:Number、String、Vector、Object、uint、int和Boolean
3.如果是自定义的数据类,应在应用程序的preinitialize事件,调用flash.net.registerClassAlias()来注册
4.如果定义复杂的类(使用非内置数据类型),则必须将数据转换为受支持的类型(String)。如果类定义了任何私有变量,则不会自动持久保存这些变量。要在持久化
机制中支持复杂的类,该类必须实现flash.utils.IExternalizable接口。并实现writeExternal()和readExternal()方法以保存和恢复类的实例

//////////////////////////////////////////////////////////////////////////////////////////

十四.ActionBar

其区域包括:导航区域,标题区域,操作区域,可以在ViewNavigatorApplication、ViewNavigator和View容器中设置用于定义ActionBar 控件内容的属性。View容器的
优先级最高,其次是ViewNavigator,再其次是ViewNavigatorApplication容器:
1.导航区域,用navigationContent属性定义组件, navigationLayout属性定义布局
2.标题区域,用title属性定义标题字符串,用titleContent属性定义组件, titleLayout属性定义布局
3.操作区域,用actionContent属性定义组件, actionLayout属性定义布局
注意,可以调用navigator的方法hideActionBar来隐藏ActionBar,还可以重写方法createActionBarHideEffect和createActionBarShowEffect来更改显示和隐藏效果,
可以调用tabbedNavigator的方法hideTabBar来隐藏TabBar,通过重写方法createTabBarHideEffect和createTabBarShowEffect来更改显示和隐藏效果


//////////////////////////////////////////////////////////////////////////////////////////

十五.移动设备可以使用组件限制

1.可以完全使用的新组件(Spark):ActionBar/BusyIndicator/Callout/CalloutButton/DataSpinner/SpinnerList/SpinnerListContainer/TabViewNavigator/
TabViewNavigatorApplication/ToggleSwitch/View/ViewMenu/ViewNavigator/ViewNavigatorApplication
2.可以使用的具有皮肤的组件(Spark):Button/CheckBox/DataGroup/Group/HGroup/VGroup/TileGroup/Image/BitmapImage/Label/List/RadioButton/
SkinnableContainer/Scroller/TextArea/TextInput
3.其他的Spark Skinnable组件:建议不要使用,这些组件不具有适用于移动设备主题的外观
4.其他的Spark Containner组件:建议不要使用,包括:DataGrid/RichEditableText/RichText
5.可以使用的Spacer组件(Halo)
6.可以使用的图表组件(Halo),当存在性能隐患
7.除5和6以外,其他的Halo组件是不能使用

//////////////////////////////////////////////////////////////////////////////////////////

十六.处理滚动

如果屏幕的可见区域无法显示全部内容,应用程序将显示滚动条,使用Scroller控件可以在应用程序中添加滚动条。其他组件(Spark List)支持滚动,因此您无需使用Scroller
组件;在基于桌面或浏览器的应用程序中,点击区域是滚动条的可见区域,在移动设备应用程序中,都会隐藏滚动栏,这样可使应用程序使用屏幕的全屏宽度和高度;其具备以
下几个术语:
1.内容:指整个组件区域,可能会仅显示部分内容。
2.视口:当前可见的组件内容区域中的一部分。
3.拖动:用户触摸可滚动区域,然后移动手指以便内容沿手势移动时发生的触摸手势。
4.速度:拖动手势的移动速率和方向。以沿 X 和 Y 轴每毫秒的像素为单位。
5.抛开:用户在拖动手势达到特定速度后抬起手指时的拖动手势,此时可滚动内容仍继续移动。
6.跳动:拖动或抛开手势可以将可滚动组件的视口移至组件内容之外。然后,视口显示空白区域。当您释放手指或抛开速度达到零时,视口将跳跃回其静止点,并且视口有内容
填充。移动随着视口接近静止点而减慢,因此能平稳停止。
在基于Scroller的组件中,可以使用pageScrollingEnabled和scrollSnappingMode属性,前者用来控制移动时基于像素还是基于页面的,后者用来控制吸附的方式,包括
leadingEdge/center/trailingEdge;如果要对TextInput和TextArea使用Scroller,要采用基于TextField的皮肤,而不是默认的StageText皮肤;在与其交互的过程中,程序必
须区分用户的意图,用户是要与控件交互还是要进行滚动(Button举例):
1.设置touchDelay属性,指定延迟期,可以确保用户正在选择Button而不是尝试滚动屏幕
2.延迟期内,手指必须移动约0.08英寸的距离,该手势才会被解释为滚动操作,此时Button不会识别该交互
3.延迟期后,Button识别该交互,更改其外观;此时如果移动手指的距离可以大于0.08,Button恢复正常状态,启动滚动操作
注意,以上的判断都是基于mouseDown事件,故对于该事件,用户的预期行为不明确(可能组件交互,可能滚动),建议侦听click或mouseUp事件,而不是mouseDown事件;有时我们
要自定义滚动行为,就要了解其行为:滚动操作开始时发出信号,分派mouseDown事件的组件将分派冒泡的touchInteractionStarting事件。如果未取消该事件,组件将分派冒泡的
touchInteractionStart事件,当组件检测到touchInteractionStart事件时,不得尝试响应用户手势,如果组件不希望启动滚动,组件可以在touchInteractionStarting事件的事
件处理函数中调用preventDefault方法,完成滚动操作之后,分派mouseDown事件的组件将分派冒泡的touchInteractionEnd组件

 

 

 

 

 

 

 

 

 

posted @ 2014-03-28 09:24  腐烂的翅膀  阅读(542)  评论(0编辑  收藏  举报