现在的位置: 首页 > 综合 > 正文

Sencha Touch 2 官方文档翻译之 Using Device Profiles(使用设备配置)

2012年11月19日 ⁄ 综合 ⁄ 共 11695字 ⁄ 字号 评论关闭

前言:

 

实话实说,之前我是有些小瞧了Sencha Touch中的Device Profile的作用,所以在翻译顺序上才把它放在了比较靠后的位置。细读此文之后才发现自己实在是大错特错,Device Profile简直堪称Sencha Touch MVC中的最大亮点之一。除非你甘愿放弃Sencha Touch那不可思议的跨设备能力,否则你都必须学透Device

Profile这一功能。

 

这篇文章的英文原址是 http://docs.sencha.com/touch/2-0/#!/guide/profiles

原文标题是:Using Device Profiles应用程序中使用设备配置)

Sencha Touch 交流QQ213119459欢迎您的加入。


 

Using Device

Profiles

在应用程序中使用设备配置

注:为方便起见,文中所有出现 Sencha Touch的地方均以 ST简写替代。


Today's mobile web applications are

expected to work on a wide variety of devices, spanning from the smallest

mobile phones to the largest tablets. These devices have a wide range of screen

resolutions and are used in different ways. People tend to use phone apps while

out of the house to rapidly gather some information or perform some action -

often in under a minute. Tablet apps are more likely to be used for longer

periods of time, usually within the home or somewhere else they can sit for a

long time.

今日之移动web应用程序开发要求我们必须考虑尽可能广泛的设备适用性,从最小的智能手机,到最大的平板电脑,不一而足。这些设备分辨率跨度很大而且使用方式千奇百怪。通常人们不在家的时候会使用手机应用来快速获取信息或者做些别的什么,不过使用时间基本上都控制在一分钟以内(译者注:应该是每次一分钟以内吧)。平板电脑的使用时间显然就更长一些,而且一般使用场合是在家里或者在其他能够长久安坐的什么地方。


All of this means that people expect

different app experiences on different devices. However, much of your

application logic and assets can be shared between these different experiences.

Writing separate apps for each platform is time consuming, error-prone and just

plain boring. Thankfully, Device Profiles give us a simple way to share just as

much code as we need to between device types while making it easy to customize

behavior, appearance and workflows for each device.

凡此总总意味着人们在不同的设备上期望的是不同的体验,但事实上,尽管体验不同,可应用程序的绝大部分逻辑和资源还是可以共享的。为每个平台编写一个独立的app不仅浪费时间、容易出错,而且还超级无聊。谢天谢地,设备配置(这一功能)给我们提供了一种简单的方式,使得我们能够共享尽可能多的代码,同时又能轻松地为每种设备定制行为、外观和工作流。


Setting

up Profiles

配置内容


Device Profiles exist within the

context of an Application, for example if we want to create an email app with

phone and tablet profiles we can define our app.js like this (see the Intro to

Apps guide if this is not familiar):

