App 에서 View 를 사용해 보자!!
사용자가 실제로 보는 부분은 view 이다. 오늘은 app 에서 어떻게 view 를 만들고 그렇게 만들어진 View 를 통해 어떻게 application 을 build 하는 지를 설명하겠다.
지난 시간에 배웠듯이, component 를 만들 때, 센차에서 제공하는 Component class 를 이용하는데 이 때, Ext.create 를 사용한다.
Ext.create('Ext.Panel', { html: 'Welcome to my app', fullscreen: true });
그러나 이 것 보다 실제로 더 많이 쓰이는 방법은, Ext.define 을 사용하는 방법인데, 센차에서 기본적으로 제공하는 class 를 상속하여 프로그래머가 필요로 하는 class 를 만들고 그 class 를 가지고 instance 를 만드는 방법이다. 아래 코드를 보자.
Ext.define('MyApp.view.Welcome', { extend: 'Ext.Panel', config: { html: 'Welcome to my app', fullscreen: true } }); Ext.create('MyApp.view.Welcome');
위 코드 결과는, 그 위의 코드 결과와 같지만, 프로그래머가 Ext.Panel 을 상속하여 새로 define 한 'MyApp.view.Welcome' 를 계속 사용할 수 있다는 장점이 있다. 실제로 이 방법이 app 을 개발할 때 많이 쓰이는 방법이다.
즉, 센차가 제공하는 components class 를 상속하여 새로운 class 를 만들고, 그렇게 새로 만들어진 class 를 가지고 나중에 instance 를 만들 때 사용하는 것이다.
Ext.define 을 사용하므로써 바뀐 부분은 아래와 같다.
- Ext.define allows us to create a new class, extending an existing one (Ext.Panel in this case) : 새로운 클래스를 만든다. 이 때 이미 있는 클래스를 상속하여 만든다.
- We followed the MyApp.view.MyView convention for our new view class. You can name it whatever you like but we suggest sticking with convention : MyApp.view.MyView 관습을 따른다.
- We defined config for the new class inside a config object : config 객체 안에 새로 만드는 클래스에 적용할 속성을 define 한다.
예를 들어 Ext.Panel 을 상속하여 새로운 class 를 define 할 때, 새로 define 하는 class 의 속성에 이미 부모 class 인 Ext.Panel 에 명시 돼 있는 각종 config 들 중에 일부는 값을 할당해 주면서 define 하고 싶을 수 있다. 이 때는, 상속 받을 새 class 의 config 객체에서 지정해 주면 된다.
혹은 Ext.Panel 을 상속해서 새로 class 만든 뒤, 그 새로 만든 class 를 가지고 instance 를 만들 때 config 에 값을 줄 수도 있다.
이 두 가지 방법이 바로 아래 코드에 나와 있다.
Ext.define('MyApp.view.Welcome', { extend: 'Ext.Panel', config: { html: 'Welcome to my app', fullscreen: true } }); Ext.create('MyApp.view.Welcome', { styleHtmlContent: true });
예제를 한번 봅시다.
Ext.define('Twitter.view.SearchBar', { extend: 'Ext.Toolbar', xtype : 'searchbar', requires: ['Ext.field.Search'], config: { ui: 'searchbar', layout: 'vbox', cls: 'big', items: [ { xtype: 'title', title: 'Twitter Search' }, { xtype: 'searchfield', placeHolder: 'Search...' } ] } });
위 예제 코드는 Ext.Toolbar 를 확장하여 Twitter.view.SearchBar 라는 class 를 만든다. 이 때 사용될 수 있었는 filed 값들은 extend 말고도 여러가지 속성들이 사용된다.(xtype, requires, config 등등)
먼저 결과 화면 부터 보자.
여기서 두 가지를 유심히 보자.
1. requires 는 items 부분에서 사용하는 components 들 중에 추가로 필요로 하는 class 들을 명시를 해준다.
가령 Ext.Toolbar 를 검색 해 보면, requires 에 Ext.Button, Ext.Spacer, Ext.Title 가 있는 것을 알 수 있다.
그러나 위의 코드에서는 searchfield 를 추가적으로 사용하고 있고, 이는 기본적으로 명시된 requires 에 없는 class 이기 때문에, dynamic loading system 은 이 순간에 이게 어떤 class 인지를 모른다. 그러므로 requires 에 searchfield 의 full name 을 명시해서 추가적으로 load 할 수 있도록 한다.
requires: ['Ext.field.Search'], <-- 그래서 이게 필요한 것이다.
2. xtype : 우리가 새로 만든 type 에 대해 새로운 xtype 을 부여한다. 이 xtype 은 다른 곳에서 사용할 수 있다.
아래는 새로 만든 class 를 가지고 instance 를 만드는 두 가지 방법을 보여준다.
//creates a standalone instance Ext.create('Twitter.view.SearchBar'); //alternatively, use xtype to create our new class inside a Panel Ext.create('Ext.Panel', { html: 'Welcome to my app', items: [ { xtype: 'searchbar', docked: 'top' } ] });
커스톰한 설정 주기!
예제를 통해 알아보자! 지금 우리가 하려는 것은 image view 를 만드는데, 해당 image 를 touch 하면 그에 해당하는 title 과 설명(description) 을 보여주는 image view 를 만들려고 한다. Ext.img 가 대부분의 우리가 필요로 하는 view 로써의 속성을 가지고 있기 때문에 Ext.Img 를 활용을 할 것이다.
결과 화면 먼저 보자 (아래 코드를 그대로 실행한 결과 화면은 아니다. 거의 차이는 없지만..)
Ext.define('MyApp.view.Image', { extend: 'Ext.Img', config: { title: null, description: null }, //sets up our tap event listener initialize: function() { this.callParent(arguments); this.element.on('tap', this.defaultTap, this); }, //this is called whenever you tap on the image defaultTap: function() { Ext.Msg.alert(this.getTitle(), this.getDescription()); } }); //creates a full screen tappable image Ext.create('MyApp.view.Image', { title: 'Orion Nebula', description: 'The Orion Nebula is rather pretty', src: 'http://apod.nasa.gov/apod/image/1202/oriondeep_andreo_960.jpg', fullscreen: true });
config 에 보면 title 과 description 이 포함 된 것을 알 수 있다. 이는 기존의 Ext.Img 에서는 없는 config 속성이었다. 그러므로 앞으로 'MyApp.view.Image' 으로 image view 를 만들 때는 (다른 config 속성을 줄 때와 마찬가지로) title 과 description 속성을 주고 값을 줄 수 있다.
주위 깊게 볼 부분은 initialize 부분이다. 해당 function 은 처음 instance 를 만들 때 호출 되는 function 이다. (모든 component 에 해당)
이 내부에서
this.callParent(arguments);
는 superclass 의 initialize function 을 호출하는 역할을 한다. 이게 없다면 정상적으로 작동하지 않기 때문에 반드시 포함시켜야 한다.
callParent 를 했으니, 이제 tap event 가 발생했을 때 이미지의 title 과 description 을 출력할 수 있도록 해주기 위한 장치를 마련해야 한다. this.element.on('tap', this.defaultTap, this);
는 tap 이라는 이벤트가 발생했을 때, defaultTap 이라는 함수가 event handler 가 되어 해당 이벤트를 처리 해주라는 의미이다. 이 때 this 는 핸들링하는 함수가 실행될 때의 scope 을 의미하는데, 보통 this 를 많이 쓴다. (on 은 addListener 의 별칭이다. http://docs.sencha.com/touch/2-0/#!/api/Ext.mixin.Observable-method-addListener )
this.element.on('tap', this.defaultTap, this);
를 좀 더 살펴 보면,
on 은 tap 이라는 이름의 이벤트에 대해서 listener 를 해당 component 의 element 에 더할 수 있도록 해준다. 그러므로, 해당 component 의 element 가 tap 될 때 마다 defaultTap 이 호출되는 것이다. 모든 component 들은 자기 자신에 해당하는 element 속성을 가지고 있기 때문에, DOM 객체에 발생하는 이벤트들을 듣기 위해서는 위에서 보는 것처럼 처리하면 된다.
그 이외에도 각 components 에 속한 elements 에 style 을 추가/삭제 할 수 있으며, Ext.dom.Element 과 관련된 동작 등을 수행할 수 있다. (DOM 에 대한 보다 자세한 정보는 http://jokergt.tistory.com/62 를 참조!)
그리고 중요한 것은 config 에 새로운 속성을 추가할 경우, 자동적으로 getter setter 가 생성된다는 점이다
더욱 발전된 속성?!!
config 안에 주어진 속성들에 대해서 자동적으로 getter setter 가 생긴다는 것은 이미 위에서 언급한 사항이다. 아래 코드를 보자.
Ext.define('MyApp.view.MyView', { extend: 'Ext.Panel', config: { border: 10 } }); var view = Ext.create('MyApp.view.MyView'); alert(view.getBorder()); //alerts 10 view.setBorder(15); alert(view.getBorder()); //now alerts 15
그러나 단지 getter setter 가 생기는 것만은 아니다.
Ext.define('MyApp.view.MyView', { extend: 'Ext.Panel', config: { border: 0 }, applyBorder: function(value) { return value + "px solid red"; }, updateBorder: function(newValue, oldValue) { this.element.setStyle('border', newValue); } });
위의 경우 처럼 추가적으로 apply~~ 와 update~~ 함수를 정의할 수 있다.
위의 예제 에서는 applyBorder 의 경우, border 값이 정해지거나 바뀔 때마다 호출된다. (처음 instance 로 만들어 질 때도 호출이 된다.) 이 함수(~~border)는 config 속성의 값을 바꿀 때 사용하기 좋다. 이 함수가 제대로 작동하기 위해서는 값을 return 해야 하며, 이는 (위의 예제처럼) 입력된 값을 새로운 값으로 바꿔주는 역할을 한다.
updateBorder 는 applyBorder 가 호출 된 뒤에 호출된다. 여기서는 바뀐 border 값을 바로 style 적용할 수 있도록 하였다.
아래는 이를 활용한 코드이다.
//as before Ext.define('MyApp.view.MyView', { extend: 'Ext.Panel', config: { border: 0 }, applyBorder: function(value) { return value + "px solid red"; }, updateBorder: function(newValue, oldValue) { this.element.setStyle('border', newValue); } }); //create an instance of MyView with a spinner field that updates the border config var view = Ext.create('MyApp.view.MyView', { border: 5, fullscreen: true, styleHtmlContent: true, html: 'Tap the spinner to change the border config option', items: { xtype: 'spinnerfield', label: 'Border size', docked: 'top', value: 5, minValue: 0, maxValue: 100, increment: 1, listeners: { spin: function(spinner, value) { view.setBorder(value); } } } });
결과 화면은 아래와 같다.
MVC 패턴 안에서 view !
MVC 방식을 아직 배우지는 않았지만 훗날을 위에 미리 지금 공부하자.
view 를 만들 때 따라야 하는 규칙이 있다.
우리가 만든 클래스가 가령
MyApp.view.MyView
라면 해당 클래스를 정의하는 파일은 반드시
app/view/MyView.js
이 파일 안에 정의 되 있어야 한다.
파일 뿐 아니라 파일이 어디 속해있는지도 유심히 봐야 한다.
이렇게 규칙을 따라 줘야 application 이 원하는 클래스를 찾아서 load 할 수 있다.
//contents of app.js Ext.application({ name: 'MyApp', views: ['MyView'], launch: function() { Ext.create('MyApp.view.MyView'); } });
위의 코드를 보면 views: ['MyView'] 를 통해 우리가 추가한 MyView class 를 load 하고, Ext.create 를 활용해서 해당 class 타입의 instance 를 만들어 주고 있다.
'Sencha Touch 2' 카테고리의 다른 글
5일차 : Sencha Touch 2 layout 에 대한 이해 (0) | 2012.06.28 |
---|---|
HW3 : Sencha Touch 2 View 사용하기 (0) | 2012.06.28 |
Extra2 : Sencha Touch 2 Unexpected identifier (0) | 2012.06.27 |
HW2 : Sencha Touch 2 Components 를 활용하기 (0) | 2012.06.27 |
3일차 : Sencha Touch 2 Components 에 대한 이해! (0) | 2012.06.26 |