반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


Sharing sub views

전 시간 마지막에 다뤘던 예제도 유용하지만 서로 다른 프로파일별로 부분적인 특정 view를 공유하고 또 그 부분적인 view들을 서로 합치고 하는 방법도 일반적으로 사용됩니다. 예를 들어 태블릿 UI의 이메일 앱은 왼쪽에 메세지 리스트가 있고 오른쪽에 현재의 메세지가 나타나도록 스크린을 나눈다고 가정해 봅시다. Phone 버전에서는 똑 같은 message list 와 비슷한 message 뷰가 사용됩니다. 하지만 이 경우 스크린이 태블릿과 비교해서 많이 작기 때문에 card layout에 두가지를 한꺼번에 나타내기가 힘듭니다.

이 문제를 해결하기 위해 우리는 두 개의 서로 공유되는 sub view들을 생성하겠습니다. 메세지 리스트와 메세지 뷰어를 따로따로 sub view로 만들게 되겠죠. 어떤 경우든 class 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...
});


이제 태블릿 main view 에서는 아래와 같은 식으로 이 sub view를 이용하게 될 겁니다. :

Ext.define('Main.view.tablet.Main', {
    extend: 'Ext.Container',

    config: {
        layout: 'fit',
        items: [
            {
                xtype: 'messagelist',
                width: 200,
                docked: 'left'
            },
            {
                xtype: 'messageviewer'
            }
        ]
    }
});


이렇게 하면 200 픽셀크기의 메세지 리스트가 왼쪽에 나타날거구요 나머지 공간에 메세지 뷰어가 나타날 겁니다. 그럼 이제 phone 의 경우는 어떻게 될지 살펴 보죠.

Ext.define('Main.view.phone.Main', {
    extend: 'Ext.Container',

    config: {
        layout: 'card',
        items: [
            {
                xtype: 'messagelist'
            },
            {
                xtype: 'messageviewer'
            }
        ]
    }
});


이 경우 card layout과 함께 Container를 사용하면 됩니다. (이렇게 되면 한번에 한 아이템만 화면에 나타납니다.) 그리고 나서 리스트와 뷰어를 이 콘테이너에 집어 넣으면 됩니다. 이제 리스트 안의 어떤 메세지를 유저가 tap 했을 경우 메세지 뷰어를 보여주는 기능만 만들면 됩니다 . 이렇듯이  우리는 로드된 프로파일을 근거로 서로 다른 configuration만 함으로서 두개의 sub view를 쉽게 재 사용할 수 있습니다.




Specializing Controllers

View와 마찬가지로 많은 어플리케이션들은 여러 Profile 에서 공유될 수 있는 많은 Controller 로직들이 있습니다. Profile들 사이에서 달라져야 할 점은 대개 workflow와 관련된 것들입니다. 예를 들어 앱의 태블릿 프로파일은 한 페이지로 해결 될 수 있는 workflow가 Phone에서는 여러 화면으로 나누어야 되는 경우가 많습니다.

아래 간단한 Phone 프로파일이 있습니다. 여기서는 Main이라는 view와 Message라는 Controller 를 로드 합니다. 이전에 살펴 봤듯이 이럴경우 실제로는 app/view/phone/Main.js와 app/controller/phone/Messages.js 를 로드할 겁니다.

Ext.define('Mail.profile.Phone', {
    extend: 'Ext.app.Profile',

    config: {
        views: ['Main'],
        controllers: ['Messages']
    },

    launch: function() {
        Ext.create('Mail.view.phone.Main');
    }
});


여기서 폰과 태블릿에서는 대부분 controller들을 공유합니다. 그래서 우선 app/controller/Messages.js 에 controller 수퍼클래스를 생성하겠습니다.

Ext.define('Mail.controller.Messages', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            viewer: 'messageviewer',
            messageList: 'messagelist'
        },
        control: {
            messageList: {
                itemtap: 'loadMessage'
            }
        }
    },

    loadMessage: function(item) {
        this.getViewer().load(item);
    }
});


이 Controller는 3가지로 구성돼 있습니다.

- 우리가 다룰 view와 관련해서 refs를 셋업합니다.
- Message List item의 tap 이벤트를 Listening 합니다. tap 되면 loadMessage 함수를 call 합니다.
- loadMessage 함수에서는 선택된 메세지 아이템을 Viewer 에 로드합니다.


이제 Phone 에 맞는 controller 작업을 하겠습니다.

Ext.define('Mail.controller.phone.Messages', {
    extend: 'Mail.controller.Messages',

    config: {
        refs: {
            main: '#mainPanel'
        }
    },

    loadMessage: function(item) {
        this.callParent(arguments);
        this.getMain().setActiveItem(1);
    }
});


보시면 Messages 수퍼클래스 controller를 extend 했습니다. 그리고 두개의 기능을 정의했습니다.

We add another ref for the phone UI's main panel

Phone UI의 panel에 맞게 하기 위해 수퍼클래스와는 다른 ref를 add 했습니다. 원래의 로직을 수행하기 위해 loadMessage 함수를 extend 했고 main 패널의 active 아이템을 message viewer에 셋업합니다. 수퍼클래스의 모든 configuration은 subclass에 의해 inherite 됐습니다. refs 같이 duplicated config가 있을 경우 이 config는 통합됩니다. 그래서 phone Message controller 클래스에는 3개의 refs 가 있게 됩니다. (main,viewer, messageList) 이와 같이 수퍼클래스를 extend 해서 사용할 경우 superclass의 config를 사용할 수 있게 됩니다.

Mail.controller.Messages 수퍼클래스는 애플리케이션이나 프로파일에 의해 사용되거나 변경되지 않았습니다. 이렇게 되면 자동적으로 로드되게 됩니다. Mail.controller.phone.Message controller 가 이것을 extends 했기 때문입니다.

What to Share

위 예제에서 refs 중 일부를 공유할 수 있습니다. 또한 Controller의 control config에 대해 Listen 하는 이벤트를 공유할 수도 있습니다. 일반적으로 프로파일별로 이보다 더 그 로직들이 나눠집니다. refs와 control config 들 중 좀 더 적은 수만이 공유될 겁니다.

모든 프로파일에 걸쳐 공유되어야 할 Controller config는 route 입니다. 이 map url은 콘트롤러 action을 위한 그리고  back button 지원과 좀 더 깊게 menu link 를 하기 위한 겁니다. 수퍼클래스에 route를 가지고 있게 만드는 것은 중요합니다. 왜냐하면 device에 상관 없이 같은 url은 같은 content에 map 되어야 하기 때문입니다.

예를 들어 여러분의 친구가 여러분 앱의 phone version을 사용한다면 그리고 여러분에게 그 친구가 현재 사용하고 있는 앱의 현재 페이지 링크를 send 한다면 태블릿을 사용하고 있는 여러분도 그 링크를 tab 함으로서 같은 내용을 볼 수 있어야 하기 때문입니다. 모든 route들을 수퍼클래스에서 관리하는것은 device에 상관없이 url structure의 consistent를 유지 가능하게 해 줄 겁니다.

Specializing Models

Model 은 Controller와 View에 비해 profile 별로 다른 기능이 적용되어야 하는 경우가 적습니다. 그래서 대개 subclass가 필요하지 않습니다. 이 에제에서는 model을 모든 device에 같이 적용되도록 하나의 클래스로 관리합니다.

Ext.define('Mail.profile.Tablet', {
    extend: 'Ext.app.Profile',

    config: {
        models: ['Mail.model.Group']
    }
});


반응형

Comment