OrangeUI

 
 
为什么建议使用Frame?
在移动开发中,使用Frame相对于Form来讲,
具有占用内存小,加载速度快,结构简单,使用灵活等优点,
在XE7发布会的时候李维老师也推荐使用Frame来作为APP页面。
 
通常一个APP的首页都有五个分页,如下图所示:

如果使用Form,就要将五个分页及里面所包含的子控件都放在一个Form上,
不仅增加开发的复杂度,并且用户打开APP就要创建包含这么多控件的窗体,
APP势必会慢,占用内存也比较大,
 
而使用Frame,打开APP时,只需要先创建并显示其中的一页,仅占一页的内存,
然后用户点击Tab按钮,再创建另一页显示出来,占用内存很合理,
并且开发的时候,可以拆分成五个页面,十分方便简洁,如下图所示:


并且Frame很灵活,可以嵌套在其他控件中,如Form,Panel,TabItem,
很多对话框、进度框、提示框、弹出菜单框等都很适合用Frame来实现。
但这些框在FireMonkey平台下用Form来实现就很不方便了。
 
 
 
OrangeUIFrame框架的实现逻辑如下:
当前显示AFrame页,
然后我们要显示BFrame页,
需要调用ShowFrame(BFrame),
ShowFrame方法中会生成一个FrameHistory,
FrameHistory表示当前页面跳转的上下文,
其中FrameHistory.ToFrame表示当前显示的Frame,
其中FrameHistory.LastToFrame表示之前显示的Frame,
所以要把BFrame记录到FrameHistroy.ToFrame中,
再把之前显示的AFrame记录到FrameHistory.LastToFrame中,
并把这个FrameHistroy加入到FrameHistroyLogList中,
因为我们从BFrame返回上一页时要知道AFrame是我们要返回的上一页,
再把这个FrameHistroy复制给CurrentFrameHistroy,
流程如下:

当前显示BFrame,
需要返回上一页时,
首先调用HideFrame(BFrame)隐藏当前页,
再调用ReturnFrame(BFrame),表示从BFrame返回上一页,
ReturnFrame方法会在FrameHistoryLogList倒序查询上一页的FrameHistroy,
当前页的FrameHistory为Item1,Item1.ToFrame为BFrame,
上一页的FrameHistory为Item0,Item0.ToFrame为AFrame,
就是我们要返回到的页面是AFrame,
流程如下:

 
 
Frame框架的使用方法如下:
一.先新建一个Frame,
File->New->Other:

在弹出的New Items对话框中,依次选Delphi Projects->Delphi Files->FireMonkey Frame:

OK->保存,给Frame所在的单元命名,
比如主页面的单元为MainFrame.pas,
再给Frame命名,
比如主页面的Frame类型一般命名为FrameMain,
 
 
二.Frame框架使用模式1:
在MainFrame单元中引用uUIFunction.pas,

然后给TFrameMain类添加TFrameHistroy类型的公共成员:
FrameHistroy:TFrameHistroy;
并在Frame单元的implementation上方,
定义一个TFrameMain类型的全局页面变量:
GlobalMainFrame:TFrameMain,

在主窗体MainForm中加一个按钮btnShowMainFrame,
点击它来显示主页MainFrame:

代码如下:

//显示主页的时候,不需要动画,因为主页是立即显示的,
ShowFrame(TFrame(GlobalMainFrame),TFrameMain,frmMain,nil,nil,nil,Application,True,True,ufsefNone);
//记录页面切换的上下文
GlobalMainFrame.FrameHistroy:=CurrentFrameHistroy;
 
主页一般就是默认页、第一页,如果从主页返回,那就就只剩一片空白的窗体了。
 
再创建一个FirstFrame,
然后在MainFrame上加一个按钮,
点击之后跳转到FirstFrame,

代码如下:

//先隐藏当前页
HideFrame(Self,hfcttBeforeShowFrame);
//显示第一页
ShowFrame(TFrame(GlobalFirstFrame),TFrameFirst,frmMain,nil,nil,DoReturnFromFirstFrame,Application);
//记录页面切换的上下文
GlobalFirstFrame.FrameHistroy:=CurrentFrameHistroy;
 
