NAV Navbar
xml

시작하기

HTML5와 이를 사용하는 여러 웹앱 개발 프레임워크 등장으로 많은 웹앱이 개발되고 있으나 아직 단말의 성능이나 UI문제 등으로 인해 좀 복잡한 앱은 네이티브앱으로 개발되는 경우가 많습니다. 그러나 네이티브앱은 개발이 어렵고 UI와 로직을 분기하기 어려워 코드의 재활용성 부족으로 개발비용이 높다는 단점이 있습니다.
유익소프트에서는 이러한 네이티브앱의 단점을 개선하기 위해 struct나 spring과 유사한 네이티브앱 개발 프레임워크를 제공하고 있습니다.

네이티브앱 개발 프레임워크 개발 프로젝트인 Agate에서는 앱을 Presentation 영역과 Component(Container, Object)영역으로 구분하여, 비 개발자도 네이티브 개발자가 잘 만들어 놓은 Componet를 가져다 손쉽게 앱을 개발 할 수 있는 프레임워크를 제공하고 있습니다.

MOML(Mobile Object Markup Language)은 Agate의 Presentation 영역에 해당하는 부분으로 앱의 UI구성과 동작에 관한 부분을 정의하고 있습니다.
MOML을 사용하여 앱을 개발하면 복잡한 기능이 객체화 되어있어 이해하기 쉽고 안정적인 앱을 개발 할 수 있다는 점과 화면 단위로 개발이 이루어지므로 손쉽게 부분적인 수정을 하거나 재활용 할 수 있다는 이점이 있습니다.

본 문서는 MOML에 대한 기본적인 이해를 돕고자 작성한 문서로 MOML Object를 사용하는 방법 위주로 설명을 하고 있으며, 네이티브 개발자 영역인 User Component영역에 대해서는 다루고 있지 않습니다.

MOML 개발 환경 준비하기

애플리케이션을 빌드 하기 위해서는 Xcode나 eclipse와 같은 개발 환경이 있어야 합니다. 그러나 개발목적이 아닌 테스트나 문법 학습을 위해서는 간단히 MOML Application Viewer를 활용 할 수 있습니다.

MOML Application Viewer 설치

MOML을 이해하고 배우기 위해서 복잡한 네이티브 개발 툴을 설치 할 필요가 없습니다.
웹 브라우저를 이용하는 것처럼 MOML Application Viewer을 실행한 후 URL을 입력을 통하여 MOML 앱이 동작하는 것을 확인 할 수 있습니다.

MOML Application Viewer는 현재 안드로이드 버전만을 배포하고 있습니다. iOS용은 스토어에 등록되지 않아 별도로 제공해드립니다.

먼저 안드로이드 앱 마켓인 Play스토어에서 MOML Application Viewer를 다운 받도록 합니다.

실행 화면 예제사이트 접속화면

MOML Application Viewer를 처음 받아 보시면 몇 개의 테스트 링크가 있습니다. 위의 화면은 예제사이트 중 AgateApiDemo의 화면입니다.
MOML Application Viewer는 MOML 해석 엔진인 Agate 라이브러리를 사용하여 만들어진 앱 입니다. 이와 같이 MOML를 통해 개발 된 앱은 Agate 라이브러리와 함께 Packaging를 하여 독립적인 앱으로 배포 할 수 있습니다.
Agate 라이브러리를 이용하여 독립된 앱으로 배포하는 방법은 16장 MOML 앱 Package 및 배포에서 설명하도록 합니다.

XML Editor

MOML은 앱의 동작방식을 XML로 정의한 언어 입니다. 따라서, 특정 편집기가 제공되지 않지만 자신이 사용하기에 편리한 Editor을 이용하여 개발을 할 수 있습니다. 여기서는 XML 편집기로 MS의 XML Notepad 2007(무료) 나 Oxygen XML Editor(유료) 를 간단히 살펴 보겠습니다.

아래 화면은 XML Notepad 2007 의 화면입니다. 마이크로 소프트 사이트에서 무료로 받으실 수 있습니다. 다운로드

XML Notepad 2007은 XML을 다루기 위한 필수적인 기능들에 대해 직관적인 방법으로 이해하기 편하고 편집이 용이 하도록 되어있습니다.

화면의 좌측은 XML의 구조를 ELEMENT와 Attribute에 대해 트리구조로 보여 주며 우측은 Attribute의 값을 나타내도록 되어있습니다. 또한 XML Notepad의 View> Schema 를 보면 XML Schema를 등록 할 수 있도록 되어있는데, 이곳에 MOML의 Schema를 등록하면 문법적인 오류 검출과 함께 자동완성 (auto complete) 기능을 이용하여 손쉽게 개발을 할 수 있습니다.

ELEMENT에 대한 자동 완성 기능 Attribute에 대한 자동 완성 기능

Oxygen XML Editor는 XML 문서들을 프로젝트 단위로 관리하기에 유용한 XML Tools로 기본적인 XML 편집기능 이외에 관리를 위한 프로젝트 파일 생성 및 폴더관리 FTP 폴더 접속 기능 등 유용한 기능들을 제공합니다.

Oxygen XML Editor은 문서의 구조를 한눈에 파악할 수 있도록 구성되어 있으며 문서 내에서의 Auto Complete 기능과 Attribute들에 대해 보기 편하고 손쉽게 관리 할 수 있는 기능들을 제공하고 있습니다. Auto Complete 기능을 사용하기 위해서는 Options > Preferences > Document Type Association 에서 Document Type를 만들어 Catalogs에 사용할 XSD 파일을 지정해 주어야 합니다.

Web Server 설치

MOML Application Viewer는 주소창에 MOML XML이 놓여 있는 곳의 URL을 적도록 되어있습니다. 만일 MOML XML이 단말의 storage에 놓여 있다면 http: 대신에 storage: 를 입력하면 동작을 합니다.

본 문서에서는 iOS와 Android에 대해 동일한 환경을 유지하기 위하여 web server를 통하여 MOML XML을 전달 받도록 하겠습니다.

WINDOW 이용자의 경우 시작>제어판>프로그램 추가/제거 에서 왼쪽 탭의 Windows 구성요소 추가/제거를 누른후 IIS(인터넷 정보 서비스) 서버를 설치 합니다. 윈도우의 버전에 따라 설치 디스크를 넣으라는 메시지가 출력 될 수 있습니다.

무료 웹서버이자 윈도우와 macOS를 모두 지원하므로 간편하게 웹서버를 운용하기에 좋습니다.
윈도우용 다운로드, macOS용 다운로드

Getting Start MOML

Hello MOML

⚙︎ Application information 파일 생성

개발 환경이 준비 되었으면 MOML을 이용하여 Hello MOML 앱을 만들어 보도록 합니다. 먼저 XML 에디터를 이용하여 아래와 같이 applicationInfo.xml파일을 생성 합니다.

applicationInfo.xml

<MOML>
    <APPLICATIONINFO>                      
        <UPDATEINFO realTimeType="all"/>
        <START url="helloMoml.xml" />
    </APPLICATIONINFO>  
</MOML>


MOML 앱은 구동 시 애플리케이션에 대한 환경설정파일을 필요로 하는데, applicationInfo.xml 파일은 이러한 애플리케이션에 대한 환경 설정정보를 담고 있는 파일입니다.

applicationInfo.xml 파일에 나와있는 START Tag는 애플리케이션 구동 시 처음 로드 될 화면을 의미합니다. 따라서 위의 예제는 helloMoml.xml이 앱의 시작입니다.

UPDATEINFO의 realTimeType="all"은 요청 시마다 페이지를 새로 로드 한다는 것을 의미합니다. MOML은 페이지에 대한 캐시 개념으로 UPDATEINFO를 사용하며, 캐쉬를 사용하지 않는 경우 realTimeType="all" 을 명시합니다.

코드를 테스트하거나 개발 중인 경우 realTimeType="all"로 설정하는 것이 좋습니다. 개발이 완료되어 배포하는 경우 qMark 나 none와 같이 캐쉬 기능을 활용하는 옵션으로 바꾸도록 합니다.

⚙︎ UI 파일 생성

환경설정 파일작성이 완료되었으면 앞서 환경 설정페이지 applicationInfo.xml에서 처음 시작 페이지로 지정한 helloMoml.xml파일을 생성하도록 합니다.

helloMoml.xml

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT  portrait="320,460"> 
        <LABEL layout="0,200,320,30" text="Hello MOML!" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="#ffffff"/>            
    </UILAYOUT>
</MOML>


실제 화면을 보기 위하여 작성된 두 개의 파일을 http://myhost/helloMoml 이 가리키는 폴더에 옮기도록 합니다.
폴더에 옮긴 후 MOML Application Viewer에서 http://myhost/helloMoml/applicationInfo.xml을 입력합니다.

위와 같은 화면이 나왔다면 MOML을 배우기 위한 준비작업이 완료 된 것입니다. 이번 장은 개발환경 준비를 위한 장으로 코드에 대한 설명은 사용자 인터페이스에서 다루도록 합니다.

XML 기본 문법

MOML은 XML의 규칙에 따라 작성이 되어야 합니다.
초기 에러발생이나 오동작을 하는 대부분의 경우 잘못된 형식의 XML을 사용하는 경우가 많습니다.
예제 작성 및 이에 설명을 하기 이전에 XML의 기본적인 내용을 살펴보도록 하겠습니다.

⚙︎ XML 선언

<?xml version="version num" encoding="encoding type" standalong="yes|no"?>


여기서 주의해야 할 점은 XML선언 이전에는 어떤 내용이든 들어가면 안됩니다.
주석은 물론이고 엔터 혹은 공백이 들어가서도 안됩니다.

<!-- MOML input sample -->
<?xml version="1.0" encoding="utf-8"?>
<MOML></MOML>


예로 위와 같은 코드를 익스플로어와 같은 웹브라우저에서 열게 되면 XML문서 오류가 발생을 합니다. 이는 <?xml 앞에 주석부분이 들어갔기 때문입니다. 추가로 <?xml에 사이에서는 공백이 들어가면 안됩니다.

<? xml은 문법 오류를 발생합니다.

⚙︎ 유니코드(UTF-8)

MOML작성 시 기본 인코딩 방식은 UTF-8입니다.
UTF-8은 파일 사이즈를 작게 하기 위해, ASCII 문자 코드는 1바이트로 인코딩하고, 다른 문자들은 2바이트나 그 이상으로 인코딩하는 방식을 택하고 있습니다.

한글은 3바이트로 인코딩 합니다.

ASCII문자로 이루어진 파일은 ASCII 인코딩 체계 또는 UTF-8로 저장 되었을 경우 동일하게 8비트 인코딩 체계를 사용하므로 서로 호환성이 있습니다.

UTF-8 방식은 기존의 ASCII문자 코드 체계와 그대로 호환이 가능하기 때문에 인터넷상에서 기본적인 인코딩방식으로 XML 문서에서 별도의 인코딩을 언급하지 않으면 디폴트로 UTF-8을 사용하게 됩니다.

⚙︎ XML Tag의 작성규칙

다음은 엘리먼트 작성시 주의해야 할 점 입니다.

  1. 이름은 문자로 시작 할 수 있으며, 첫 번째 문자로 특수 문자 중에서 ‘_’로 시작 할 수 있습니다. 하지만 숫자나 ‘.’으로 시작할 수는 없습니다.
  2. 두 번째 문자부터 숫자 및 특수 문자 ‘_’, ‘-‘ , ‘.’ 도 가능합니다.
  3. 태그 이름에 공백을 포함 시킬 수는 없습니다.
  4. 특수 문자 중에 ‘:’문자는 태그 이름에 포함할 수 있지만 네임스페이스에 관련된 기호이므로 되도록 사용하지 않는 것이 바람직합니다.
  5. 태그 이름은 대소문자를 구별 하므로 철자가 같다고 해서 같은 태그가 아닙니다.
  6. 시작 태그의 시작인 ’<’다음에 공백 문자가 올 수 없습니다. 마찬가지로 종료태그의 ‘</’다음에 공백 문자가 올 수 없으며 반드시 시작 태그 이름과 같은 이름이 와야 합니다.
  7. 태그 이름은 xml로 시작 할 수 없습니다.

⚙︎ 엘리먼트의 내용

엘리먼트의 구성 요소에서 시 작 태그와 끝 태그 사이에 오는 내용(Content)으로 다름과 같은 것들이 올 수 있습니다.

Character Entity Reference Numeric Reference Hexadecimal Reference
& &amp; &#38; &#x26;
< &lt; &#60; &#x3C;
> &gt; &#62; &#x3E;
&quot; &#34; &#x22;

사용자 인터페이스

모바일 UI는 작은 화면에 최대한 많은 정보를 표시하기 위해 UI 컨트롤 중첩과 화면 전환 방법을 많이 사용합니다.