设备配置存在于应用程序的上下文环境之中,例如要创建一个带有phonetablet配置的emal应用,我们可以像下面这样来定义app.js(如果对此不熟悉的话请参考 Intro to Apps guide 


Ext.application({

    name: 'Mail',

 

    profiles: ['Phone',

'Tablet']

});


We didn't give our Application a

launch function, so at the moment all it is going to do is load those two

Profiles. By convention, it expects to find these in app/profile/Phone.js and

app/profile/Tablet.js. Here's what our Phone profile might look like:

我们没有给应用程序写上launch方法,所以现在它唯一能做的就是加载这两个Profiles。按照惯例,他们的存放路径是app/profile/Phone.jsapp/profile/Tablet.js,看看Phone配置文件长得什么样子吧:


Ext.define('Mail.profile.Phone',

{

    extend: 'Ext.app.Profile',

 

    config: {

       

name: 'Phone',

       

views: ['Main']

    },

 

    isActive: function() {

       

return Ext.os.is.Phone;

    }

});


The Tablet profile follows the same

pattern. In our Phone profile we only really supplied three pieces of

information - the Profile name, the optional set of additional views to load if

this Profile is activated, and an isActive function.

Tablet的配置也是一样的格式。这个Phone配置里面我们只提供了3条信息:Profile名称,一组需要额外加载的视图(该项属于可选的),还有一个isActive函数。


The isActive function is what

determines if a given profile should be active on the device your app happens

to be booting up on. By far the most common split is to create profiles for

Phone and Tablet, using the built-in Ext.os.is.Phone and Ext.os.is.Tablet

properties. You can write any code you like in the isActive function so long as

it always returns true or false for the device it is running on.

isActive这个函数将决定该profile在当前设备下是否被启用。到目前为止,最常用的区分就是使用内置的Ext.os.is.PhoneExt.os.is.Tablet属性,分别创建PhoneTabletprofile。你可以在isActive函数里面写任何代码,只要他最终能够为当前设备返回一个true或者false即可。


Determining

the Active Profile

当前活动配置


Once the Profiles have been loaded,

their isActive functions are called in turn. The first one to return true is

the Profile that the Application will boot with. This Profile is then set to

the Application's currentProfile, and the Application prepares to load all of

its dependencies - the models, views, controllers and other classes that

constitute the app. It does this by combining its own dependencies with those

specified in the active profile.

一旦Profile文件加载成功,它们的isActive函数会一次被调用。而应用程序将适配第一个返回trueprofile来启动,该Profile随即被设置成为应用程序的currentProfile,然后应用程序开始加载它所有的依赖项,包含数据模型、视图、控制器和其他组成应用程序的一些类文件。


For example, let's amend our

Application so that it loads a few Models and Views of its own:

看例子,我们改进一下刚才的应用程序,让他加载一些数据模型和试图进来:


Ext.application({

    name: 'Mail',

 

    profiles: ['Phone',

'Tablet'],

 

    models: ['User'],

    views: ['Navigation',

'Login']

});


Now when we load the app on a phone,

the Phone profile is activated and the application will load the following

files:

现在我们在手机上运行一下,Phone配置被激活,应用程序将加载如下文件:

app/model/User.js

app/view/Navigation.js

app/view/Login.js

app/view/phone/Main.js


The first three items are specified

in the Application itself - the User model plus the Navigation and Login views.

The fourth item is specified by the Phone Profile and follows a special form.

By convention, classes that are specific to a Profile are expected to be

defined in a subdirectory with the same name as the Profile. For example, the

'Main' view specified in the Phone Profile will be loaded from

app/view/phone/Main.js, whereas if we had defined 'Main' in the Application it

would be loaded from app/view/Main.js.

前三项(User数据模型以及NavigationLogin视图)是应用程序自己定义的(也就是公共资源),第四项是Phone配置定义的。按照惯例,Profile定义的类将被放置在Profile同名的目录下。比如,Phone配置定义的Main这个视图就应该放在app/view/phone/Main.js文件中,如果Main是在应用程序中定义的话,就该放在app/view/Main.js中。

The same applies to all of the

models, views, controllers and stores loaded in a Profile. This is important as

it enables us to easily share behavior, view logic and more between profiles

(see the specializing views and controllers sections below). If you need to

load classes that don't fit with this convention, you can specify the full

class name instead:


以上原则对Profile中加载的所有数据模型、视图、控制器、数据存储都适用。这样做非常重要,因为这样就能使得我们轻易地在不同设备之间共享行为、视图、逻辑以及更多资源了,后面的章节你可以看到定制视图和控制器的例子。如果想加载没按照常规位置存放的类,你就得指定完整路径了。


Ext.define('Mail.profile.Phone',

{

    extend: 'Ext.app.Profile',

 

    config: {

       

name: 'Phone',

       

views: ['Main', 'Mail.view.SpecialView'],

       

models: ['Mail.model.Message']

    },

 

    isActive: function() {

       

return Ext.os.is.Phone;

    }

});


As we see above, you can mix and

match fully-qualified class names (e.g. 'Mail.view.SomeView') and relatively

specified class names (e.g. 'Main', which becomes 'Mail.view.phone.Main'). Be

aware that all models, views, controllers and stores specified for a Profile

are treated this way. This means if there are Models or Stores that you want to

load for Tablets only but do not want to make classes like

Mail.model.tablet.User, you should specify the fully-qualified class names

instead (e.g. Mail.model.User in this case).

如上面代码所示,你可以混合使用完整路径调用方式(比如Mail.view.SomeView)和常规路径调用方式(比如Main会被解析为Mail.view.phone.Main)。请注意所有在Profile中定义的数据模型、视图、控制器、数据存储都是这样处理的。这也意味着如果你想加载一些数据模型和数据存储却不想让它们的类名如Mail.model.tablet.User这样,那就得指定完整的类名了(比如Mail.model.User)。


The

Launch Process

Launch进程


The launch process using Profiles is

almost exactly the same as it is without Profiles. Profile-based apps have a

3-stage launch process; after all of the dependencies have been loaded, the

following happens:

Profile和没有Profile的情况下,launch进程几乎是一样的。基于Profile构建的应用程序有3launch进程,当所有依赖项加载完成后,将会先后发生如下事件:


Controllers are instantiated; each

Controller's init function is called

控制器被实例化,每个控制器的init方法被调用

The Profile's launch function is

called

Profile中的launch方法被调用

The Application's launch function is

called.

Application中的launch方法被调用


When using Profiles it's common to

use the Profile launch functions to create the app's initial UI. In many cases

this means the Application's launch function is completely removed as the

initial UI is usually different in each Profile (you can still specify an

Application-wide launch function for setting up things like analytics or other

profile-agnostic setup).

当使用Profile的时候,通常会使用Profilelaunch方法去创建应用的初始界面,很多情况下意味着Applicationlaunch方法被彻底丢弃了,因为每一个Profile中的初始化UI通常是不同的。你依然可以指定一个跨profileapplication launch方法来初始化一些东西,比如分析数据或者其他。


A typical Profile launch function

might look like this:

一个典型的Profile

launch方法通常是这样的:

Ext.define('Mail.profile.Phone',

{

    extend: 'Ext.app.Profile',

 

    config: {

       

name: 'Phone',

       

views: ['Main']

    },

 

    isActive: function() {

       

return Ext.os.is.Phone;

    },

 

    launch: function() {

       

Ext.create('Mail.view.phone.Main');

    }

});


Note that both Profile and

Application launch functions are optional - if you don't define them they won't

be called.

注意ProfileApplicationlaunch方法都是可选的,如果你没定义它们,就不会被调用。


Specializing Views

专用视图


Most of the specialization in a Profile occurs in

the views and the controllers. Let's look at the views first. Say we have a

Tablet Profile that looks like this:

Profile大部分的专用设置都发生在视图和控制器上。先看视图,假定我们有一个如下的Tablet配置:


Ext.define('Mail.profile.Tablet', {

   

extend: 'Ext.app.Profile',

 

   

config: {

       

views: ['Main']

   

},

 

   

launch: function() {

       

Ext.create('Mail.view.tablet.Main');

   

}

});


When we boot this app up on a tablet device, the

file app/views/tablet/Main.js will be loaded as usual. Here's what we have in

our app/views/tablet/Main.js file:

当我们在平板电脑上启动这个应用程序时,app/views/tablet/Main.js这个文件将被加载,其内容如下:


Ext.define('Mail.view.tablet.Main', {

   

extend: 'Mail.view.Main',

 

   

config: {

       

title: 'Tablet-specific version'

   

}

});


Usually when we define a view class we extend one

of Sencha Touch's built in views but in this case we're extending

Mail.view.Main - one of our own views. Here's how that on looks:

通常我们定义一个视图的时候都会扩展某一个ST内置的视图,但是这个例子当众,我们扩展的是Mail.view.Main这个我们自己创建的视图,代码如下:


Ext.define('Mail.view.Main', {

   

extend: 'Ext.Panel',

 

   

config: {

       

title: 'Generic version',

       

html: 'This is the main screen'

   

}

});


So we have a superclass (Mail.view.Main) and a

Profile-specific subclass (Main.view.tablet.Main) which can customize any

aspect of the superclass. In this case we're changing the title of the Main

view from "Generic version" to "Tablet-specific version" in

our subclass, so when our app launches that's what we will see.

这样我们就有了一个父类(Mail.view.Main)和一个Profile指定的子类(Main.view.tablet.Main),在子类中我们可以定制任何内容。这个例子里我们在子类中把它的标题从Generic version改成Tablet-specific version,当应用运行起来的时候你就会看到了。


Because these are just normal classes it's easy to

customize almost any part of the superclass using the flexible config system.

For example, let's say we also have a phone version of the app - we could

customize its version of the Main view like this (app/view/phone/Main.js):

由于这都是些常规的类,所以我们通过伸缩性极强的config系统可以很容易定制子类中的任何部分。假设我们这个应用还有一个phone版本,我们将会在其中(app/view/phone/Main.js)像这样来定制他的版本。


Ext.define('Mail.view.phone.Main', {

   

extend: 'Mail.view.Main',

 

   

config: {

       

title: 'Phone-specific version',

 

       

items: [

           

{

               

xtype: 'button',

               

text: 'This is a phone...'

           

}

        ]

   

}

});

 

Sharing sub views

共享子视图


While the above is useful, it's more common to

share certain pieces of views and stitch them together in different ways for

different profiles. For example, imagine an email app where the tablet UI is a

split screen with a message list on the left and the current message loaded on

the right. The Phone version is the exact same message list and a similar

message view, but this time in a card layout as there is not enough screen

space to see them both simultaneously.

上面的例子很有用,不过更常见的是共享视图中的特定部分并在不同的profile中以不同的形式把它们拼合在一起。例如一个email应用,在平板电脑上的界面应该是左右分屏左侧放置邮件列表右侧显示当前加载邮件的内容,而手机版本同样是一个邮件列表和类似的内容视图,但这次他们只能通过card布局来摆放(这就意味着显示一个,隐藏另一个),因为显然手机上没有足够的屏幕空间来同时显示两者。


To achieve this we'd start off creating the two

shared sub views - the message list and the message viewer. In each case we've

left the class config out for brevity:

要实现这一设想我们得先创建两个共享子视图:一个邮件列表和一个内容浏览器,下面例子里我们将省略类的config


Ext.define('Main.view.MessageList', {

   

extend: 'Ext.List',

   

xtype: 'messagelist',

 

   

//config goes here...

});


And the Message Viewer:

下面是内容浏览器:


Ext.define('Main.view.MessageViewer', {

   

extend: 'Ext.Panel',

   

xtype: 'messageviewer',

 

   

//config goes here...

});


Now, to achieve our target layout the tablet Main

view might do something like this:

然后要达到目的我们得在tabletmain视图里我们要这样布局:


Ext.define('Main.view.tablet.Main', {

   

extend: 'Ext.Container',

 

   

config: {

       

layout: 'fit',

       

items: [

           

{

               

xtype: 'messagelist',

               

width: 200,

               

docked: 'left'

           

},

           

{

               

xtype: 'messageviewer'

           

}

        ]

   

}

});


This will create a 200px wide messagelist on the

left, and use the rest of the device's screen space to show the message viewer.

Now let's say we want to achieve our Phone layout:

以上代码将在屏幕左侧创建一个200像素宽的邮件列表,然后把内容浏览器放在屏幕剩余的区域,下面我们要实现手机布局了:


Ext.define('Main.view.phone.Main', {

   

extend: 'Ext.Container',

 

   

config: {

       

layout: 'card',

       

items: [

           

{

  

             xtype:

'messagelist'

           

},

           

{

               

xtype: 'messageviewer'

           

}

        ]

   

}

});


In this case we're just using a Container with a

card layout (a layout that only shows one item at a time), and putting both the

list and the viewer into it. We'd need to plug in some l

抱歉!评论已关闭.