然后在FirstFrame上放一个按钮,
点击它,返回上一页,也就是MainFrame,

代码如下:

//先隐藏自己
HideFrame(Self,hfcttBeforeReturnFrame);
//再返回上一页
ReturnFrame(Self.FrameHistroy);
 
 
三.Frame框架使用模式2:
新建一个SecondFrame,
拖一个FrameContext在上面,
FrameContext有如下事件:
OnCreate:Frame创建事件
OnShow:Frame显示事件
OnHide:Frame隐藏事件
OnReturnFrom:从其他Frame返回自己事件
OnDestroy:释放事件
显示含有FrameContext的Frame方法如下:
var
ASecondFrame:TFrameSecond;
begin
//先隐藏当前页
HideFrame(Self,hfcttBeforeShowFrame);
//显示第二页
ASecondFrame:=nil;
ShowFrame(TFrame(ASecondFrame),TFrameSecond,frmMain,nil,nil,DoReturnFromFirstFrame,Application);
 
返回含有FrameContext的Frame方法如下:
//返回前先隐藏
HideFrame(Self,
hfcttBeforeReturnFrame,//表示当前返回
ufsefDefault //隐藏的效果
 
);
//返回
ReturnFrame(FrameContext1.FrameHistory,
1,
True//返回后需要释放
);
 
 
三.Frame框架的方法介绍:
1.ShowFrame:显示Frame
参数:
var ToFrame:TFrame;                                                                //要显示的Frame
ToFrameClass:TFrameClass;                                                      //要显示的Frame类类型
ToFrameParent:TObject;                                                                       //ToFrame的Parent,即把Frame放在它里面
Other:TObject;                                                                         //填nil
FromFrame:TFrame;                                                                 //填nil
OnReturnFrame:TReturnFrameEvent;                           //从ToFrame页面返回后调用的事件
Owner:TComponent=nil;                                                          //创建ToFrame的拥有者
IsLogInHistory:Boolean=True                                       //是否记录到跳转历史列表
IsUseGlobalPaintSetting:Boolean=True                         //是否使用全局的背景色
UseFrameSwitchEffectType:TUseFrameSwitchEffectType//是否使用页面切换效果
ufsefNone:不使用页面切换效果
ufsefDefault:使用默认页面切换效果
 
2.HideFrame:隐藏Frame
参数:
Frame:TFrame                                                                                                              //要隐藏的页面Frame
HideFrameCalledTimeType:THideFrameCalledTimeType            //调用的时机
hfcttNone:
hfcttBeforeShowFrame:在ShowFrame之前
hfcttBeforeReturnFrame:在ReturnFrame之前
UseFrameSwitchEffectType:TUseFrameSwitchEffectType          //是否使用页面切换效果
ufsefNone:不使用页面切换效果
ufsefDefault:使用默认页面切换效果
 
3.ReturnFrame:返回上一页Frame
参数:
FrameHistroy:TFrameHistroy;
ReturnStep:Integer=1;//默认为1
IsNeedFree:Boolean;//返回之后是否需要释放Frame
 
 
 
四.Andriod手机上按返回键返回上一页的处理:
需要在主窗体MainForm的KeyUp事件中,写上如下代码:

if (Key = vkHardwareBack)
//Windows下Escape键模拟返回键
or (Key = vkEscape) then
begin
//返回
if (CurrentFrameHistroy.ToFrame<>nil)
and (CurrentFrameHistroy.ToFrame<>GlobalMainFrame) then
begin
if CanReturnFrame(CurrentFrameHistroy) then
begin
//返回上一页
HideFrame(CurrentFrameHistroy.ToFrame,hfcttBeforeReturnFrame);
ReturnFrame(CurrentFrameHistroy);
 
//表示不关闭APP
Key:=0;
KeyChar:=#0;
end
else
begin
//表示当前Frame不允许返回
end;
end
else
begin
{$IFDEF ANDROID}
//程序退到后台挂起,需要引用Androidapi.Helpers单元
FMX.Types.Log.d('OrangeUI moveTaskToBack');
SharedActivity.moveTaskToBack(False);
 
//表示不关闭APP
Key:=0;
KeyChar:=#0;
{$ENDIF}
end;
end;