HTML을 사용하는 웹앱의 경우 HTML이 문서의 양식을 정의하는 구조에서 발전한 만큼 native UI와 같은 look and feel를 구현하기 위해 많은 양의 자바스크립트 코드를 사용하므로 종종 속도의 저하 문제가 발생합니다.

MOML은 Native 앱 UI에 맞춰 정의된 언어로서 몇 가지 기본적인 개념만 이해하면 간단히 native look and feel을 갖는 앱을 구현 할 수 있습니다.

MOML 기본 구조

MOML에서 HTML의 에 해당하는 부분이 부분입니다.

MOML은 UI 컨트롤들을 배치 하기 위해 <UI><UILAYOUT>에 화면의 비율에 대한 정의를 하도록 되어 있습니다.

아래는 일반적인 UI MOML FILE의 문법의 구조입니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <THEMES> ... </THEMES>
    <FUNCTION> ... </FUNCTION>
    <CMD> ... </CMD>

    <UILAYOUT portrait="320,460">
        <!--이 사이에 화면에 보기기 위한 컨트롤 들을 배치합니다.-->          
    </UILAYOUT>

    <UILAYOUT landscape="460, 320"> ... </UILAYOUT>  
</MOML>


구조적으로 MOML은 HTML의 CSS와 유사한 기능을 하는 <THMES>, 로직 처리를 위한 <FUNCTIONLIST>, UI화면을 구성하는 영역인 <UI>, 페이지 생성시 자동으로 호출되는 <CMD> 등으로 구성됩니다.

MOML에서 좌표 등에 사용되는 단위는 moml unit이라는 비율단위계를 사용합니다. 비율단위계는 화면의 크기를 의미하는 것이 아닌 화면의 비율을 나타내는 것입니다.
이는 정해진 비율의 고무판에 Button과 같은 UI 요소들을 배치한 후 실제 적용 할 단말기에 맞춰 가로와 세로를 늘리는 것과 같습니다.

예를 들어 <UILAYOUT portrait="300,300">으로 지정하고 300*600의 디스플레이에 올리는 경우 UI Elements들의 width는 그대로 유지가 되나 height는 2배로 늘어나게 됩니다. 개발 시는 일반적으로 주 대상 단말의 해상도로 설정을 합니다.

만일 다양한 해상도의 단말에 대해 지정한 비율로 모든 화면 비율이 유지가 되어야 한다면, APPLICATIONINFO의 <AUTOFIT>을 설정하도록 합니다.

<MOML>
    <APPLICATIONINFO>                      
        <UPDATEINFO realTimeType="all"/>
        <START url="helloMoml.xml" />
        <AUTOFIT toleranceRatio="15"/>
    </APPLICATIONINFO>  
</MOML>


toleranceRatio는 가로 세로의 비율이 지정 비율보다 15%이상 틀어진 경우 비율 유지를 하며, 15% 이내인 경우 화면 사이즈에 맞추도록 설정하는 것 입니다. 만일 정확한 비율을 유지해야 한다면 toleranceRatio=“0"을 주도록 합니다.

컨트롤 배치하기

MOML을 사용하여 화면을 구성하고 UI 컨트롤을 배치하기 위해서는 아래와 같이 몇 가지 기본적인 개념을 이해 할 필요가 있습니다.

⚙︎ MOML은 별도의 Layout 컨테이너가 존재하지 않는다.

MOML에서는 제공되는 UI 컨트롤 자체가 Layout 컨테이너 역할을 수행합니다. 아래는 타이틀 바에 back 버튼을 배치하는 예제입니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT  portrait="320,460">
        <LABEL layout="0,0,320,100" align="relative" defaultImg="#5f5f5f">
            <BUTTON layout="10,0,100,60" text="BACK" />
        </LABEL>

        <WINDOW layout="0,200,320,100" align="linear:left"  defaultImg="#5f5f5f">
            <BUTTON layout="100,60" text="BACK"/>
        </WINDOW>
    </UILAYOUT>
</MOML>


코드를 보면 BUTTON을 배치하는데 있어 LABEL 또는 WINDOW의 align속성을 이용하여 배치하고 있습니다.

두 코드는 동일한 형태의 화면을 나타냅니다. 예제 코드를 보면 라벨 안에 버튼을 배치하고 정렬을 하고 있는데 이렇게 상위 UI ELEMENT가 하위 UI ELEMENT의 레이아웃을 지정하는 방식은 윈도우 애플리케이션 개발 시 UI 컨트롤 안에 다른 UI 컨트롤을 배치하는 방식과 같습니다. 이러한 방식을 통하여 다양한 구성을 갖는 앱을 작성 할 수 있습니다.

참고로 UILAYOUT에서 화면 전체의 LAYOUT을 설정합니다. UILAYOUT는 단말의 회전을 고려하여 가로방향과, 세로방향의 UI가 다른 경우 중복하여 선언 할 수 있습니다. 위의 코드에서는 세로방향의 UI인 경우만 선언하였습니다. 만일 가로 방향에서도 동일한 화면비율을 유지하려면 landscape="460,320"를 추가하도록 합니다.

⚙︎ 모든 UI 컨트롤은 WINDOW 객체를 상속 받는다.

MOML은 UI를 구성하는 컨트롤들이 가져야 하는 기본적인 속성들에 대해 WINDOW에 정의하고 있습니다. 또한 LABEL, BUTTON과 같이 UI를 이루는 모든 UI 컨트롤은 이를 상속받아 구현이 되어 있으며, 각각의 컨트롤은 WIDNDOW기본 속성 이외에 컨트롤에 해당하는 옵션이 추가 되어 있습니다.

일반적으로 WINDOW는 특별한 기능 없이 컨트롤을 배치하는 경우에 많이 사용 됩니다.

<WINDOW layout="0,0,320,130" align="relative" defaultImg="#5f5f5f">
    <BUTTON layout="10,0,100,40" text="FIRST" />
    <BUTTON layout="10,45,100,40" text="SECOND" />
    <BUTTON layout="10,90,100,40" text="THIRD" />
</WINDOW>
<WINDOW layout="0,200,320,50" align="linear:horizontal|hFill" defaultImg="#5f5f5f">
    <BUTTON layout="100,40" text="FIRST" />
    <BUTTON layout="100,40" text="SECOND" />
    <BUTTON layout="100,40" text="THIRD" />
</WINDOW>


WINDOW를 상속받는 모든 UI 컨트롤은 align 속성을 가지고 있습니다. MOML에서 지원하는 align속성은 relative, linear, flow 이며, 각각은 해당옵션을 가지고 있습니다.

⚙︎ Child Element 좌표는 Parent Element에 대한 상대좌표를 사용한다.

MOML은 컨트롤들을 배치하는데 있어 모든 객체의 좌표는 부모의 위치에 대한 상대좌표로 표현됩니다.

<WINDOW layout="0,0,320,100" align="relative" defaultImg="#5f5f5f">
    <LABEL layout="10,10,100,60" align="relative" text="Child1" defaultImg="#5f005f"/>
        <BUTTON layout="10,30,50,20" text="Child2" />
    <LABEL/>
</WINDOW>


위 예제에서 버튼의 위치는 화면에 대한 절대 좌표가 아닌 부모의 좌표를 기준으로 설정됩니다. 예제에서 BUTTON의 절대좌표상의 위치는 20, 40 이 됩니다.

좌표의 크기 관련하여 moml unit을 사용하는 것이 일반적이나 px, cm, mm, in, pt와 같은 단위와 다른 id의 위치를 참조하는 식이나 일반적인 계산식도 사용이 가능합니다. 만일 BUTTON의 가로 크기를 모든 단말에서 항상 2Cm의 크기를 유지하려고 하면 <BUTTON layout="10,30,2cm,20" text="Child2" /> 형태로 작성 할 수 있습니다.

타이틀 바 배치하고 꾸미기

앞서 설명한 UI 컨트롤의 기본적인 개념을 이해 하였다면 이제 앞서 나온 helloMoml.xml을 수정하여 타이틀 bar 형태로 상위 배치를 한 후 왼쪽에 버튼을 배치해 보도록 하겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT  portrait="320,460"> 
        <LABEL layout="0,0,320,40" align="relative" text="Hello MOML!" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="#335533">
            <BUTTON layout="10,5,60,30" text="BACK" textAlign="center" fontColor="#ffffff" fontSize="15"/>
        </LABEL>            
    </UILAYOUT>
</MOML>


구조는 LABEL이 Child 객체로 BUTTON을 가지고 있으며, LABEL은 하위 객체인 BUTTON에 대해 relative 정렬을 하도록 되어있습니다. relative 속성은 부모의 좌표에 대한 상대좌표입니다. 즉 부모의 위치가 어디에 있건 부모 객체의 좌표의 좌측 상단 부분을 기준으로 Child 객체는 0, 0의 좌표를 갖습니다.

동작 확인을 위하여 상위 코드에서 라벨의 top값만 수정을 해보도록 합니다.

<LABEL layout="0,200,320,40" align="relative" ..


위와 같이 전체 화면상에서 버튼의 Parent인 라벨의 위치와 상관없이 Child 버튼은 Parent의 좌표에 대한 상대 좌표을 갖습니다.

align은 아래와 같이 layout type, direction option, row/column align option, sub align option 의 4 단계로 값을 설정 할 수 있습니다.

layout type 설명
relative left, top을 원점(0,0)으로 하여 절대좌표 형식으로 자식 UI element의 위치를 지정.
[direction option], [row/column align option], [sub align option]은 사용하지 않음.
linear 자식 UI element 들을 1행 이나 1열으로 정렬.
자식 UI element의 layout 속성은 2개의 "," 로 분리된 값들로 구성.
(layout="width,height") 기본 option은 "horizontal
flow 자식 UI element들을 다중 행 또는 다중 열로 정렬.
자식 UI element의 layout 속성은 2개의"," 로 분리된 값들로 구성
(layout="width,height") 기본 option은 "horizontal
option 설명
horizontal 가로로 왼쪽에서 오른쪽으로 차례대로 자식 UI element들을 배치.
vertical 세로로 위에서 아래로 차례대로 자식 UI element들을 배치.
wideside 넓이와 높이 중 큰 값 방향으로 자식 UI element들을 배치
narrowside 넓이와 높이 중 작은 값 방향으로 자식 UI element들을 배치
option 설명
left /top/
right / bottom
자식 UI element들이 배치된 행이나 열을 좌/상/우/하 한쪽으로 붙여서 나열
vCenter / hCenter
/ center
자식 UI element들이 배치된 행이나 열을 가운데로 정렬
center option은 vCenter
vFill / hFill / fill 여백을 채우도록 자식 UI element들의 크기를 키움.
"fill" option은 "vFill
vJustify / hJustify
/ justify
배치된 행이나 열의 처음과 마지막 UI element를 양 끝 경계에 맞춰 정렬
만약 한개의 element 만 있는 경우, "left
sub align option 설명
subLeft / subRight 세로 방향의 direction option을 사용한 경우 배치된 열 내에서 가로 방향의 정렬을 설정
subTop / subBottom 가로 방향의 direction option을 사용한 경우 배치된 행 내에서 세로 방향의 정렬을 설정
subCenter 배치된 행이나 열내에서 중앙에 배치.
<WINDOW align="linear" />
<WINDOW align="flow:wideside⎮hJustify⎮center" />
<WINDOW align="linear:center" />
<WINDOW align="linear:center⎮subCenter" />
<WINDOW align="linear:hCenter⎮bottom⎮subBottom" />

타이틀 바에 이미지 입히기

앞서 UI ELEMENT를 배치하고 정렬하는 방법을 살펴보았습니다.

이번에는 정렬된 UI를 꾸미기 위하여 UI ELEMENT의 기본속성인 defaultImg를 이용하여 앞서 작성하였던 타이틀 바 배치 예제에 이미지를 입히도록 하겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT  portrait="320,460">
        <LABEL layout="0,0,320,40" align="relative" text="Hello MOML!" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="img/top_bg.jpg">
            <BUTTON layout="10,5,60,30" text="BACK" textAlign="center"  fontSize="15" defaultImg="img/re.jpg"/>
        </LABEL>           
    </UILAYOUT>
</MOML>


위 코드는 WINDOW의 기본 속성인 defaultImg에 해당하는 이미지의 경로를 지정한 예제입니다.

defaultImg속성에 들어가는 값은 이미지 경로만 들어 갈 수 있는 것은 아닙니다. #과 함께 색상 코드를 넣을 수 있습니다. 즉 이미지 속성에는: "[image file URL]" | "#[RRGGBB]" | "#[AARRGGBB]" 값을 가질 수 있습니다.

