Appspresso Studio(앱스프레소 스튜디오)는 이큽립스 기반의 하이브리드 앱 개발에 필요한 SDK를 포함한 IDE 이다. 이클립스 기반이라는 말은 JRE를 이용하고 Java VM 위에서 동작하는 IDE라는 말이다.



Appspresso Studio를 열고 About Appspresso Studio를 열어보면 현재 설치되어 있는 앱스프레소 스튜디오 정보를 확인할 수 있는데 밑에보면 Appspresso Studio에 포함된 플러그인들을 확인할 수 있다.


1. WTP (Web Tools Platform)

WTP는 이클립스의 메이저 개발 툴 플러그 인으로 웹 개발을 할 때 사용하는 플러그인이다. Appspresso 로 만들어지는 앱은 웹과 네이티브 코드가 같이 만들어야하기 때문에 웹 개발툴이 포함되어 있는 것은 지극히 당연한 것일 것 이라 생각된다. 또한 WTP에는 XML 에디터가 포함이 되어 있는데 이것은 XML의 속성을 정의하고 추가할 때 code로 입력하는 것이 아니라 WTP에서 제공하는 key, value 형식의 GUI 입력기를 사용할 수 있게 지원하고 있다. 그래서 우리가 project.xml이나 다른 앱스프레소 설정에서 사용되는 xml 에서 입력기를 이용해서 속성을 간단하게 추가할 수 있는 것이다.





2. Eclipse 

Appspresso Studio는 Eclipse 기반으로 만들어진 IDE이다. 현재 3.7.2 (코드명 Indigo) 기반에 만들어진 것을 확인할 수 있다.



3. Appsrpesso Studio

현재 사요중인 Appspresso Studio는 1.1.0 버전이고 2012년 4월 27일에 릴리즈된 버전이라는 것도 확인할 수 있다.



4. EMF

마지막으로 포함된 플러그인은 EMF(Eclipse Modeling Framework Core Runtime)이다. 이 플러그인은 객체를 모델링하거나 GUI 입력기를 사용할때 사용되는 플러그인인데, 아직은 앱스프레소에서 그래프 형태의 에디터는 보이지 않지만 향후에는 Xcode의 xib나 안드로이드의 GUI 툴과 같은 인터페이스를 제공해주지 않을까 조심스레 기대해본다.



이렇게 Appspresso Studio는 IDE와 Plugins 모두가 JRE를 이용하고 Java VM 위에서 동작하고 있다. 이말은 Java VM의 자원을 사용한다는 것이다. 이러한 이유로 코드량이 많아지면 Java VM에서 사용하는 자원인 메모리 영역이 부족한 현상을 겪게 될 수 있다. Java VM도 일종의 어플리케이션이고 운영체제 위에서 메모리를 할당 받고 그 안에서 운영중인 Java application을 관리하게 되는데, Appspresso Studio의 사용률이 높아지면서 메모리를 점유하거나 대량의 코드를 메모리에 올려서 작업할 때 VM의 메모리가 부족해서 문제가 발생할 수도 있다는 것이다. 이러한 문제는 코드가 크지면 발생하게 되는데 이유는 Appspresso Studio가 Eclipse 기반으로 만들어졌기 때문에 Eclipse가 가지고 있는 Code Assiatant의 동작과 indexing 기능을 사용하기 때문이다. 이 두가지는 우리가 Eclipse를 사용할 때 아주 편리하게 코드를 작성하기 위해서 탭이나 . 을 찍으면 자동으로 관련된 코드를 힌트로 보여준다거나, 관련된 클래스의 정보(메소드, 변수, 주석)등을 보여주기 위해서 코드를 분석해두는 일을 하는 것이다.


Appspresso Studio를 디폴트로 설치한 후 Sencha Touch 2 라이브러리를 추가하고 sencha-touch-all-debug.js를 여는 순간 Appspresso Studio는 갑자기 멈추는 현상이 일어난다거나, git에 올려둔 코드를 다른 곳에서 clone 해서 열었는데 다음과 같은 에러를 만날 수 있다는 것이다.



코드를 열면서 Appspresso Studio가 코드를 분석해서 인덱싱을하는 도중에 Building workspace를 하는 동안 Java heap space의 문제를 알려주는 경고이다. 이 문제는 Appspresso Studio가 사용하는 IDE가 동작할때 사용하는 힙의 크기가 부족해서 발생하는 문제이다. 우리는 이 문제를 해결하기 위해서 Appspresso Studio가 사용할 수 있는 힙 사이즈를 더 크게 변경해줄 것이다.


여러분들이 앱스프레소 스튜디오를 다운받아서 설치한 폴더 안에 appspresso.app/Contents/MacOS 폴더로 이동한다. 보통 애플리케이션은 /Applications  폴더로 이동시켜둔다고 가정하고 진행한다.