기타 이미지관련 옵션으로는 loadingEffect와 loadingImg가 있습니다. 만일 로딩 되는 이미지가 서서히 나오는 효과를 주려면 loadingEffect ="fadeIn" 속성을 줄 수 있고, 통신으로 받아야 하는 경우 이미지가 로딩되는 동안 효과가 필요하면 loadingEffect="progressBar" 속성을 쓸 수 있습니다.
기타 loadingImg 속성은 defaultImg 가 로딩 되기 전에 나오는 이미지를 의미합니다.

글자 포멧팅 하기

일반적인 화면의 대부분은 이미지와 글자로 구성됩니다.
주로 글자를 표시 할 때 사용되는 LABEL과 BUTTON은 글자를 Formatting하기 위한 다양한 옵션을 제공합니다.

⚙︎ AUTO LAYOUT 설정하기

모바일앱을 개발하는 경우 가장 번거로운 작업 중에 하나가 글자의 길이에 따라 버튼 또는 라벨의 크기를 잡고 그에 따른 이미지 작업을 하는 것입니다. MOML은 객체의 크기에 auto옵션을 줄 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT  portrait="320,460">
        <LABEL layout="0,0,320,40" align="relative" text="Hello MOML!" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="img/top_bg.jpg">
            <BUTTON layout="10,5,auto,30" text="BACK" textAlign="center" fontSize="25" defaultImg="img/re.jpg"/>
        </LABEL>           
    </UILAYOUT>
</MOML>


위 코드는 글자의 길이에 따라 자동으로 객체의 크기를 결정하도록 설정하는 코드입니다.
layout의 width 속성을 auto로 주게 되면 글자의 폭에 따라 BUTTON의 사이즈가 변경됩니다. Text의 값을 “BACK"과 “BUTTON"으로 주었을 때 화면은 아래와 같습니다.

만일 객체의 사이즈가 auto 속성이 아니라면, width안에 글자가 모두 표현되지 않을 때에는 폰트사이즈가 minFontSize까지 자동으로 줄어들며 출력되는 것이 기본 설정입니다. 따라서, width가 auto가 아닐 때 fontSize를 고정하고자 하는 경우에는 minFontSize에 ="-1"을 설정하거나 fontSize와 동일하게 설정하도록 합니다.

정해진 width내에 글자가 모두 출력할 필요가 없이 생략부호로 출력하고 싶을 경우에는 ellipsis 속성을 사용하여 앞, 중간, 뒤쪽에 생략부호(…)를 출력하도록 설정합니다.

⚙︎ ELLIPSIS 속성 사용 하기

<LABEL defaultImg="#bbbbbb" fontSize="20" text="This is sample text"  layout="120,auto" minFontSize="-1" ellipsis="none"/>

<LABEL defaultImg="#bbbbbb" fontSize="20" text="This is sample text"  layout="120,auto" minFontSize="-1" ellipsis="end"/>

<LABEL defaultImg="#bbbbbb" fontSize="20" text="This is sample text"  layout="120,auto" minFontSize="-1" ellipsis="middle"/>

<LABEL defaultImg="#bbbbbb" fontSize="20" text="This is sample text"  layout="120,auto" minFontSize="-1" ellipsis="start"/>


위 예제 코드는 MOML Application Viewer의 예제 URL에 있는 Agate API Demo에서 발췌한 코드입니다.
위 코드는 가로의 길이를 고정하고 ellipsis의 속성을 변경한 코드로 이에 따른 화면은 아래와 같습니다. 이는 다양한 크기의 화면과 애플리케이션의 globalization시에 자주 발생하는 문자 문제를 해결하기 위하여 유용한 기능입니다.

MOML에서 기본적인 화면 구성하기 위하여 객체를 배치하고 꾸미는 과정을 살펴보았습니다.

실제 앱 개발 시에는 EDIT, SPINNER, LIST등과 같은 많은 UI Control를 사용하게 됩니다. 각각의 사용방법 및 속성은 MOML API Reference guide에 자세히 소개되어 있습니다.

화면전환하기(페이지이동)

NAVIGATIONCONTAINER를 이용하여 화면간의 관계를 설정하는 방법을 살펴보겠습니다.
화면간의 관계는 버튼 클릭 시 상세화면으로 이동하거나 Back 버튼 클릭 시 이전화면으로 이동하는 흐름을 정의하는 것을 의미합니다.

페이지 전환하기

버튼클릭과 같은 이벤트가 발생하였을 때 다른 화면으로 전환해야 하는 경우 MOML은 HTML과 같이 링크형태로 화면을 전환하는 방법과 <NAVIGATIONCONTAINER> 라는 특수 컨테이너를 사용하여 화면간의 관계를 정의하는 방법을 제공합니다.
또한 NAVIGATIONCONTAINE는 화면전환시 특수한 효과가 실행되는 기능을 제공합니다.

먼저 NAVIGATIONCONTAINER에 대하여 살펴보도록 하겠습니다.

MOML에서 CONTAINER는 여러 UI Elements또는 다른 컨테이너를 배치 할 수 있는 틀로 생각 할 수 있습니다. NAVIGATIONCONTAINER는 CONTAINER와는 다르게 여러 화면들 간의 흐름을 관리하는 특수한 목적을 가진 CONTAINER입니다.

아래는 NAVIGATIONCONTAINER를 사용하는 MOML 소스입니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UI>
        <UILAYOUT  portrait="640,960"> 
<!--         UI Elements, UI Container       -->
            <NAVIGATIONCONTAINER id="navi" layout="0,150,640,810" selectedItem="page1" >
                <VIEWITEM id="page1" src="page1.xml" />
            <VIEWITEM id="page2" src="page2.xml" />            
<!--             관리페이지 추가       -->
            </NAVIGATIONCONTAINER>             
<!--         UI Elements, UI Container       -->
        </UILAYOUT>
    </UI>
</MOML>


위 코드에서 VIEWITEM은 화면들을 의미하며, 이 VIEWITEM을 NAVIGATIONCONTAINER에 배치 하고 있습니다. 이를 화면상에 개념적으로 표현하면 아래와 같습니다.

위의 그림을 보면 NAVIGATIONCONTAINER가 배치된 영역에서만 화면의 전환이 발생하며, 이외의 영역인 UI Elementss는 변경이 없이 현상태를 유지합니다. NAVIGATIONCONTAINER에서 변경할 화면을 선택하는 방법은 selectedItem="page id" 형태로 지정합니다.

먼저, page1, page1_1, page2 화면을 작성해 보겠습니다.

page1.xml
<MOML>
    <UILAYOUT  portrait="640,810"> 
        <LABEL layout="0,0,640,810"  text="PAGE 1" textAlign="center"  fontSize="50" fontColor="#88AA88" defaultImg="#777799"/>
    </UILAYOUT>
</MOML>


page2.xml
<MOML>
    <UILAYOUT  portrait="640,810"> 
        <LABEL layout="0,0,640,810"  text="PAGE 2" textAlign="center"  fontSize="50" fontColor="#88AA88" defaultImg="#997777"/>
    </UILAYOUT>
</MOML>


이제 준비된 화면을 제어 하기 위해 NAVIGATIONCONTAINER를 사용하는 페이지를 만들어 보도록 합니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT  portrait="320,460" >
        <LABEL layout="0,0,320,40" align="relative" text="Navigation Container" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="img/top_bg.jpg">
            <BUTTON layout="10,5,auto,30" text="BACK" textAlign="center" fontSize="25" defaultImg="img/re.jpg"/>
        </LABEL>   

        <WINDOW layout="0,40,320,40" align="linear:wideside|center" defaultImg="#ffffff">
            <BUTTON layout="130,30" text="page1" fontColor="#00ff00" defaultImg="/img/rbutton.jpg" />
            <BUTTON layout="130,30" text="page2" fontColor="#00ff00" defaultImg="/img/rbutton.jpg" />
        </WINDOW>

        <NAVIGATIONCONTAINER id="mynavi" layout="0,80,320,380" selectedItem="page1" >
            <VIEWITEM id="page1" src="page1.xml"  transitionInEffect="fade" />
            <VIEWITEM id="page2" src="page2.xml"  transitionInEffect="fade" />                              
         </NAVIGATIONCONTAINER>             
    </UILAYOUT>
</MOML>


코드를 보면 타이틀 바 밑에 2개의 버튼을 배치하고 , 그 밑에 <NAVIGATIONCONTAINER> 영역을 지정하였습니다.
또한 Navigation Container영역에 page1.xml, page2.xml 페이지를 VIEWITEM Tag를 통하여 지정하였습니다.

아직 버튼을 눌러도 화면 전환이 발생하지 않습니다.

화면을 보면 앞서 만든 여러 개의 화면 중에 PAGE1화면이 출력 되어 있는데 이는 NAVIGATIONCONTAINER의 속성 중 selectedItem="page1" 로 설정이 되어 있기 때문입니다.

이제 page1 , page2의 화면 전환을 위한 코드를 추가 해 보도록 합니다.

⚙︎ 화면 전환하기

화면 전환을 하는 방법은 단순히 NAVIGATIONCONTAINER의 selectedItem 속성값을 이동할 페이지의 ID값으로 변경하면 됩니다. 기존 코드의 버튼에 onClick 이벤트 속성을 지정합니다.

<BUTTON layout="130,30" text="page1" defaultImg="/img/rbutton.jpg" onClick="mynavi.selectedItem='page1'"/>

<BUTTON layout="130,30" text="page2" defaultImg="/img/rbutton.jpg" onClick="mynavi.selectedItem='page2'"/>


각각의 버튼 onClick 부분을 보면 해당 페이지로 이동을 하도록 selectedItem값을 변경하도록 되어있습니다. 이제 실행을 하여 버튼을 클릭하면 NAVIGATIONCONTAINER 영역인 layout="0,80,320,380" 에서만 화면 전환이 이루어집니다.

⚙︎

화면 트리 구성하기
화면 트리는 다양한 방법으로 구성할 수 있어 모두 설명하기는 어렵지만, MOML코드에서 자주 보이는 패턴이므로 간단히 살펴 보겠습니다. <NAVIGATIONCONTAINER>의 동작방식은 VIEWITEM의 id로 관리됩니다. 아래 예제를 보면

<NAVIGATIONCONTAINER id="mynavi" layout="0,150,640,810" selectedItem="page1" >
    <VIEWITEM id="page1" src="page1.xml" transitionInEffect="fade" >
        <VIEWITEM id="page1_1" src="page1_1.xml" transitionInEffect="fade" />
    </VIEWITEM>   
    <VIEWITEM id="page2" src="page2.xml" transitionInEffect="fade" >      
        <VIEWITEM id="page2_1" src="page1_1.xml" transitionInEffect="fade" />
    </VIEWITEM>   
</NAVIGATIONCONTAINER>


id= page1_1, Id= page2_1은 모두 소스로 page1_1.xml을 지정하고 있습니다.

이 코드에서 page1_1.xml은 논리적으로 page1.xml 과 page2.xml의 하위 계층에 속해 있습니다. Navigation Container에 화면간의 논리적인 계층을 만들어 두게 되면 MOML 엔진에서 자동으로 화면간의 관계를 관리하여 주는 이점이 있습니다.

즉, page1_1 화면에서 상위 페이지를 가기 위하여 onClick="mynavi.selectedItem=’page1’" 이라고 명시 할 필요 없이 onClick="mynavi.back"으로 현재 페이지의 상위로 이동을 하게 됩니다.

위의 코드는 2개의 간단한 화면만을 만들어 보았으나 실제 코드 작성시에는 많은 화면간의 관계 설정을 하는 경우 발생합니다. 이러한 관리를 위하여 VIEWITEM을 담아 두기 위한 VIEWITEMGROUP을 사용하거나 또는 메인 NAVIGATIONCONTAINER에서 해당 메뉴 별로 VIEWITEM을 관리하는 하위 NAVIGATIONCONTAINER를 호출하는 방식을 사용하기도 합니다.

페이지 전환 효과

웹앱과 네이티브 앱의 커다란 차이점 중 하나가 부분적인 페이지 전환과 전환 시 다양한 화면 효과를 줄 수 있는 부분이라고 할 수 있습니다.

화면 전환 효과는 VIEWITEM의 속성 중 transitionInEffect와 transitionOutEffect 속성을 통하여 해당 페이지가 출력되거나 사라질 때 특정 효과를 지정할 수 있습니다.

화면이 나타날 때의 효과는 transitionInEffect속성을 사용하며, 화면이 사라질 때는 transitionOutEffect 속성을 사용합니다. 지원되는 효과는 move, slide, zoom과 같은 기본적인 효과와 blind, flip, innercube, mosaic, tornado, twirl 과 같은 OpenGL 효과 등이 있습니다. 각각의 효과는 이동 해야 할 페이지의 성격에 맞추어 적용하는 것이 바람 직 합니다. 각각에 대한 화면 전환 데모는 MOML APPLICATION VIEW의 예제 링크 중 AgateApiDemo의 예제 중 Navigation Transition Effects에 자세히 나와 있습니다.