cd /Applications/Appspresso/appspresso.app/Contents/MacOS


맥에서는 .app으로 해당 애플리케이션을 패키징화 시켜두는데 그 안에 Contents/MacOS에서 appspresso.ini 파일이 존재한다. 이것은 애플리케이션에 관련된 initialization 파일로 애플리케이션이 시작할 때 애플리케이션을 설정하는 사항이 포함되어 있다.


-startup

../../../plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar

--launcher.library

../../../plugins/org.eclipse.equinox.launcher.cocoa.macosx.x86_64_1.1.101.v20120109-1504

--launcher.XXMaxPermSize

256m

-vmargs

-Dfile.encoding=utf-8

-XstartOnFirstThread

-Dorg.eclipse.swt.internal.carbon.smallFonts


디폴트로 설정되어 있는 appspresso.ini 파일에는 startup 할때 사용하는 launch와 그리고 library 그리고 launcher의 MaxPermSize 사이즈 그리고 -vmargs이 바로 JavaVM의 옵셥인데 인코딩과 쓰레드 등이 설정되어 있다.

우리는 여기서 힙사이즈를 설정하는 코드를 추가한다.


-startup

../../../plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar

--launcher.library

../../../plugins/org.eclipse.equinox.launcher.cocoa.macosx.x86_64_1.1.101.v20120109-1504

--launcher.XXMaxPermSize

256m

-vmargs

-Dfile.encoding=utf-8

-XstartOnFirstThread

-Dorg.eclipse.swt.internal.carbon.smallFonts

-Xms512m

-Xmx512m


이 설정은 Eclipse의 힙사이즈를 설정하는 방법과 동일한데, perm는 클래스의 메타 정보가 저장되는 공간이고, Xms는 힙사이즈, Xmx는 최대 힙사이즈 크기를 설정하는 것이다. (보통 힙사이즈와 최대 힙 사이즈를 동일하게 해주라고 권장하고 있다.) 힙사이즈가 크면 클 수록 좋다고 생각할지 모르겠지만, 힙사이즈를 키우면 운영체제가 사용하는 메모리가 부족하게 되거나 다른 애플리케이션이 사용하는 힙사이즈가 줄어들어 컴퓨터 자체의 속도가 줄어들어 오히려 역효과가 생길수도 있으니 상황에 맞게 조정하는 것이 좋다. 


저장하고 다시 Appsresso Studio를 실행시키면 힘사이즈 크기로 생기는 문제를 해결할 수 있다.


<참조>

1. http://wiki.eclipse.org/Eclipse.ini


<Sencha Touch 2 튜토리얼 관련 포스트>

http://blog.saltfactory.net/category/Sencha


<Appsrpesso 튜토리얼 관련 포스트>

1. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 1. 빌드

2. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 2. 디버깅 (on the fly; 빌드없이 변경사항 바로 확인하기)

3. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 3. 내장 플러그인으로 원격데이터 요청

4. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 4. ADE (Appspresso Debug Extension) 으로 디버깅하기

5. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 5. PDK를 이용하여 네이티브 코드 사용

6. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 6. 디바이스로 빌드하기

7. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 7. xcode-select 사용하여 빌드하기

8. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 8. 지역화 적용

9. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 9. 푸시 적용 (iOS)

10. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 10. 푸시 적용 (Android C2DM)

11. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 11. WAC 사용- Deviceapis 확인

12. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 12. WAC 사용- DeviceStatus

13. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 13. WAC 사용- AddressBook, Contact (주소록, 연락처)

14. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 14. Sencha 로 UI 프레임워크 사용 - (1) 뷰 (view)추가

15. Appspresso를 사용해서 iPhone 과 Android 앱 동시에 개발하기 - 15. 앱스프레소 힙사이즈 문제 해결


작성자 : 송성광 개발 연구원 

프로필 : http://about.me/saltfactory

이메일 : saltfactory@gmail.com

트위터 : @saltfactory

페이스북 : http://facebook.com/salthub

연구소 : 하이브레인넷 부설연구소

저작자 표시 비영리 동일 조건 변경 허락
Posted by saltfactory

오늘은 어떻게보면 갑작스런 컨퍼런스 참석이 아니였나 생각이든다. 평소에 연구소 팀장님이 먼저 컨퍼런스 이야기를 잘 안하시는데, 이번 컨퍼런스는 NFC와 Cloud 내용이 포함되어 있어서 먼저 참석해보자고 말씀하셨다. 제목도 "Big Issue Of Mobile" 이라는 주제로 정말 모바일의 중요한 세가지 이슈를 들을 수 있는 좋은 기회라고 생각하면서 컨퍼런스 며칠전에 등록신청을하고 상경하게 되었다.