팝업은 현재 화면은 유지된 상태로 임시적으로 입력 또는 정보를 표시하기 위하여 나타나는 화면으로 주로 애플리케이션의 다음 동작을 위하여 사용자에게 확인을 받거나 입력 값을 얻어야 하는 경우에 사용됩니다.

POPUP Tag는 Custom UI을 갖는 팝업을 만들기 위해 사용됩니다. 커스텀 팝업을 살펴보기 전에 OS에서 제공하는 시스템 팝업을 사용하는 방법을 알아 보도록 하겠습니다.

⚙︎ 시스템 팝업으로 에러 메시지 띄우기

시스템 팝업은 OS에서 제공하는 팝업으로 device객체를 이용하여 호출합니다.

<BUTTON layout="50,80" onClick="device.systemPopup('error', 'password invailed', 'OK', '', '')"/>

OS에서 제공하는 팝업은 device.systemPopup('TITLE','MSG','TEXT1','TEXT2','TEXT3') 형태로 사용합니다. 만일 확인 버튼 이외에 취소버튼이 나와야 한다면 TEXT2 부분에 ‘취소’를 입력합니다.

<BUTTON layout="50,80" onClick="device.systemPopup('Alert', 'Do you want to quit', 'OK', 'CENCEL', '')"/>


OK 또는 CANCEL 이 선택된 것에 따라 처리를 해야 하는 루틴은 아래와 같이 정의합니다.

<BUTTON layout="50,80" onClick="device.systemPopup('Alert', 'Do you want to quit', 'OK:function.shoppingBasketSave ', 'CANCEL', '')"/>


위의 코드에서 OK 버튼 클릭 시 shoppingBasketSave 함수를 실행하도록 정의 되어 있습니다.

안드로이드에서는 사용자에게 보여진 후 사라지는 toastPopup이라는 것이 있습니다. 이는 사용자에게 확인과 같은 입력을 받는 것이 아닌 내부적으로 어떤 일이 있었는지 알려주기 위해 사용하는 것입니다.

<BUTTON layout="50,80" onClick="device.toastPopup('This is toastPopup')"/>


위와 같이 toastPopup은 사용자의 입력 값이 필요 없이 잠깐 상태를 알려주기 위하여 사용되는 것으로 메시지만 입력 하도록 되어있습니다.

⚙︎ CUSTOM 팝업 만들기

시스템에서 제공하는 팝업의 UI는 매우 제한적이므로 제작하는 애플리케이션의 디자인과 어울리지 않는 경우가 많습니다.
시스템에서 제공하는 팝업 UI를 변경 할 필요가 있거나, 기능적으로 시스템팝업이 제공하기 어려운 UI의 팝업을 생성 할 필요가 있을 때 Custom Popup을 사용합니다.
Custom Popup을 사용하는 예로 로그인 팝업 창을 만들어 보겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT portrait="320,460">
        <POPUP layout="35,60,250,300" showEffect="slide:100,down"  defaultImg="#aabbcc" onClick="container.close">
            <WINDOW layout="10,50,230,155" defaultImg="#ffffff">
                <EDIT id="userID" layout="30,15,170,35"  fontSize="15"/>
                <EDIT id="userPW" layout="30,60,170,35" fontSize="15" textFormat="password"/>
                <LABEL layout="30,100,100,30" text="자동로그인 설정" fontSize="15" textAlign="vCenter"/>
                <CHECKBOX layout="125, 100, 80, 30"  style="iOS"/>
            </WINDOW>

            <BUTTON layout="25,235,200,45" text="로그인" onClick="function.login" />          
        </POPUP>
    </UILAYOUT>
</MOML>


POPUP은 UI Elements 컨테이너의 한 종류로서 UILAYOUT아래 화면을 구성하듯이 작성하면 됩니다.

일반적인 컨테이너와 다른 점은 팝업 창이 화면에 나타나거나 사라질 때 효과를 줄 수 있는 showEffect, hideEffect 속성이 있다는 점입니다. 위의 예제코드를 실행 시키면 팝업이 나타날 때 위에서 아래로 슬라이드로 내려오는데 생성부터 지정 위치에 나타나기까지 100 millisecond 의 속도로 내려오게 설정된 경우입니다.

아래는 작성된 팝업 UI XML을 호출하는 코드입니다.

<BUTTON layout="50,80" onClick="container.open('loginPopup.xml', 'root.new')"/>


위의 코드는 BUTTON 클릭 시 앞서 만든 로그인 팝업 창을 띄우도록 되어 있습니다.

container.open은 HTML의 링크 클릭 시 새로운 창을 불러 오는 것과 동일하게 동작합니다. 여기서 동작은 버튼 클릭 시 앞서 작성한 로그인 팝업 창(loginPopup.xml)을 root 화면에 새로운 창으로 띄웁니다. 만일 기존에 존재하는 컨테이너에 띄우는 경우 root.new 자리에 컨테이너의 id를 적어 주도록 합니다.

출력된 팝업을 닫기 위해서는 <POPUP onClick="container.close">와 같이 container.close를 호출합니다.
POPUP이 사라질 때에는 hideEffect에 지정된 효과를 보이며 사라집니다.

이벤트 처리

이벤트는 GUI프로그래밍에 있어 일반적인 개념입니다.

이벤트의 발생은 사용자에 의해서 또는 내부장치에서 발생 합니다. 즉 사용자가 텍스트박스를 클릭하면 키보드가 나온다거나, GPS가 동작을 하면서 주기적으로 위치를 측위하여 알려주는 것도 이벤트가 발생하였다고 말합니다.

이벤트는 Button의 onClick과 같이 Object별로 발생하는 이벤트의 종류들이 미리 정해져 있습니다. 예를 들어 Button의 경우 onClick 이외에 onShow, onCreate, onHide, onLongClick, onFlicking등이 미리 정해져 있습니다.

이벤트가 발생하였을 경우 처리되어야 하는 작업을 등록 시키는 방법은 크게 Object에 event를 거는 방법과 UI에 event를 거는 방법이 있습니다.

object에 event연결하기

아래의 예제는 서버에 데이터를 전송하고 전송이 완료되면 그 결과 값을 화면에 보여주는 소스 중 일부입니다. http객체는 UI를 갖지 않는 object로 http object의 addEventListener 함수를 통하여 직접적으로 event와 event발생시 호출되는 함수를 등록하는 방법입니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <FUNCTION id="onFileUploadComplete">
        <CMD cmd="device.toastPopup('file upload completed')"/>
    </FUNCTION>

    <UILAYOUT portrait="300,300" landscape="300,300">
       <BUTTON layout="20,20,100,30" text="fileUpload" onClick="function.fileUpload"/>
    </UILAYOUT>

    <CMD cmd="http.addEventListener('onComplete', 'onFileUploadComplete')"/>
</MOML>


코드에서 <FUNCTION><UILAYOUT> 외부에 있는 CMD는 UI생성 후 자동으로 호출됩니다. 이 곳에서 http의 onComplete이벤트와 이벤트 발생시 실행될 함수onFileUploadComplete를 등록했습니다.

이제 전송버튼에서 서버쪽으로 데이터 전송하여 전송이 완료되면 http에서 onComplete 이벤트가 발생을 하며 onFileUploadComplete 함수가 실행됩니다.

UI에 이벤트 연결하기

UI에 이벤트를 거는 방법은 arrtibute에 파라미터 형태로 이벤트를 거는 방법과 addEventListener를 통해 이벤트를 함수를 연결하는 방법이 있습니다.

⚙︎ attribute 를 통한 이벤트 함수 연결

<?xml version="1.0" encoding="utf-8"?>
<MOML>
    <FUNCTION id="onSavePicture">
        <CMD cmd="{device.systemPopup('Alert', parameter.param[0], '확인', '', '')}"/> 
    </FUNCTION>

    <UILAYOUT portrait="300,300" landscape="300,300">
        <WINDOW layout="0,0,300,300">
          <CAMERA id="cam" layout="0,0,300,270" savePath="storage:camera" onSavePicture="onSavePicture"/>
          <WINDOW layout="0,270,300,30" align="linear">
              <BUTTON layout="100,30" text="open" onClick="{cam.open()}"/>
              <BUTTON layout="100,30" text="take" onClick="{cam.takePicture()}"/>
              <BUTTON layout="100,30" text="close" onClick="{cam.close()}"/>               
          </WINDOW>
        </WINDOW>       
    </UILAYOUT>
</MOML>


위 예제는 사진이 저장되면 현재 컨테이너의 onSavePicture function이 호출이 되어 사진을 저장하는 예제입니다.

CAMERA와 같이 UI를 갖는 UI ELEMENT인 경우 onSavePicture와 같이 이벤트가 Attribute로 지정 되어있습니다. 이 경우 이벤트 발생시 실행될 함수명을 파라미터로 전달 할 수 있습니다. onSavePicture="onSavePicture" 는 이미지가 저장되면 onSavePicture 함수를 호출합니다.

⚙︎ addEventListener를 통한 이벤트 함수 연결

위와 같이 Attribute가 아닌 addEventListener를 통해 UI에 이벤트를 걸 수도 있습니다.

addEventListener는 [ui id].addEventLister('[event name]', '[moml function name]')입니다. 사용방법은 앞서 addEventListener를 사용하여 이벤트는 거는 방법과 같이 addEventLister에 발생할 이벤트와 이벤트 발생시 실행될 함수를 지정합니다.

아래 코드는 앞서 설명 드린 attribute를 통한 이벤트 함수 연결의 예제를 addEventListener를 사용하여 이벤트를 연결하는 방법으로 바꾼 것입니다.

<?xml version="1.0" encoding="utf-8"?>
<MOML>
    <FUNCTION id="onSavePicture">
        <CMD cmd="{device.systemPopup('Alert',parameter.param[0],'확인','','')}"/> 
    </FUNCTION>

    <UILAYOUT portrait="300,300" landscape="300,300">
        <WINDOW layout="0,0,300,300" onCreate="{cam.addEventListener('onSavePicture', 'onSavePicture')}">
            <CAMERA id="cam" layout="0,0,300,270" savePath="storage:camera"/>
            <WINDOW layout="0,270,300,30" align="linear">
                <BUTTON layout="100,30" text="open" onClick="{cam.open()}"/>
                <BUTTON layout="100,30" text="take" onClick="{cam.takePicture()}"/>
                <BUTTON layout="100,30" text="close" onClick="{cam.close()}"/>                 
            </WINDOW>
        </WINDOW> 
    </UILAYOUT>
</MOML>


카메라를 감싸고 있는 WINDOW UI영역 생성시 발생하는 onCreate 이벤트에 카메라의 addEventListener 함수를 실행하여 이벤트를 등록하도록 되어있습니다.

onCreate 객체는 UI를 갖는 객체가 공통으로 가지고 있는 이벤트 입니다. addEventListener를 통하여 이벤트를 등록하는 경우 앞서 object에 이벤트를 연결하기 예제에서 나온 것과 같이 CMD에 지정하여도 동일하게 동작합니다.

스크립트 사용하기

MOML은 버튼 클릭 시 화면전환이나 애니메이션 동작과 같이 화면상의 내용이 바뀐다거나 이벤트 처리를 하기 위하여 FUNCTION SCRIPT를 사용합니다.

MOML 스크립트 이해

MOML에서는 로직 처리를 위해 XML기반의 FUNCTION SCRIPT 방식을 사용합니다. FUNCTION SCRIPT는 독립적인 실행이 가능한 단위들을 XML로 작성하는 방식으로 javascript과 같은 일반적인 스크립트 언어는 명령문의 각 부분이 다른 부분과 종속적인 부분이 많아 재 활용성이 떨어진다는 점을 보완하기 위해 만들어진 SCRIPT방식입니다.

⚙︎ FUNCTION SCRIPT 구조

FUNCTION SCRIPT는 <FUNCTION>, <CMD>, <ELSECMD> 과 같은 Tag를 사용합니다.

<CMD condition="" cmd="" elseCmd=""/>

<FUNCTION id="login">
    <CMD condition="..." cmd="..." elseCmd="..."/>

    <CMD condition="...">
        <CMD cmd="..."/>
        <ELSECMD cmd="..."/>
    </CMD>
</FUNCTION>


FUNCTION SCRIPT는 <UILAYOUT>외부에 정의합니다.

하나의 독립적인 실행이 가능한 단위가 CMD입니다. 여러 CMD을 순차적으로 실행하여 하나의 기능으로 동작하는 단위는 FUNCTION입니다.