Big Data, HTML5, Cloud, NFC 주제어를 키워드를 가지고 있어서 정말 요즘 대두되고 있는 키워드들의 집합이 아닌가하는 마음가짐으로 컨퍼런스에 참석하게 되었다. 하지만, 너무 기대가 컸던 것일까... 내가 원하던 기술적 내용을 듣지 못해서일까? 오늘은 컨퍼런스 마치고 내려오는 서울에 자꾸만 미련이 남았던 것 같다. 하지만 참석자 모두 나와 같은 생각은 아니였을것이라고 생각이든다. 기술적 내용은 없었지만, 이슈와 트랜드에 대해서는 리뷰와 오버뷰 형식으로 발표하는 강연이였기 때문에 이제 모바일 사업으로 출발하려는 스타트업 기업이나, 전반적인 서비스의 트랜드를 듣기 원했던 참석자에게는 부담없이 듣고 갈 수 있는 자리였을 것이라 생각된다.


첫번째 세션은 플랫폼 비즈니스의 승자와 패자 세션 시간에는 다음 주제로 강연이 이루어졌다.

1. 플랫폼의 해설, 보이지 않는 성공엔진 플랫폼의 중요성

2. 플랫폼 비즈니스의 진화, 성공 플랫폼의 키워드는?

3. 플랫폼을 가진자, 21세기를 지배한다.

4. 이들은 어떻게 성공하였고 쇠퇴하였는가?

5. 우리나라 IT 플랫폼 비즈니스의 문제?

6. 우리나라의 플랫폼 성공을 위한 시사점 및 과제


이미 PaaS(Platform as a Service), SaaS(Software as a Service), IaaS(Infrastructure as a Service) 가 화두가 되고 있는 시점에서 약간 진부한 이야기일수도 있지만 최근 사례를 중심으로 Apple, Google, IBM 그리고 MS 를 비교하여 표를 만들어서 소개해주서 Keynote가 오픈되면 한번쯤 참고해도 좋을 자료가 될 것 같다는 생각이든다. 다만 Paas, SaaS, IaaS 라는 용어가 명시적으로 나와서 설명이 되지 않아서 조금 아쉽기는 했지만, 강연 내용에 그 내용도 포함되어 있었다. 듣는 사람에 따라서는 모바일 사업이 대중화되면서 OS에 종속적이고 폐쇄적인 플랫폼에서 오픈 플랫폼 변경되어 있는 것에 이미 익숙한 개발자나 IT 종사자들에게는 이미 익숙한 내용이였을 수도 있고, 처음 모바일이나 오픈 플랫폼 위에서 사업을 처음 준비하는 분들에게는 좋은 자료가 되었을 거라고 생각이든다. 




스마트기기를 위한 Big Data 전략 가이드에 대한 세션에는 다음과 같은 주제로 강연이 이루어졌다.

1. 빅데이타 전략 도입의 가치는 무엇인가?

2. 왜 스마트기기 분야에 빅 데이타가 필요한가?

3. 스마트기기에서 가능한 빅데이타의 전략 방향

4. 빅데이터 도입에 대한 장벽


강연자가 현재 전략 업무에 종사하시는 분이시라 Big Data의 기술적인 디테일 설명보다는 빅 데이터 전략 방향에대해 강연이 진행이 되었다. 개인적으로는 좀더 디테일한 기술적 소개를 듣고 싶었지만, 빅데이터를 처음 접하는 사람에게는 리뷰가 될 수 있는 세션이였던것 같다. 모바일 서비스 분야에서 뿐만 아니라 빅데이터의 잠재적 가치와 활용사례 등을 좀더 자세히 듣고 싶었는데 이에 대한 아쉬움은 5월 31일에 있는 3Big Technology에서 얻을 수 있을것 같다는 생각이 들었다. 세션 내용은 대부분 포괄적인 리뷰 내용들이였던 것 같다. 





모바일 Cloud 전쟁과 플랫폼 전쟁이라는 세션에는 다음과 같은 주제로 강연이 진행 되었다.

1. 모바일 Cloud

2. Cloud 플랫폼 현황

3. 플랫폼 트랜드

4. 플랫폼 선택 포인트


앞에 세션들과 다르게 이번 세션은 마인드 맵으로 강연이 진행되었는데, 기존의 파워포인트의 강연과 달라서 참신했던것 같다. 그리고 현 개발자로 종사하고 계시는 분이시라 dropbox에 관련된 샘플 코드를 안드로이드 시뮬레이터를 돌려서 보여주시는 기술적 소개도 잠시 있었다. 이 세션에는 주로 dropbox, evernote 등의 현재 클라우드 대표 서비스에 대해서 소개가 되어졌다. 이번 세션도 okjsp 에서 발표하는 세션이라 나름 디테일한 기술적 내용을 들을 수 있을거라 예상했는데 클라우드 앱과 서비스의 소개만 이루어 져서 아쉬웠는데 아마도 이번 컨퍼런스 자체가 이슈와 트랜드에 대한 전반적인 리뷰나 오버뷰를 컨셉트로 잡은 것 같다는 생각이 들었다. 디테일한 기술적인 내용은 아쉬웠지만 모바일 서비스를 이제 시작하려고 준비하는 분들에게는 간략한 트랜드 소개가 되는 자리였을 것 같다.