함수를 호출하는 최소 단위는 FUNCTION으로 CMD을 단독으로 호출하지는 못합니다.

⚙︎ 조건에 따른 함수 실행

FUNCTION Script를 사용하는 방법을 보기 위하여 앞서 나온 로그인 예제 코드에서 로그인 이전에 WIFI 접속 여부를 판단하여 WIFI가 켜져 있지 않는 경우, 알람을 띄우는 코드를 넣어 보도록 하겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT portrait="320,460">
        <BUTTON layout="25,235,200,45" text="go" onClick="function.checkWifi" />
    </UILAYOUT>

    <FUNCTION id="checkWifi">
        <CMD condition="device.network.type=='wifi'"
             cmd="device.toastPopup('ok!')"
             elseCmd="device.systemPopup('error', 'Not wifi', 'OK', '', '')"/>
    </FUNCTION>
</MOML>


위의 코드 중 CMD 부분을 보면 condition은 상태여부를 판단하는 조건절이며, wifi가 켜져 있는 경우 cmd에 정의된 실행코드를 수행하며, 꺼져있는 경우 elseCmd부분에 정의된 실행코드가 동작 합니다.

함수의 실행은 실행을 시켜야 할 부분에서 function.함수ID(파라미터) 형태로 호출을 하게 됩니다. 따라서 함수 실행을 위하여 FUNCTION은 반드시 ID를 부여하여야 합니다.

버튼을 누르면 wifi 접속여부를 판단하는 함수인 function.checkWifi가 실행됩니다.

Function parameter & return 규칙

스크립트를 작성하다 보면 FUNCTION에 파라미터를 전달하거나, 처리된 결과값을 리턴해야 하는 경우가 발생합니다.
FUNCTION에서 파라미터를 전달하는 방법은 parameter object를 사용하는 방법과 사용자 정의 parameter를 사용하는 방법이 있습니다.

⚙︎ Parameter object 사용하기

MOML의 parameter object를 사용하여 변수를 전달하는 방법으로, param[index] 형태로 함수에 전달된 파라미터를 접근합니다.

<MOML>
    <UILAYOUT  portrait="300,300" landscape="300,300">
        <WINDOW layout="0,0,300,300" align="linear:vertical" defaultImg="#ffffff">
            <LABEL id="label" layout="100,50" text="label"/>
            <LABEL id="label1" layout="100,50" text="label1"/>

            <BUTTON layout="100,50" text="A" onClick="function.setLabel('Here!', 'MOML!')"/>
        </WINDOW>
    </UILAYOUT>

    <FUNCTION id="setLabel">
        <CMD cmd="label.text=parameter.param[0]"/>
        <CMD cmd="label1.text=parameter.param[1]"/>
    </FUNCTION>
</MOML>


⚙︎ 사용자 정의 parameter 사용하기

일반적인 함수 호출방법으로 FUNCTION에 지정한 파라미터 변수를 이용하여 처리하는 방법입니다.

<MOML>
    <UILAYOUT  portrait="300,300" landscape="300,300">
        <WINDOW layout="0,0,300,300" align="linear:vertical" defaultImg="#ffffff">
            <LABEL id="label" layout="100,50" text="label"/>
            <LABEL id="label1" layout="100,50" text="label1"/>

            <BUTTON layout="100,50" text="A" onClick="function.setLabel('Here!', 'MOML!')"/>
        </WINDOW>
    </UILAYOUT>

    <FUNCTION id="setLabel(param1, param2)">
        <CMD cmd="label.text=param1"/>
        <CMD cmd="label1.text=param2"/>
    </FUNCTION>
</MOML>

데이터 연동하여 화면 구성하기

앱에 효과를 주거나 다양한 형태의 화면을 구성을 하는 이유는 작은 모바일 화면에서 컨텐츠를 효과적으로 보여주기 위해서 입니다.
앞서 라벨이나 이미지 버튼 등 UI ELEMENT를 이용하여 화면을 구성하는 방법에 대해 보았습니다.

이제 구성된 화면에 내용물(컨텐츠)를 얻어와 채우는 방법을 살펴보도록 하겠습니다.

데이터 접근 방식

컨텐츠을 이용하기 위해 먼저 컨텐츠 데이터에 접근하는 방법을 살펴보도록 하겠습니다.
MOML에서는 파일 접근방식으로 상대경로, Base Path, Protocol 접근 방식을 지원합니다.

⚙︎ 상대경로 접근방식

현재 파일의 위치를 기준으로 상대적인 경로를 표시하는 방법입니다.

<LABEL layout="150,50"  defaultImg="img/test.png"/>


일반적으로 상대 경로는 위와 같이 폴더나 파일명을 바로 쓰거나 ./나 ../로 시작합니다. 현재의 경로가 folder1 이면 folder1/img/test.png을 찾게 됩니다. 만일 현재 경로가 folder2이면 folder2/img/test.png을 찾게 됩니다.

이와 같이 상대경로를 이용하여 코드를 작성하는 경우 폴더의 이름 변경 등이 용이 합니다.

⚙︎ Base Path 접근방식

애플리케이션의 Base 경로를 기준으로 경로를 표시하는 방법입니다.

<LABEL layout="150,50"  defaultImg="/img/test.png"/>


위와 같이 / 로 경로를 표시합니다.

Base 경로는 applicationInfo.xml파일에서 로 설정합니다.
만일 별도로 설정하지 않는 경우 applicatioInfo.xml 파일이 위치한 경로가 Base path 입니다. "/" 가 시스템의 최상위를 나타내지 않음에 주의하십시오. (시스템의 최상위는 "storage:/" 입니다.)

⚙︎ Protocol 접근 방식

일반적인 앱을 작성 할 때는 상대경로 또는 Base Path 방식을 주로 사용하게 됩니다. 그러나 저장된 사진을 불러 오는 것과 같이 애플리케이션의 영역을 벗어난 폴더에 접근한다거나 외부시스템의 리소스에 접근해야 하는 경우는 상대경로나 Base Path 방식으로 접근하는 것이 불가능 합니다.

이를 위하여 Protocol방식을 지원합니다.

protocol 설명
embed 애플리케이션 내장 리소스의 경로를 의미합니다.
storage OS의 파일 시스템에서 인식하는 경로를 의미합니다.
http, https 웹서버의 리소스 경로를 의미합니다.

사용방법은 path부분에 protocol의 명칭을 적고 경로를 적으면 됩니다.

<LABEL layout="150,50"  defaultImg=" storage:/mnt/sdcard/img/test.png"/>
<LABEL layout="150,50"  defaultImg=" embed:/xml/img/test.png"/>
<LABEL layout="150,50"  defaultImg=" http:/192.168.0.3/MOMLTest/xml/img/test.png"/>