NFC의 과거, 현재, 미래라는 세션에는 다음과 같은 주제로 강연이 진행되었다.

1. NFC의 역사

2. NFC의 기술, UX, Biz, Model

3. NFC의 개방성, 상호협력, 보안성, 편리성


사실 이번 컨퍼런스에 참석하게된 가장 큰 이유가 바로 이 세션 때문이였다. 연구하면서 궁금했던 것이 NFC(Near Field Communication)로 결제에 관한 금융서비스가 아닌 데이터를 서로 주고 받을 수 있는 통신으로 사용할 수 있느냐는 것이였다. 하지만 지금까지 NFC에 대한 이슈는 많았지만 컨퍼런스나 세미나에 참석할 기회가 없었다. 한때 급속하게 화두에 올랐다가 어느순간 잠잠해진 이슈인데 그 이유도 궁금했었기 때문이다. 발표자는 이러한 궁금증을 잘 요약해서 설명해주셔 얻고 싶은 답을 조금 얻고 갈 수 있게 되었다. 단순하게 데이터 커뮤니케이션을 할 수 있는 모델인줄 알았는데 실제는 WiFi나 블루투스처럼 쉽게 데이터를 주고 받을 수 있는 것이 아니라는 생각이 들었다. 그리고 왜 이슈로 되었다가 다시 잠잠해질수 밖에 없었는지에 대해서 간략하게 말씀해주셨다. 발표 내용에 대해서는 자세히 언급하지 않을 생각이다. 나중에 강연자료가 업로드가 되면 링크로 대신할 생각이다. 




작년에는 모바일 개발에 대한 세미나, 컨퍼런스가 많았다면 올해는 Big Data, Cloud, HTML5에 대한 주제가 많다는 것을 느끼게 된다. 지금까지 계속 모바일 서비스 개발에 대해서 집중적으로 참석한 반면 올해는 Big Data, Cloud 에 대한 관점을 집중해보기로 했다. 실제 모바일 서비스를 연구하다보면 예전에 웹서비스에 익숙하던 서버-클라이언트 모델로는 현재의 서비스를 구현하는데 한계가 있다는 것을 느끼기 때문이다. 좀더 적은 비용으로 좀 더 효과와 효율을 극대화 할 수 있는 방법이 바로 이러한 주제어에 관련된 내용이 아닌가 생각이 든다. 오늘 참석한 세션들 모두 전반적으로 리뷰나 오버뷰 느낌이 강했다는 생각이 들었다. 이미 유사 컨퍼런스와 세미나를 다녀와서 중복되는 내용이 있어서 아쉽기도 했지만, 다시한번 정리할 수 있었고 기술 현황을 들을 수 있어서 좋았던것 같다. 한국무선인터넷산업연합회에서 개최된 컨퍼런스 였던만큼 무선 인터넷의 기술과 무선 인터넷 중심적 자료를 더 깊게 다루어 주었으면하고 아쉽기도 했고, 처음 참석하려고 했던 마음가짐에 기술적인 내용을 기대하고 갔기 때문에 기술적인 내용이 없어서 아쉬운 자리였지만, 모바일에 관련된 이슈와 트랜드에 대한 센션마다의 짦은 정리에 그동안 기술적으로만 접근하고 살펴보았던 모바일 관련 서비스에 대해서 정리할 수 있는 시간이였던것 같다.



저작자 표시 비영리 동일 조건 변경 허락
Posted by saltfactory

앱을 만들다보면 가장 많이 사용하는 UI가 바로 아이폰에서는 UITableView 이고 안드로이드폰에서는 ListView가 아닌가  생각된다. 리스트는 데이터를 출력시키는 UI로 모든 앱에서 반드시 필요하고 가장 많이 사용하는 UI이다. Sencha에서는 ListView를 Store-bound components 범주에 포함시키기고 있다. 이유는  Store라는 것을 사용하는 Ext.Component 들 중에 하나이기 때문이다. Sotre는 나중에 Sencha의 Model에가서 좀더 자세히 설명할 것이다. 여기선 뷰에 데이터를 출력시키는 데이터 저장 공간으로 생각하기로 하자. 


1. DataView


DataView는 말 그래도 data를 가지고 표현하는 view 이다. store라는 곳에 데이터를 임시적으로 캐싱해서 fields에 맞는 데이터들을 반복해서 출력하게 되는데 이 때, itemTpl 이라는 속성에서 {} 표현식 안에 store에 저장된 field의 이름을 매핑해서 출력할 수 있다. 이 방법은 Rails나 Django 등에서 view template에서 데이터를 표현하는 방법과 같은 방법이다.

우리는 앞에서 살펴본 코드에 다음과 같이 코드를 수정하자.


/** 

* file : MainView.js

* author : saltfactory

* email : saltfactory@gmail.com

*/


Ext.define('SaltfactorySenchaTutorial.view.MainView', {

extend: 'Ext.Panel',

alias: 'main_view',

config: {

    styleHtmlContent: true,

//html: '<h1>Hello, World!</h1>',

fullscreen: true,

layout:{

type: 'card',

align: 'start',

pack: 'start'

}

},


initialize: function(){

var titlebar = {

xtype: 'titlebar',

docked: 'top',

title: 'Home',

items: [

{

xtype: 'button',

iconCls: 'compose',

iconMask: true,

align: 'right',

handler:function(){

console.log('tap compose button')

}

}

]

}

var toolbar = {

xtype : 'toolbar',

docked: 'bottom',

items: [

{

xtype: 'spacer'

},

{

xtype: 'button',

iconCls: 'info',

iconMask: true

}

]

}

var dataview = {

xtype: 'dataview',

fullscreen: true,

store: {

autoLoad: true,

fields: ['contact', 'url'],

data: [

{contact: 'twitter', url: 'http://twitter.com/saltfactory'},

{contact: 'facebook', url: 'http://facebook.com/salthub'},

{contact: 'blog', url: 'http://blog.saltfactory.net'}

]

},

itemTpl: '<div> saltfactory\'s {contact} is  <a href="{url}">{url}</a>'

}



this.add([titlebar, dataview, toolbar])

}

});



위의 코드에 대해서 다시 좀더 설명을 하자면, Ext.dataview.DataView에서 저장된 되이터를 출력할 것인데, store 라는 곳에서 저장된 되이터를 관리한다. 이 때 data 라는 곳에서는 실제 데이터가 저장되어 캐싱되는 곳이고 fields에서 store에 저장된 data의 형태를 정의한다. 그리고 datView에서 데이터를 출력시킬 때는 itemTpl 이라는 속성에서 정의한 대로 출력을 하는데 이 때 {} 를 이용해서 data에 저장된 field의 이름을 매핑해서 html과 같이 렌더링해서 코드를 완성시킨다. 



2. Carousel


Carousel는 회전목마라는 뜻인데 Ext.Carousel은 아이폰의 UIPageController와 동일한 구성을 만들 수 있는 Sencha의 Ext.Component 이다.

위 코드에 Carousel을 구성하기 위한 코드를 추가하고 다음과 같이 수정해보자.


/** 

* file : MainView.js

* author : saltfactory

* email : saltfactory@gmail.com

*/


Ext.define('SaltfactorySenchaTutorial.view.MainView', {

extend: 'Ext.Panel',

alias: 'main_view',

config: {

    styleHtmlContent: true,

fullscreen: true,

layout:{

type: 'card',

align: 'start',

pack: 'start'

}

},


initialize: function(){

var titlebar = {

xtype: 'titlebar',

docked: 'top',

title: 'Home',

items: [

{

xtype: 'button',

iconCls: 'compose',

iconMask: true,

align: 'right',

handler:function(){

console.log('tap compose button')

}

}

]

}

var toolbar = {

xtype : 'toolbar',

docked: 'bottom',

items: [

{

xtype: 'spacer'

},

{

xtype: 'button',

iconCls: 'info',

iconMask: true

}

]

}

var dataview = {

xtype: 'dataview',

fullscreen: true,

store: {

autoLoad: true,

fields: ['contact', 'url'],

data: [

{contact: 'twitter', url: 'http://twitter.com/saltfactory'},

{contact: 'facebook', url: 'http://facebook.com/salthub'},

{contact: 'blog', url: 'http://blog.saltfactory.net'}

]

},

itemTpl: '<div> saltfactory\'s {contact} is  <a href="{url}">{url}</a>'

}

var carousel = {

xtype: 'carousel',

fullscreen: true,

defualts: {

styleHtmlContent: true

},

items: [

{

html: 'Page 1'

},

{

html: 'Page 2'

}

]

}


this.add([titlebar, carousel, toolbar])

}

});



Carousel은 items의 갯수만큼 컴포넌트를 추가할 수 있는 페이지들이 추가가 된다. 예제에서는 items를 두가지로 했기 때문에 2가지 페이지가 추가되었다.



carousel에서 추가되는 items에서는 html 코드말고 Ext.Component도 추가될 수 있다. 우리가 위해서 생성한 dataview 컴포넌트를 carousel의 items에 추가해보자.