embed 의 root 디렉토리 경로는 앱이 설치 된 폴더의 assets 폴더입니다. 따라서 /xml/test.xml 이라 쓰면 안드로이드인 경우 *.apk 내의 assets/xml/test.xml를 읽고 iOS인 경우 *.ipa내의 Payload/*.app/xml/test.xml을 읽게 됩니다.

embed 는 Base 경로를 외부시스템으로 설정하고 내부 리소스를 사용해야 하는 경우와 같이 항상 단말내의 리소스를 사용해야 하는 경우를 명시하기 위해 사용합니다.

storage의 경로는 OS파일 시스템의 경로와 동일합니다. 안드로이드에서 SD카드에 직접 접근(storage:/mnt/sdcard/)하거나 임시 파일을 기본 storage경로에 생성(storage:temp1.txt)하거나 사진 또는 음악 폴더와 같이 애플리케이션 영역을 벗어난 단말 시스템의 리소스를 가지고 오는 경우에 사용합니다.

DATASOURCE를 사용하여 데이터 얻어오기

앞서 화면 UI를 구성하고 데이터를 얻어오는 방법을 살펴보았습니다.

이제 리소스가 모두 갖추어진 상태에서 화면을 구성하는 데는 문제가 없습니다. 그러나 위의 방법만으로 서버로부터 수신된 데이터나 가변적인 데이터를 처리 하기는 어렵습니다. 이런 경우 MOML에서는 DATASOURCE라는 개념을 사용하여 서버로부터 수신된 데이터나 내부 데이터를 처리하는데 매우 편리한 방법을 제공합니다.

DATASOURCE는 UI와 데이터를 분리하여 작업 할 수 있는 방법으로 UI작업시 데이터를 받아와 표시해야 할 부분에 xpath로 파싱 할 값을 정한 후 이곳에 Data Source를 연결하는 방식입니다. 예제 코드를 보도록 하겠습니다.

아래는 두 개의 데이터 소스를 사용하여 하나의 화면을 구성하는 예제입니다.
먼저 아래와 같이 UI화면과 데이터를 작성합니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <DATASOURCE id="mainItem" src="data1.xml"/>
    <DATASOURCE id="subItem" src="data2.xml"/>

    <UILAYOUT portrait="300,300" landscape="300,300">
        <LABEL id="testLabel" layout="50,60,200,30" textAlign="center" defaultImg="#abcdef" text="{xpath.evaluateEx('mainItem', '/DATA/MAINITEM/TITLE/text()')}" />
        <LABEL id="testLabe2" layout="50,90,200,30" defaultImg="#fedcba" textAlign="center" text="{xpath.evaluateEx('subItem', '/DATA/SUBITEM/TITLE/text()')}" />
    </UILAYOUT>
</MOML>

data1.xml
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
  <MAINITEM>
    <TITLE>Animal</TITLE>
    <STATE>LIVE</STATE>
  </MAINITEM>
</DATA>

data2.xml
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
  <SUBITEM>
    <TITLE>LION</TITLE>
    <SEX>Male</SEX>
  </SUBITEM >
</DATA>


코드를 보면 UI작성시 코드의 라벨에 들어갈 text영역에 xpath로 datasource id와 datasource로 부터 파싱하여 가지고 올 값을 지정하고 있습니다.
이제 data.xml만 바꾸면 라벨의 값이 바뀌는 것을 확인 할 수 있습니다.

참고로 코드상에서 Data Source에 data1.xml, data2.xm과 같은 로컬 데이터를 지정하였으나 네트워크상의 URL을 지정 할 수도 있습니다.
만일 두 개의 서버로부터 데이터를 수신한 후 하나의 화면을 구성하는 경우 또는 화면은 동일하나 컨텐츠가 가변적인 템플릿과 같은 화면을 구성하는 경우 매우 유용하게 사용 할 수 있습니다.

LIST 만들기

앱을 개발시 많은 데이터를 표시하는데 있어 가장 기본적인 방법이 LIST입니다.

LIST는 정해 놓은 UI형태로 데이터를 반복적으로 표시하는 UI Elements입니다.

먼저 리스트를 구현하기 위하여 반복적인 데이터를 준비하도록 합니다.

listData.xml
<xml version="1.0" encoding="UTF-8"?>
<DATA>
  <CATEGORYGROUP>
    <IMAGE>
      <TITLE>http://localhost/mall/data/category/1020_ctlog</TITLE>
    </IMAGE>
    <CATEGORY id="list_category_0">
      <NAME><![CDATA[Slite]]></NAME>
      <URL>http://localhost/logeo/list_item.php?ca_id=102010</URL>
    </CATEGORY>
    <CATEGORY id="list_category_1">
      <NAME><![CDATA[WMF]]></NAME>
      <URL>http://localhost/logeo/list_item.php?ca_id=102020</URL>
    </CATEGORY>
  </CATEGORYGROUP>

  <ITEMLIST>
    <ITEM id="item_5644178937">
      <IMAGE>http://localhost/mall/data/item/5644178937_m</IMAGE>
      <NAME><![CDATA[Title1]]></NAME>
      <MAKER><![CDATA[[product1]]]></MAKER>
      <CUSTAMOUNT>329,000</CUSTAMOUNT>
      <AMOUNT>369,500</AMOUNT>
      <URL>http://localhost/logeo/item.php?it_id=5644178937</URL>
    </ITEM>
    <ITEM id="item_5644178936">
      <IMAGE>http://localhost/mall/data/item/5644178936_m</IMAGE>
      <NAME><![CDATA[Title2]]></NAME>
      <MAKER><![CDATA[[product2]]]></MAKER>
      <CUSTAMOUNT>361,000</CUSTAMOUNT>
      <AMOUNT>291,500</AMOUNT>
      <URL>http://localhost/item.php?it_id=5644178936</URL>
    </ITEM>
      . . . . .
  </ITEMLIST>
</DATA>


위 데이터는 상품에 대한 정보를 반복적으로 나타내고 있는 데이터 입니다.

위에서 작성한 상품데이터를 사용하는 LIST예제를 작성하기 전에 LIST를 사용하는 방법을 간단히 살펴보도록 하겠습니다.

리스트를 작성하는데 사용되는 tag는 <LIST><LISTLAYOUT>입니다.
LIST는 화면상에서 리스트가 차지하는 영역과 사용 할 Data Source를 지정합니다.
형식은 아래와 같습니다.

<LIST id="list" layout="320,300" dataSource="listData.xml" dataList="/DATA/ITEM" >


리스트 layout에서 리스트의 크기를 설정하고, 데이터소스로 사용될 데이터의 경로를 표시하고 있습니다.
dataList 부분은 dataSource에서 받는 데이터 중 리스트에 반복되는 데이터의 초기 경로를 지정하도록 되어있습니다.

<LISTLAYOUT condition="xpath.evaluate('./@group')=='1'">


LISTLAYOUT은 리스트에서 반복이 되는 Row의 UI를 배치하기 위한 하나의 unit입니다.

아래는 LIST UI Elements를 사용하여 작성한 리스트 화면 코드입니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT landscape="800,381">
        <LIST id="product_list" layout="0,50,800,332" dataSource="listData.xml" dataList="/DATA/ITEMLIST " divider="#00000000">
            <LISTLAYOUT>
                <WINDOW layout="0,0,400,110" align="relative" defaultImg="image/item_list_section.png">

                    <WINDOW id="photowindow" layout="25,5,102,102" align="linear:vertical|center" defaultImg="image/thumb_bg.png">
                        <IMAGE layout="{parent.width-3px},{parent.height-3px}" loadingEffect="fadeIn" loadingImg="image/defaultImg.jpg" defaultImg="{xpath.evaluate('./ITEM/IMAGE/text()')}" />
                    </WINDOW>

                    <LABEL layout="140,5,233,20"  text="{xpath.evaluate('./ITEM/MAKER/text()')}" fontSize="18" fontStyle="bold" fontColor="#da080b" />
                    <LABEL layout="140,30,233,45" text="{xpath.evaluate('./ITEM/NAME/text()')}" fontSize="14" fontStyle="bold" fontColor="#404040" />                  

                    <LABEL  layout="140,75,80,35" text="{function.left_isEmpty(xpath.evaluate('./ITEM/CUSTAMOUNT/text()'))}" fontSize="15"  fontColor="#a1a1a1" fontStyle="bold" textAlign="center" >
                        <IMAGE layout="0,{parent.height/2-1},{parent.width},1" defaultImg="{function.left_line(xpath.evaluate('./ITEM/CUSTAMOUNT/text()'))}" />
                    </LABEL>

                    <LABEL layout="{parent.width-self.width-20},75,153,35" text="{xpath.evaluate('./ITEM/AMOUNT/text()')}원" fontSize="23"  fontColor="#fe6c00" fontStyle="bold" textAlign="right|center" />

                    <IMAGE layout="370,43,17,19" defaultImg="image/ico_more.png"/>
                    <BUTTON layout="0,0,400,110" defaultImg="#00000000" pressedImg="#5000ff00" onClick="{userVariable.productURL=first_url.text,function.go_proDetail}" />
                    <LABEL id="first_url" layout="0,0,1,1" text="{xpath.evaluate('./ITEM/URL/text()')}" visible="invisible" />
                </WINDOW>
            </LISTLAYOUT>
        </LIST>
    </UILAYOUT>
</MOML>


LIST의 dataSource 속성에 dataSource= listData.xml 와 같이 받아올 경로를 지정하고, LIST내에서 반복되는 UI를 LISTLAYOUT에서 정의합니다.

LISTLAYOUT은 LIST내에서 하나의 row로 취급되며 data의 개수만큼 반복되어 출력합니다.

위의 코드는 정리하면 다음과 같은 순서로 처리됩니다.
1. List의 dataSource 에서 지정된 listData.xml파일을 불러온다.
2. 데이터 수신 후 dataList에 정의 다음 Tag 부분을 반복적으로 읽는다.
3. xpath.evaluate()로 해당 데이터 값을 읽어온다.
4. 불러온 데이터 값을 지정한 위치에 표시한다.

위 예제를 실행하면 다음과 같은 화면을 볼 수 있습니다.

⚙︎ 여러 개의 LISTLAOUT를 갖는 리스트

LIST 안에서 다른 형태의 Row로 구성하고 싶다면 여러 개의 를 사용합니다.
예로 리스트에 배경색을 두가지 색상으로 번갈아가며 출력하는 코드를 보겠습니다.

먼저 배경 색상이 다른 두 개의 LISTLAYOUT을 작성합니다. 그 후 LISTLAYOUT의 속성 중 condition에 조건을 지정하여 어느 조건에 출력되는 LISTLAYOUT인지를 판단하도록 합니다.
아래 예제는 리스트의 홀수 번째는 빨간색 배경을, 짝수 번째는 파란색의 배경을 넣는 예제입니다.

<LIST id="product_list" layout="800,332" dataSource="listData.xml" dataList="/DATA/ITEMLIST " divider="#00000000">
    <LISTLAYOUT condition="xpath.position()%2 == 0">
        <WINDOW layout="0,0,400,110" align="relative" defaultImg="#0000ff">
          . . . . .
        </WINDOW>
    </LISTLAYOUT>

    <LISTLAYOUT condition="xpath.position()%2 != 0">
        <WINDOW layout="0,0,400,110" align="relative" defaultImg="#ff0000">
          . . . . .
        </WINDOW>
    </LISTLAYOUT>
</LIST>


Objects

MOML은 자주 사용되는 기능이지만 개발이 어렵고 복잡한 기능들을 object로 단순화하여 사용하기 쉽게 제공합니다.
MOML 개발자는 object를 사용하면 예상하지 못했던 예외처리나 오류에 시간을 소모하는 시간을 단축시킬 수 있고, 높은 안정성을 보장받게 됩니다.

MOML에서 제공하지 않은 특수한 object는 직접 개발하여 사용할 수 있는 방법을 제공하고 있습니다. (Object를 만드는 방법은 “MOML Component Interface 다루기"로 별도의 문서로 예제와 함께 제공됩니다.)

UI Element는 대문자로 표기하는 반면에 Object는 소문자로 표기합니다.

DataBase

DataBase는 SQLite와 동일한 의미이며 MOML에서는 db로 표시합니다.
아래는 DataBase에 Table를 생성하는 예제입니다.

<FUNCTION>
  <CMD cmd="db.exec('CREATE TABLE IF NOT EXISTS CODAFDB( _id INTEGER PRIMARY KEY AUTOINCREMENT, feedUrl VARCHAR(255) NOT NULL, title TEXT NOT NULL)')"/>
<FUNCTION>


단말에서 DataBase를 사용하는 방법은 일반적인 DataBase를 사용하는 것과 동일하게 SQL문을 사용합니다.

MOML 엔진에서는 DataBase Query문을 실행 시키기 위하여 Select, Update, Insert, Delete 문 모두 exec 메소드를 사용하도록 되어있습니다. 또한 DataBase로부터 Query한 결과를 쉽게 사용 할 수 있도록 getXmlData() 메소드를 제공하고 있는데 이는 Query한 결과를 XML로 반환합니다.

만일 db.exec(‘SELECT FIRST, SECOND,THIRD FROM COUNTTABLE) 을 실행 후 db.result.getXmlData()를 호출하면 아래와 같은 데이터 XML이 추출됩니다.

<?xml version="1.0" encoding="utf-8"?>
<DATA>
   <ROW FIRST="DATA1" SECOND="DATA2" THIRD="DATA3" />
   ...
<ROW FIRST="DATA10" SECOND="DATA11" THIRD="DATA12" />
</DATA>


Animation

Animation은 앱을 보다 Interactive하게 꾸미거나, 역동적인 UI를 갖는 애플리케이션을 개발하는데 도움을 줍니다.
MOML에서 제공하는 animation object는 화면상에 보이는 모든 UI Element에 대해 animation 효과를 부여할 수 있습니다.

아래는 간단한 애니메이션 예제입니다.

animation.show('bg', ‘fade’, '', 3000, 'function.flower')


위 예제는 bg의 아이디를 가진 UI Element를 3초 동안 서서히 화면에 보이도록 하고, 애니메이션 효과가 완료되면 function.flower를 실행하라는 의미입니다. 아래는 자주 사용 되는animation으로 기능을 살펴보면 다음과 같습니다.

UI 컴포넌트가 설정한 시간 동안 해당 id의 객체를 보이게 한다.  
animation.show('id', 'effect', 'timecurve', milisec, 'endfunction')

UI 컴포넌트가 설정한 시간 동안 해당 id의 객체를 사라지게 한다.
animation.hide('id', 'effect', 'timecurve', milisec, 'endfunction')

UI Component가 설정한 시간 동안 설정한 좌표와, 크기로 Translate, Scale Animation을 실행 후에 보여지게 된다.
animation.flyIn('id', x, y, width, height, 'timecurve', milisec, 'endfunction')

UI Component가 설정한 시간 동안 설정한 좌표와, 크기로 Translate, Scale Animation을 실행 후에 안보여지게 된다.
animation.flyOut('id', x, y, width, height, 'timecurve', milisec, 'endfunction')

UI Component가 설정한 시간 동안 설정한 각도와 설정한 회전 중심에 따라 rotate Animation을 실행한다.
animation.rotate('id', degree, pivotX, pivotY, 'timecurve', milisec, endfunction)


animation은 파라미터 값을 변경하거나 동일한 UI Element에 여러 animation을 조합하여 적용할 수 있어 매우 다양한 효과를 연출할 수 있습니다.

참고로, animation의 파라미터 중 timecurve는 UI 오브젝트가 변화하는 시간을 의미하는데 "easeIn1-7"(점점처음을느리게), "easeOut1-7"(점점끝을느리게), "easeInOut1-7"(점점처음과끝을느리게), "roundTrip"(왕복), "bounce"(도착위치에서 튕김) 등이 있습니다.

애니메이션 도중에 애니메이션을 종료 시켜야 하는 경우에는 언제든 animation을 적용한 UI Element id에 stop명령을 줄 수 있습니다.

animation.stop(‘id’)


기타 Object

MOML에서 기본적으로 제공하는 Object들은 앱을 개발하는데 있어 가장 필수적인 object입니다.

기타 object들 로서 GPS나 WIFI와 같이 단말의 하드웨어 관련 상태나 동작에 관련된 부분은 device object에서 정의 하고 있으며, 앱 동작 중 웹브라우저 같은 다른 앱을 띄워야 하는 경우는 appLancher object를 사용합니다.

본 Tutorial에서는 object에 대한 간략한 소개와 사용방법에 대한 예를 들었습니다.
MOML에는 소개된 Object외에 앱 개발 시 자주 사용되는 유용한 많은 object를 제공하고 있으므로 MOML API문서를 참고하여 필요한 object를 활용하시기 바랍니다.

Multimedia(Video, Camera)

컨텐츠를 사용자에게 가장 효과적으로 제공하기 위해 스마트 단말에서 가장 자주 사용하는 멀티미디어 데이터를 사용하는 방법을 보도록 합니다.
실제 네이티브 코딩을 하여 멀티미디어 관련 데이터를 처리하는 것은 제조사와 단말 별로 조금씩 하드웨어적인 차이가 있어 여러 예외사항을 처리하기가 까다로우나 MOML에서는 간단히 해당 Tag를 사용합니다.

예로 카메라는 <CAMERA>, 비디오는 VIDEO>와 같이 해당 Tag를 적고 영역을 지정합니다.

Camera 사용하기

<?xml version="1.0" encoding="utf-8"?>
<MOML>
  <UILAYOUT portrait="320,480">
      <WINDOW layout="10,10,300,220" align="linear:horizontal">
          <CAMERA layout="240,180" margin="5,5,5,5" />
      </WINDOW>
  </UILAYOUT>
</MOML>


카메라가 표시될 영역을 <CAMERA layout="">로 표시하면 됩니다.
위의 코드에는 카메라의 미리보기 기능나 사진을 찍는 것과 같은 동작을 수행하는 코드가 없습니다.

그럼 동작 할 수 있도록 버튼을 배치하도록 합니다.

<?xml version="1.0" encoding="utf-8"?>
<MOML>
    <UILAYOUT portrait="320,480">
        <WINDOW layout="10,10,300,350" align="linear:vertical">
            <CAMERA id="cam" layout="300,300" margin="5,5,5,5"/>
            <WINDOW layout="300,30" align="linear:hJustify">
                <BUTTON text="open" onClick="{cam.open()}"/>
                <BUTTON text="take" onClick="{cam.takePicture()}"/>
                <BUTTON text="save" onClick="{cam.save()}"/>
                <BUTTON text="close" onClick="{cam.close()}"/>
                <BUTTON text="front" onClick="{cam.type='front'}"/>
                <BUTTON text="back" onClick="{cam.type='back'}"/>
            </WINDOW>
        </WINDOW>
    </UILAYOUT>
</MOML>


동작을 위한 버튼과 함께 savePath="storage:camera" onSavePicture="onSavePicture" 와 같은 옵션을 추가 하였습니다.
만일 사진을 찍은 후 저장 버튼을 누르면 savePath에 설정된 경로에 이미지가 저장됩니다. 여기서 storage:camera는 단말의 갤러리 폴더에 사진이 저장하라는 의미입니다.

사진 저장이 완료되면 이후 처리를 위하여 onSavePicture 속성에 onSavePicture 함수를 호출하도록 하였습니다.
실제 위의 코드에서는 onSavePicture 함수를 구현하지 않았으므로, 사진은 저장되나 이후 동작은 발생하지 않습니다.

위와 같이 MOML에서는 카메라를 호출하는 경우 카메라의 동작에 필요한 버튼이나 기능들이 all-in-one 형태의 UI로 나오지 않고 필요한 것만 자유로운 위치에 사용하도록 되어있습니다. 이러한 방법을 이용하여 다양한 형태의 카메라 UI를 구성 할 수 있습니다.

Video 사용하기

Video를 사용하는 것은 카메라를 사용하는 것과 동일합니다.
Video를 화면에 보이기 위하여 Camera에서 사용한 코드를 수정합니다.

<?xml version="1.0" encoding="utf-8"?>

<MOML>
    <UILAYOUT portrait="320,480">
        <WINDOW layout="10,10,300,350" align="linear:vertical">
            <VIDEO id="video" layout="300,300" src="moml.mp4" captionSrc="moml.smi" margin="5,5,5,5"/>
            <WINDOW layout="300,30" align="linear:hJustify">
                <BUTTON text="open" onClick="{video.play}"/>
                <BUTTON text="take" onClick="{video.pause}"/>
                <BUTTON text="save" onClick="{video.stop}"/>
                <BUTTON text="close" onClick="{video.close}"/>
                <BUTTON text="front" onClick=" {video.caption = !video.caption} "/>
            </WINDOW>
        </WINDOW>
    </UILAYOUT>
</MOML>


위의 코드는 앞서 나온 Camera의 코드의 UI를 유지하고 내용물만 바꾼 코드입니다. VIDEO의 경우 비디오 컨텐츠에 대한 src 속성과 자막의 동작 여부에 관련된 captionSrc 속성이 있습니다.

참고로 mp3, wav와 같은 Sound관련 멀티미디어 데이터는 화면 UI를 갖지 않으므로 Sound를 위한 별도의 XML Tag는 존재하지 않습니다. Sound 멀티미디어는 sound object를 사용합니다.

자세한 사용방법은 MOML API Reference를 참조하시기 바랍니다.

Map View

Map View는 화면상에 지도를 나타내기 위하여 주로 gps object와 함께 사용됩니다. Map View의 tag는 MAPVIEW입니다.
지도에 여러 지점의 위치를 표시하고 지점의 위치를 클릭하면 지점의 제목을 출력하는 예제를 보도록 하겠습니다.

iOS는 별도의 인증키를 발급받거나 추가적인 설정이 필요없지만, 안드로이드의 경우 Map View를 사용하기 위해서는 Google APIs Console(https://code.google.com/apis/console/)에서 인증키를 발급받아야 합니다.

인증키를 발급 받은 후 AndroidMenifest.xml를 열어 아래의 내용을 참고하여 permission과 발급받은 인증키를 입력합니다.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:required="false" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:required="false" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>

<permission android:name="kr.co.logeo.tablista01.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>
<uses-permission android:name="package명.permission.MAPS_RECEIVE"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>   

<application>

</application>

<uses-library android:name="com.google.android.maps" />
    <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="Google Map 인증키값"/>
</application>


MOML은 Main Activity에 MOMLActivity를 상속받아 구현되지만, google map을 사용하는 경우에는 MOMLFragmentActivity를 상속받아야 합니다.

앞서 코드 테스트를 위하여 사용하였던 MOML APPLICATION VIEWER는 MOMLActivity를 상속 받아 구현되어 있으므로 MAPVIEW의 동작을 확인하기 위해서는 별도의 프로젝트를 만들어 아래와 같이 네이티브 코드를 작성해야 합니다.

import org.mospi.moml.framework.pub.core.MOMLFragmentActivity;
import android.os.Bundle;

public class TabListA01 extends MOMLFragmentActivity{
    /** Called when the activity is first created. */
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.loadApplication("moml/applicationInfo.xml");
    }
}