/** 

* file : MainView.js

* author : saltfactory

* email : saltfactory@gmail.com

*/


Ext.define('SaltfactorySenchaTutorial.view.MainView', {

extend: 'Ext.Panel',

alias: 'main_view',

config: {

    styleHtmlContent: true,

fullscreen: true,

layout:{

type: 'card',

align: 'start',

pack: 'start'

}

},


initialize: function(){

var titlebar = {

xtype: 'titlebar',

docked: 'top',

title: 'Home',

items: [

{

xtype: 'button',

iconCls: 'compose',

iconMask: true,

align: 'right',

handler:function(){

console.log('tap compose button')

}

}

]

}

var toolbar = {

xtype : 'toolbar',

docked: 'bottom',

items: [

{

xtype: 'spacer'

},

{

xtype: 'button',

iconCls: 'info',

iconMask: true

}

]

}

var dataview = {

xtype: 'dataview',

fullscreen: true,

store: {

autoLoad: true,

fields: ['contact', 'url'],

data: [

{contact: 'twitter', url: 'http://twitter.com/saltfactory'},

{contact: 'facebook', url: 'http://facebook.com/salthub'},

{contact: 'blog', url: 'http://blog.saltfactory.net'}

]

},

itemTpl: '<div> saltfactory\'s {contact} is  <a href="{url}">{url}</a>'

}

var carousel = {

xtype: 'carousel',

fullscreen: true,

layout: 'card',

defualts: {

styleHtmlContent: true

},

items: [

dataview,

{

html: 'Page 2'

}

]

}


this.add([titlebar, carousel, toolbar])

}

});



Carousel의 첫번째 페이지에 위에서 설정한 dataview가 표현되는 것을 확인할 수 있다.


3. List


우리가 앱을 개발할 때 가장 많이 사용할 UI중에 하나인 List는 우리가 앞에서 테스트한 dataview와 동일하게 사용할 수 있다. Sencha는 모든 컴포넌트가 Ext.Component를 상속받아서 사용하는데 Ext.List는 Ext.dataview.DataView를 상속받기 때문에 dataview를 구성하는 것과 동일하게 사용할 수 있는 것이다. 



그래서 우리는 dataview를 다음과 같이 list로 변경을 할 것이다.


/** 

* file : MainView.js

* author : saltfactory

* email : saltfactory@gmail.com

*/


Ext.define('SaltfactorySenchaTutorial.view.MainView', {

extend: 'Ext.Panel',

alias: 'main_view',

config: {

    styleHtmlContent: true,

fullscreen: true,

layout:{

type: 'card',

align: 'start',

pack: 'start'

}

},


initialize: function(){

var titlebar = {

xtype: 'titlebar',

docked: 'top',

title: 'Home',

items: [

{

xtype: 'button',

iconCls: 'compose',

iconMask: true,

align: 'right',

handler:function(){

console.log('tap compose button')

}

}

]

}

var toolbar = {

xtype : 'toolbar',

docked: 'bottom',

items: [

{

xtype: 'spacer'

},

{

xtype: 'button',

iconCls: 'info',

iconMask: true

}

]

}

var dataview = {

xtype: 'list',

fullscreen: true,

store: {

autoLoad: true,

fields: ['contact', 'url'],

data: [

{contact: 'twitter', url: 'http://twitter.com/saltfactory'},

{contact: 'facebook', url: 'http://facebook.com/salthub'},

{contact: 'blog', url: 'http://blog.saltfactory.net'}

]

},

itemTpl: '<div> saltfactory\'s {contact} is  <a href="{url}">{url}</a>'

}

var carousel = {

xtype: 'carousel',

fullscreen: true,

layout: 'card',

defualts: {

styleHtmlContent: true

},

items: [

dataview,

{

html: 'Page 2'

}

]

}


this.add([titlebar, carousel, toolbar])

}

});







우리는 특별한 작업을 하지 않았고 단지 dataview였던 xtype을 list로 변경했는데, 리스트뷰를 생성해서 출력시켜주는 것을 확인할 수 있다. 만약에 리스트에 출력되는 아이템에 Disclosure 버턴을 추가하고 싶으면 다음과 같이 onItemDisclosure 속성을 추가한다.


/** 

* file : MainView.js

* author : saltfactory

* email : saltfactory@gmail.com

*/