Eclipse 혹은 ADT의 Project Property에서 google-play-service_lib를 추가하고, Build Path에 android-support-v4.jar를 추가합니다.

이제 MAPVIEW를 사용할 준비가 모두 끝났으니 소스를 작성하면서 동작을 확인해보도록 하겠습니다.
먼저 지도에 표시할 지점에 대한 정보가 들어있는 데이터를 작성하도록 합니다.

mapViewData.xml
<?xml version="1.0" encoding="utf-8"?>
<MAPDATA>
    <MARKERITEM lat="37.456736770757715" lon="127.16634035110474" title="1호점" snippet="서울시 강남점"/>
    <MARKERITEM lat="37.51622769566558" lon="127.0201063156128" title="2호점" snippet="서울시 역삼점"/>
</MAPDATA>

Map를 사용하는 화면을 구성하도록 합니다.
<?xml version="1.0" encoding="UTF-8"?>
<MOML version="1.0">
    <UILAYOUT portrait="320,300" landscape="320,300">
        <MAPVIEW id="mapview" layout="0,0,320,300"
           mapType="default" dataSource="mapViewData.xml" dataList="/MAPDATA/MARKERITEM"
           latitudePath="./@lat" longitudePath="./@lon" titlePath="./@title"
           snippetPath="./@snippet" imagePath=" "/>
    </UILAYOUT>
</MOML>


mapViewData.xml의 지점이 지도위에 출력되고, 지점을 터치하면 지점의 title과 snippet이 출력됩니다.

GPS로부터 내 위치를 수신하여 지도에 출력하기 위해 소스에 다음과 같이 추가합니다.

<?xml version="1.0" encoding="UTF-8"?>

<MOML version="1.0">
    <FUNCTION id="gpsLocation">
        <CMD condition="userVariable.gpsMarker != ''" cmd="mapview.removeMarker(userVariable.gpsMarker)"/>
        <CMD cmd="userVariable.gpsMarker = mapview.addMarker(parameter.param[0], parameter.param[1], '내위치', parameter.param[2], 'img/timeclose.png')"/>
        <CMD cmd="mapview.setCenter(parameter.param[0], parameter.param[1])"/>
    </FUNCTION>

    <FUNCTION id="onAnnTouched">
    </FUNCTION>

    <CMD cmd="device.gps.addEventListener('gpsLocation', 'gpsLocation')"/>
    <CMD cmd="device.gps.readyGPS"/>

    <UILAYOUT portrait="320,300" landscape="320,300">
        <MAPVIEW id="mapview" layout="0,0,320,300"
           mapType="default" dataSource="mapViewData.xml" dataList="/MAPDATA/MARKERITEM"
           latitudePath="./@lat" longitudePath="./@lon" titlePath="./@title"
  snippetPath="./@snippet" imagePath=" " onAnnTouched="onAnnTouched"/>
    </UILAYOUT>
</MOML>


GPS로부터 위치를 수신할 때마다 gpsLocation FUNCTION이 실행됩니다.
이때 지도에 GPS위치를 addMarker function으로 추가하면 지도에 출력됩니다.
setCenter function으로 지도의 중심 위치도 함께 변경해 줍니다.

GPS위치를 수신할 때마다 지도의 중심위치를 변경하고 싶지 않을 때에는 <FUNCTIONITEM cmd="mapview.setCenter(parameter.param[0], parameter.param[1])"/>를 삭제하면 됩니다.

onAnnTouched에 수행할 FUNCTION id를 지정해주면 지점을 터치했을 때 화면을 이동하거나 처리를 수행할 수 있습니다.

Theme

스크립트 단점은 반복적인 코드를 빈번하게 사용되므로, 복잡하고 길어지게 되면 가독성이 떨어져 분석하기 어려운 문제가 발생 할 수 있습니다.
반복적인 코드를 수정할 일이 발생하게 되면 해당되는 모든 부분을 일일이 수정을 해야 하는 불편함이 있습니다.

MOML에서는 이러한 단점을 보완하기 위한 방법으로 Theme를 제공합니다. Theme를 사용하면 반복적인 코드를 단순하게 하는 이점 이외에 Theme을 바꾸는 것 만으로 다른 분위기의 앱을 만드는 것이 가능합니다.

Theme 의 종류

MOML에서 제공하는 Theme는 적용 방법에 따라 System, Application, Layout Theme로 분류 됩니다.

⚙︎ System Theme

System Theme는 가장 기본이 되며, moml engine에서 제공되는 Theme입니다.
적용되는 범위가 어플케이션 전체에 적용되는 Theme로 applicationInfo.xml 파일에서 설정을 합니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <APPLICATIONINFO>
        <START url="main/mainNavigation.xml"/>
        <THEME />
        <UPDATEINFO realTimeType="qMark"/>
    </APPLICATIONINFO>
</MOML>


기본적으로 제공되는 Theme 종류는 default, iOS, android입니다.
아무런 theme 정보가 없으면 default값이며, default옵션은 각 OS의 UI를 따른다는 의미입니다.

Theme 파일을 ApplicationInfo.xml 파일에 THEME tag에 정의하여 사용합니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <APPLICATIONINFO>
        <NAME appFolder="AgateApiDemo"/>
        <START url="main/mainNavigation.xml"/>
        <THEME src="themeAgate.xml"/>
        <UPDATEINFO realTimeType="qMark"/>
    </APPLICATIONINFO>
</MOML>


<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <THEMES id="theme2">
        <THEME id="textLabel" fontSize="12" fontColor="#753300"/>
        <THEME element="LABEL" parent="textLabel"/>
        <THEME element="CHECKBOX" parent="textLabel"/>
    </THEMES>
    <UILAYOUT portrait="320,460" landscape="320,460" theme="loginTheme.xml|theme2">
             ...
    </UILAYOUT>
</MOML>


위와 같은 Layout Theme는 <UI> Tag 내의 UI Elements들에 대해 영향을 주는 지역 Theme입니다.

THEME 작성하기

THEME을 이용하여 화면을 꾸미는 방법을 살펴보도록 하겠습니다.

⚙︎ Layout Theme 작성하기

THEME의 이해를 위하여 THEME의 종류 중 먼저 Layout Theme를 사용하는 예제를 보도록 하겠습니다.

먼저 아래와 같이 UI 구조만을 갖는 xml을 작성합니다.

Bar.xml
<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <UILAYOUT  portrait="320,460">
        <LABEL layout="0,0,320,40" align="relative" text="Hello MOML!">
            <BUTTON layout="10,5,60,30" text="BACK"/>
        </LABEL>           
    </UILAYOUT>
</MOML>


위 코드는 타이틀 바 배치하고 꾸미기의 예제 코드에서 이미지나 색상 등을 모두 제외하고 구조만 남겨 놓은 코드입니다.
화면을 실행하면 아무 디자인이나 색상이 없는 단순 버튼만 나옵니다.

이 코드에 Layout Theme를 적용을 하여 화면을 꾸며보도록 하겠습니다.
<THEMES>을 선언하여 내용을 작성하고 UILAYOUT에 THEMES에서 지정한 id을 사용 테마로 지정하여 줍니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <THEMES id="bar">
        <THEME element="BUTTON" fontSize="15" textAlign="center" fontColor="#ffffff" />
        <THEME element="LABEL" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="#335533" />
    </THEMES>

    <UILAYOUT  portrait="320,460" theme="bar">
        <LABEL layout="0,0,320,40" align="relative" text="Hello MOML!">
            <BUTTON layout="10,5,60,30" text="BACK"/>
        </LABEL>               
    </UILAYOUT>
</MOML>


위의 코드는 3.2의 예제화면과 동일한 화면을 보여 줍니다. 하나의 UI 파일에는 여러 개의 THEMES Tag가 올 수 있습니다.
따라서 UILAOUT에도 theme="themeid1|themeid2|themeid3" 와 같이 여러 개의 THEMES의 ID를 부여 할 수 있습니다.

실제 적용될 스타일 지정은 THEMES 안쪽에 있는 THEME에서 합니다. THEME Tag는 THEME가 적용될 범위를 지정하기 위해 id, element, parent라는 3가지의 고유 속성을 갖습니다.