Ext.define('SaltfactorySenchaTutorial.view.MainView', {

extend: 'Ext.Panel',

alias: 'main_view',

config: {

    styleHtmlContent: true,

fullscreen: true,

layout:{

type: 'card',

align: 'start',

pack: 'start'

}

},


initialize: function(){

var titlebar = {

xtype: 'titlebar',

docked: 'top',

title: 'Home',

items: [

{

xtype: 'button',

iconCls: 'compose',

iconMask: true,

align: 'right',

handler:function(){

console.log('tap compose button')

}

}

]

}

var toolbar = {

xtype : 'toolbar',

docked: 'bottom',

items: [

{

xtype: 'spacer'

},

{

xtype: 'button',

iconCls: 'info',

iconMask: true

}

]

}

var dataview = {

xtype: 'list',

fullscreen: true,

onItemDisclosure:function(record, btn, index){

// disclouse 버턴이 눌러졌을 , 동작 메소드 정의

},

store: {

autoLoad: true,

fields: ['contact', 'url'],

data: [

{contact: 'twitter', url: 'http://twitter.com/saltfactory'},

{contact: 'facebook', url: 'http://facebook.com/salthub'},

{contact: 'blog', url: 'http://blog.saltfactory.net'}

]

},

itemTpl: '<div> saltfactory\'s {contact} is  <a href="{url}">{url}</a>'

}

var carousel = {

xtype: 'carousel',

fullscreen: true,

layout: 'card',

defualts: {

styleHtmlContent: true

},

items: [

dataview,

{

html: 'Page 2'

}

]

}


this.add([titlebar, carousel, toolbar])

}

});



4. Nested List


Store-bound components 에 속한 Ext.component로 마지막으로 Ext.dataview.NestedList 컴포넌트가 있다. 이것은 말 그래도 List와 동일한데 자식 List를 가지고 있는 경우를 말한다. 이것은 우리가 아이폰에서 navigationController에 viewController를 push하는 것과 동일한 기능을 구현한 것이다. Nsted List는 List 를 구성하는 store를 TreeStore로 저장된 data 안에 단계적으로 다른 data가 존재하는 경우이다. Nested List를 설명하기 위해서는 Model을 알고 있어야하는데 Model은 다음 포스팅에 소개할 예정이고 여기서 Model은 간단하게 데이터가 어떻게 저장될지를 논리적으로 정의한 객체라고만 알아두자. 다음과 같이 Nested List를 테스트하기 위한 코드를 추가하자.


/** 

* file : MainView.js

* author : saltfactory

* email : saltfactory@gmail.com

*/


Ext.define('SaltfactorySenchaTutorial.view.MainView', {

extend: 'Ext.Panel',

alias: 'main_view',

config: {

    styleHtmlContent: true,

fullscreen: true,

layout:{

type: 'card',

align: 'start',

pack: 'start'

}

},


initialize: function(){

var titlebar = {

xtype: 'titlebar',

docked: 'top',

title: 'Home',

items: [

{

xtype: 'button',

iconCls: 'compose',

iconMask: true,

align: 'right',

handler:function(){

console.log('tap compose button')

}

}

]

}

var toolbar = {

xtype : 'toolbar',

docked: 'bottom',

items: [

{

xtype: 'spacer'

},

{

xtype: 'button',

iconCls: 'info',

iconMask: true

}

]

}

var dataview = {

xtype: 'list',

fullscreen: true,

onItemDisclosure:function(record, btn, index){

// disclouse 버턴이 눌러졌을 , 동작 메소드 정의

},

store: {

autoLoad: true,

fields: ['contact', 'url'],

data: [

{contact: 'twitter', url: 'http://twitter.com/saltfactory'},

{contact: 'facebook', url: 'http://facebook.com/salthub'},

{contact: 'blog', url: 'http://blog.saltfactory.net'}

]

},

itemTpl: '<div> saltfactory\'s {contact} is  <a href="{url}">{url}</a>'

}

var carousel = {

xtype: 'carousel',

fullscreen: true,

layout: 'card',

defualts: {

styleHtmlContent: true

},

items: [

dataview,

{

html: 'Page 2'

}

]

}

var data = {

    text: 'Groceries',

    items: [{

        text: 'Drinks',

        items: [{

            text: 'Water',

            items: [{

                text: 'Sparkling',

                leaf: true

            }, {

                text: 'Still',

                leaf: true

            }]

        }, {

            text: 'Coffee',

            leaf: true

        }, {

            text: 'Espresso',

            leaf: true

        }, {

            text: 'Redbull',

            leaf: true

        }, {

            text: 'Coke',

            leaf: true

        }, {

            text: 'Diet Coke',

            leaf: true

        }]

    }, {

        text: 'Fruit',

        items: [{

            text: 'Bananas',

            leaf: true

        }, {

            text: 'Lemon',

            leaf: true

        }]

    }, {

        text: 'Snacks',

        items: [{

            text: 'Nuts',

            leaf: true

        }, {

            text: 'Pretzels',

            leaf: true

        }, {

            text: 'Wasabi Peas',

            leaf: true

        }]

    }]

};


Ext.define('ListItem', {

    extend: 'Ext.data.Model',

    config: {

        fields: [{

            name: 'text',

            type: 'string'

        }]

    }

});


var store = Ext.create('Ext.data.TreeStore', {

    model: 'ListItem',

    defaultRootProperty: 'items',

    root: data

});


var nestedlist = Ext.create('Ext.NestedList', {

    fullscreen: true,

    title: 'Home',

    displayField: 'text',

    store: store,

     toolbar:titlebar

});


this.add([nestedlist, toolbar])

}

});