그럼 3가지 고유 속성을 사용하는 방법을 보기 위해 위의 코드에서 버튼을 하나 더 추가해 보겠습니다.

<LABEL layout="0,0,320,40" align="relative" text="Hello MOML!">
    <BUTTON layout="10,5,60,30" text="BACK"/>
    <BUTTON layout="250,5,60,30" text="NEXT"/>
</LABEL>


화면을 보면 BACK버튼과 같은 스타일의 NEXT 버튼이 생성되었습니다.
이는 THEME의 element 속성값을 element="BUTTON"이라 선언을 하여서 BUTTON에게 모두 fontSize="15" textAlign="center" fontColor="#ffffff" 의 속성을 일괄적으로 적용하기 때문입니다. 이와 같이 element 속성은 해당 ELEMENT에 일괄적으로 적용됩니다.

id속성은 theme가 적용되는 범위를 제한하는데 사용 됩니다.

위의 코드에서 NEXT 버튼의 다른 속성을 유치하며 글자색상만 빨간색으로 바꾸어 보도록 하겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <THEME id="red" fontColor="#ff0000" />
    <UILAYOUT portrait="320,460" theme="bar">
        <LABEL layout="0,0,320,40" align="relative" text="Hello MOML!">
            <BUTTON layout="10,5,60,30" text="BACK"/>
            <BUTTON themeId="red" layout="250,5,60,30" text="NEXT"/>
        </LABEL>
    </UILAYOUT>
</MOML>


위와 같이 id가 "red"인 THEME를 추가하고 NEXT 버튼에 themeId="red"을 하여 주도록 하였습니다.
이때 NEXT 버튼은 BUTTON 전체에 해당하는 THEME와 ID에 해당하는 THEME 두 가지의 THEME속성을 갖게 됩니다.

parent 속성은 theme 상속 관계를 나타냅니다.
예를 들어 앞의 코드에서 button의 element 속성을 사용하지 않고 다음과 같이 나타낼 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<MOML>
    <THEMES id="bar">
        <THEME id="mom" fontSize="15" textAlign="center" />
        <THEME id="white" fontColor="#ffffff" parent="mom"/>
        <THEME id="red" fontColor="#ff0000" parent="mom"/>
        <THEME element="LABEL" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="#335533" />
    </THEMES>

    <UILAYOUT portrait="320,460" theme="bar">
        <LABEL layout="0,0,320,40" align="relative" text="Hello MOML!">
            <BUTTON themeId="white" layout="10,5,60,30" text="BACK"/>
            <BUTTON themeId="red" layout="250,5,60,30" text="NEXT"/>
        </LABEL>               
    </UILAYOUT>
</MOML>


여기서 white와 red의 id값을 갖는 THEME는 parent 속성에 지정된 mom theme의 속성을 갖게 됩니다.
이와 같이 layout theme는 UILAYOUT과 함께 id, element, parent속성을 이용하여 화면 별 스타일을 만드는데 사용하여 화면 구성과 스타일 코드를 구분하여 작성하는데 사용됩니다.

⚙︎ Application THEME 파일 작성하기

Application Theme는 앞서 소개를 한 것처럼 애플리케이션 전체에 적용되는 테마입니다.
Application theme를 이용하면 theme 파일 교체만을 통하여 전체적인 앱의 분위기를 바꿀 수 있습니다.

그럼 application theme파일을 작성해 보도록 합니다.
구조적으로 layout theme는 MOML UI파일에 속하는 반면 application theme은 MOML THEME파일에 속합니다. 따라서 UI를 갖지 않는 파일 형태로 작성됩니다.

그럼 간단히 THEME 파일을 만들어 보도록 하겠습니다.

themesample.xml
<MOML>
    <THEME element="BUTTON" fontSize="15" textAlign="center" fontColor="#ffffff" defaultImg="#ababab"/>
    <THEME element="LABEL" textAlign="center" fontColor="#00ff00" fontSize="20" defaultImg="#335533" />
</MOML>


THEME 전용 파일을 만드는 것은 앞서 설명한 Layout Theme와 동일합니다.
테마파일을 만들었으면 애플리케이션이 테마를 읽을 수 있도록 지정합니다.

애플리케이션 테마를 사용하는 방법은 두 가지 방법이 있습니다. 먼저 앞서 설명한 APPLICATIONINFO에서 지정하는 방법을 보겠습니다.

<APPLICATIONINFO>
    <THEME src="themesample.xml"/>
    . . . .
</APPLICATIONINFO >


애플리케이션은 시작 시 APPLICATIONINFO가 있는 XML파일을 읽어 환경을 설정하는데 이때, theme 파일을 지정하여 처음 애플리케이션이 로딩될 때 사용할 파일을 지정할 수 있습니다.

또 하나의 방법은 application객체를 이용하는 방법입니다.

<CMD cmd="application.loadTheme(‘themesample.xml’)"/>


이 방법은 application객체의 loadTheme 함수를 이용하는 것으로 상황에 따라 테마를 바꾸는 경우 사용하는 방법입니다.
applicationInfo.xml에 위의 theme 파일을 지정한 후 layout theme의 bar.xml을 실행하면 앞서 만든 타이틀바 예제와 동일한 결과 화면이 나옵니다.

Wireless 업데이트

MOML앱은 스크립트 언어로 UI와 LOGIC 변경이 가능하다는 점을 이용하여 서버 측에 소스코드를 두고 필요에 따라 화면 구성 및 컨텐츠를 쉽게 바꿀 수 있는 앱 개발이 가능합니다. 주로 컨텐츠에 따라 화면구성을 자주 바꾸어 주거나, 잦은 업데이트를 해야 하는 애플리케이션에 자주 쓰이는 기능입니다.

Wireless 업데이트를 위해 필요한 몇 가지 설정에 대해 알아보도록 합니다.

리소스 Cache설정하기

일반적으로 서버와 통신을 하는 애플리케이션의 경우 사용되는 리소스는 애플리케이션 내부에 존재하는 리소스와 통신을 통해 받아오는 리소스로 구분될 수 있습니다.
예로 상품을 소개하는 애플리케이션의 경우 화면을 구성하고 있는 버튼들의 이미지는 내장 이미지을 사용하고 상품 이미지와 같은 것은 실시간으로 받아와야 합니다.

MOML Engine은 외부에서 받아오는 이미지에 대해 이미지 Cache 기능을 하기 때문에 외부이미지 리소스에 대한 Type을 정해 줄 필요가 있습니다.
앞서 잠깐 언급하였듯이 APPLICATIONINFO의 하위속성인 UPDATEINFO의 realTimeType 속성을 사용하여 애플리케이션의 리소스 업데이트 속성을 지정 할 수 있는데, realTimeType은 qMark, all, none, 3가지 values를 가지고 있으며, 각각은 다음과 같은 의미를 갖습니다.

Value Description
qMark 요청 url에 ? 가 있을 경우에만 실시간 데이터로 인식한다.
all 모든 요청에 대해 실시간 데이터로 인식한다.
none(default) 모든 요청에 대해 실시간 데이터로 인식하지 않는다.

설정 값이 all인 경우 캐시는 동작하지 않습니다.
설정 값이 none인 경우 모든 데이터를 캐시하게 됩니다.
따라서 한번 받아온 후 캐시에 데이터가 있으면 다시 받아 오지 않습니다.

<UPDATEINFO realTimeType="all" />


위의 코드의 경우 모든 데이터에 대해 실시간으로 값을 받아옵니다.
만일 아래와 같이 realTimeType이 qMark로 되어있고 코드상에 defaultImg="http://remote/image.png? 로 되어 있다면 image.png에 대하여 캐시를 하지 않고 요청 시 마다 image.png 이미지를 받아옵니다.

<BASE url="http://mospi.org/moml/" />
<UPDATEINFO realTimeType="qMark" />


서버로부터 실시간 UI 변경하기

HTML과 같은 스크립트 언어는 서버로부터 HTML 코드를 받아와 UI을 그려주므로, 문제가 있는 경우 서버에서 코드를 수정하여 수정할 수 있습니다.
마찬가지로 MOML도 서버에 코드를 두어 실시간으로 반영되는 UI를 개발할 수 있습니다.

⚙︎ 환경설정파일 서버에 두기

애플리케이션의 UI애플리케이션 개발 시 환경설정 파일의 경로를 서버에 놓는 경우 얻을 수 있는 이점은 코드를 변경 할 때 마다 컴파일을 하지 않아도 된다는 점입니다.

아래 코드는 네이티브 앱으로 패키징을 하는 코드입니다.

public class SampleActivity extends  MOMLActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        loadApplication("http://remoteserver.com/sample/applicationInfo.xml");
//URL 주소에 있는 값을 가지고 온다.
    }
}


위 코드는 단말 외부에 applicationInfo.xml 파일을 두고 loadApplication에서 통신을 통하여 호출하도록 되어있습니다.
이 경우 어플리케이션의 BASE 경로 값은 applicationInfo.xml이 위치한 경로가 됩니다.

이와 같은 구조로 개발시 재 컴파일 없이 변경된 코드의 결과를 확인 할 수 있다는 점은 UI를 개발하는데 있어 많은 편리한 점을 줄 수 있습니다.
예를 들면, 웹 디자이너가 웹 디자인을 한 후 개발자에게 html코드와 함께 디자인페이지를 같이 넘기는 것과 같은 방식으로 Native 애플리케이션 개발도 동일한 방법으로 개발자의 도움 없이 디자이너가 디자인과 MOML코드를 작성하여 개발자에게 전달할 수 있습니다.

버전별 파일 업데이트 하기

서버측에 코드를 두는 것은 개발의 편의성이나 업데이트시에는 유용하나 번번한 통신이나 통신 속도에 따라 늦은 화면 반응의 문제가 발생 할 수 있습니다.
이러한 경우에는 리소스와 코드파일을 단말측에 두고 업데이트가 필요한 파일들만 일괄적으로 변경하는 기능을 사용 할 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<MOML>
    <APPLICATIONINFO>
        <BASE url="http://mospi.org/demos/" />
        <UPDATEINFO url="/server_res_ver_info.xml" />
        <NETWORK requestMethod="post" />
        <START url="spit.xml" />
    </APPLICATIONINFO>
</MOML>


UPDATEINFO는 서버측에 업데이트가 되어야 하는 리소스가 있는 경우 이를 확인하여 처리하기 위한 태그입니다.
UPDATEINFO을 설정하는 경우 앱 실행 시 서버의 업데이트 정보를 비교하도록 되어 있습니다.

url속성으로 지정된 server_res_ver_info.xml은 서버로부터 미리 다운로드 받을 파일들의 파일명과 버젼이 나열되어 있습니다.
최초 어플리케이션이 시작될 때 나열된 파일들을 모두 다운로드 하여 sd카드에 저장 한 후 실제 요청이 있을 때는 서버의 resource를 사용하는 대신 다운로드하여 저장된 resource를 사용합니다. 어플이 시작 될 때 마다 server_res_ver_info.xml의 내용을 읽어 들여 업데이트 된 파일이 있나 확인 후 업데이트 된 resource가 있으면 다운로드 받아 sd카드에 다시 저장합니다.

WEBVIEW

WEBVIEW는 앱 내애서 HTML 컨텐츠를 다루기 위하여 사용됩니다.
MOML에서는 WEBVIEW ELEMENT를 제공하므로서 손쉽게 앱안에서 HTML로 만들어진 페이지를 호출 할 수 있습니다.

WEBVIEW로 모바일 페이지 접속하기

WEBVIEW는 일반적인 웹 페이지를 이용하여 웹 애플리케이션을 개발에 필요한 기능을 지원합니다.

<WEBVIEW layout="0,0,300,300" loadSrc="http://www.yooic.com" clientControl="true" loadingProgress="true"/>


위의 코드는 www.yooic.com에 접속하기 위한 방법입니다.
단순히 웹뷰가 들어갈 영역을 지정한 후 loadSrc에 호출할 페이지 경로를 적어주면 됩니다.

경로는 데이터 접근방식에 나와있는 방법과 같이 loadSrc="/local/index.htm"형식으로 로컬페이지를 호출 할 수 있습니다.
참고로 loadSrc에는 페이지 url만 들어갈 수 있는 것은 아니며, html소스코드를 입력하여도 동일하게 동작합니다.

<WEBVIEW layout="0,0,300,300" loadSrc="&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;" clientControl="true" supportZoom="true"/>


clientControl은 WEBVIEW에서 제공하는 메소드를 사용 할 수 있는 버튼의 유무를 나타내는 것으로 clientControl="true"로 하는 경우 forward, back, refresh 버튼이 생기게 됩니다.

웹뷰에 이미지 등을 넣어 확대/축소 기능이 동작해야 하는 경우 supportZooom="true"로 설정합니다.

xml