새로 고침해서 웹앱을 재 실행해보자. 아래 그림처럼 세 단계에 데이터 깊이가 있고 각각 하위 데이터가 있으면 nested list는 마치 navigationcontroller에 viewcontroller을 푸시 하듯이 내부로 들어가게된다. 이 때 상단의 백 버턴에는 바로 이전에 선택된 아이템의 텍스트가 나타난다는 것을 확인할 수 있을 것이다. 이것은 iOS의 NavigationController에서 백버턴의 구성과 동일하다. 그림지 작아서 볼 수 없다면 클릭해서 확인할 수 있다.



테스트에 사용된 data는 Sencha Touch2 의 공식 메뉴얼에 포함된 데이터이다. NestedList는 데이터를 네비게이션하기 때문에 자체적으로 Toolbar를 포함하고 있다. 그래서 NestedList에 toolbar를 교체하기 위해서는 외부에서 Ext.Toolbar를 설정해서 넣어주면 된다. 우리는 이미 titlebar라는 것을 만들어 두었기 때문에 NestedList의 toolbar를 titlebar로 지정하였다. NestedList에 관해서는 Ext.data.Model을 설명할 때 다시한번 더 소개하겠다.


이번 포스팅에서는 Ext.Component 중에서도 Store-bound components에 대해서 살펴보았다. 여기에 속한 UI는 앱을 구성할 때 가장 많이 사용하는 UI 컴포넌트들이라 매우 중요한 부분이다. 실제 네이티브 앱에서도 UITableView나 ListView가 가장 많이 사용되기 때문이다. 그리고 NavigationViewController와 같이 리스트의 내부에 자식 데이터가 있으면 마치 navigationcontroller에 push를 하듯 하위로 들어갈 수 있는 UI 컴포넌트가 NestedList라는 것도 확인했다. 다만 Ext.dataview.NestedList는 Ext.data.Model을 상요하는데 우리는 아직 Model을 테스트하지 않아서 단순히 Model은 데이터가 어떻게 저장되는지 논리적으로 정의한 객체라고만 알고 그 모델을 이용해서 NestedList의 Store에 TreeStore로 저장되어 NestedList UI를 구성한다는 것을 알았다. 그리고 NestedList는 자체적으로 toolbar를 가지고 있고 하위로 내려가면 선택된 텍스트가 하위의 백버턴에 그 내용이 나온다는 것을 확인했고, toolbar를 변경하기 위해서 외부에서 Ext.Toolbar를 정의해서 넣어줘야한다는 것도 알게되었다. 이제 우리는 간단한 앱을 만들 수 있는 UI의 조건을 모두 배웠다. 다음 포스팅에서는 Sencha의 Ext.data.Model에 관해서 포스팅할 예정이다.


<참고>

1. http://docs.sencha.com/touch/2-0/#!/api/Ext.dataview.DataView

2. http://docs.sencha.com/touch/2-0/#!/api/Ext.carousel.Carousel

3. http://docs.sencha.com/touch/2-0/#!/api/Ext.dataview.List

4. http://docs.sencha.com/touch/2-0/#!/api/Ext.dataview.NestedList



<Appsrpesso 튜토리얼 관련 포스트>

http://blog.saltfactory.net/category/Appspresso


<Sencha Touch 2 튜토리얼 관련 포스트>

1. Sencha Touch 2 (센차터치)를 이용한 웹앱 개발 - 1. 설치, 생성, 패키징, 빌드(device, simulator)

2. Sencha Touch 2 (센차터치)를 이용한 웹앱 개발 - 2. 뷰(View) 생성

3. Sencha Touch 2 (센차터치)를 이용한 웹앱 개발 - 3. 뷰(View) 구성 - 컴포넌트 생성,구성

4. Sencha Touch 2 (센차터치)를 이용한 웹앱 개발 - 4. 뷰(View) 구성 - Navigation Components

5. Sencha Touch 2 (센차터치)를 이용한 웹앱 개발 - 5. 뷰(View) 구성 - Store-bound components (리스트 뷰)


작성자 : 송성광 개발 연구원 

프로필 : http://about.me/saltfactory

이메일 : saltfactory@gmail.com

트위터 : @saltfactory

페이스북 : http://facebook.com/salthub

연구소 : 하이브레인넷 부설연구소


저작자 표시 비영리 동일 조건 변경 허락
Posted by saltfactory