アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

OnsenUIを使って、Flickrアプリを5分で作ろう

この記事は、英語版アシアルブログの翻訳記事です。
(原文はこちら

==============================

この記事では、Flickr APIを利用して写真を表示するアプリを、HTML5 モバイル UIフレームワークOnsenUIを利用して作成します。

さらに、ボタンのスピナーアニメーションを使うことで、アプリに生き生きとした見た目を与えます。

今回作成するのは以下のアプリです。実際に動くので、触ってみてください。



1. プロジェクトを作成する



1. Monacaダッシュボードで、「新しいプロジェクト」をクリックします。





2. 「Onsen UI最小限のテンプレート」を選択します。





プロジェクトの名前を「Flickr」とし、IDEを起動します。



OnsenUI最小限のテンプレートには、page1.htmlとpage2.htmlを行き来するナビゲーターコンポーネントが含まれています。



2. コードを書く



1. page2.htmlを削除します。



今回作成するのは1ページのアプリなので、page2.htmlは必要ありません。
page2.htmlを右クリックし、「削除」をクリックします。

2. ナビゲーターツールバーのタイトルを変更する



home_navigator.html を開き、 title="Page 1" となっている部分をを title="Flickr" に変更します。

3. 取得したデータを操作するコントローラーを作成する



flickr.js という名前のファイルを www フォルダーに作成し、以下のコードをコピーして貼り付けます。



function FlickrController ($scope) {
 
    $scope.fetchPhotos = function(){
        $scope.failed = false;        
        $scope.isFetching = true;
 
        $.ajax({
            url: "http://api.flickr.com/services/feeds/photos_public.gne?format=json",
            dataType: "jsonp",
            jsonpCallback: 'jsonFlickrFeed',            
            success: function(feeds){
                $scope.$apply(function(){
                    $scope.feeds = feeds;
                    $scope.isFetching = false;
                    $scope.failed = false;
                });
            },
            error: function(error){
                $scope.$apply(function(){
                    $scope.failed = true;                                   
                    $scope.isFetching = false;    
                });
            }
        });
    };
}


4. flickr.js を index.html で読み込む



index.html のタグ内に、以下の記述を追加します。



<script src="flickr.js"></script>




5. page1.htmlを編集し、FlickrControllerが取得したデータを表示する



page1.html を開き、既存のコードを全て消去して、以下のコードに書き換えます。



<div ng-controller="FlickrController">
    <ons-list>
        <ons-list-item class="center">                          
                <ons-button type="cta" should-spin="{{isFetching}}" ng-click="fetchPhotos()">Fetch Photos</ons-button>
        </ons-list-item>
 
        <ons-list-item ng-animate="'zoom'" ng-show="failed">
            Oops! looks like Flickr is down.
        </ons-list-item>
 
        <ons-list-item ng-repeat="item in feeds.items">
            <img width="100%" ng-src="{{item.media.m}}">
        </ons-list-item>
    </ons-list>
</div>


6. 動作確認



ここまでで、コードの作成は終了です。Monaca IDEの「プレビュー」機能やMonaca Debuggerで、動作確認してみましょう。

7. FlickrControllerとpage1.htmlの結びつき



OnsenUIは、AngularJSをベースに作られています。AngularJSでは、コントローラーと、HTML要素を、ng-controllerで結びつけています。コントローラーは、以下の図で示されているように、$scopeオブジェクトを介してデータをDOMに渡しています。



1. FlickrControllerという名前の関数をコントローラーとして作成し、$scopeをこの関数に渡しました。$scopeを介して、DOMにデータを渡すことができます。DOMとコントローラーを、ng-controllerで結びつけています。

2. ボタンがクリックされると、$scope.fetchPhotos()が呼ばれます。

3. Flickrからデータを取得している間、ボタンにスピナーアニメーションが表示されます。

4. feed.items はFlickr APIから取得した配列です。ng-repeatを使って、配列の全要素を表示します。

5. ng-showを使って、APIの呼び出しが失敗した際のエラーメッセージを表示しています。

3. まとめ



OnsenUIを使うと、スムーズなアニメーション等のリッチなUIを備えたアプリを、簡単に作ることができます。

ng-controllerによって、データを簡単にDOMに渡すことができます。

4. ソースコード全文



index.html



<!doctype html>
<html lang="en" ng-app="myApp">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <link rel="stylesheet" href="plugins/plugin-loader.css">     
  <script type="text/javascript" src="plugins/plugin-loader.js"></script>
 
  <script src="flickr.js"></script>
 
  <script>
    angular.module('myApp', ['onsen.directives']);
 
    document.addEventListener("deviceready", onDeviceReady, false);
 
    function onDeviceReady() {
        // Now safe to use the Cordova API
    }
  </script>    
</head>
 
<body>
 
  <ons-screen page="home_navigator.html"></ons-screen>
 
</body>
</html>


home_navigator.html



<ons-navigator title="Flickr" page="page1.html"></ons-navigator>


flickr.js



function FlickrController ($scope) {
 
    $scope.fetchPhotos = function(){
        $scope.failed = false;        
        $scope.isFetching = true;
 
        $.ajax({
            url: "http://api.flickr.com/services/feeds/photos_public.gne?format=json",
            dataType: "jsonp",
            jsonpCallback: 'jsonFlickrFeed',            
            success: function(feeds){
                $scope.$apply(function(){
                    $scope.feeds = feeds;
                    $scope.isFetching = false;
                    $scope.failed = false;
                });
            },
            error: function(error){
                $scope.$apply(function(){
                    $scope.failed = true;                                   
                    $scope.isFetching = false;    
                });
            }
        });
    };
}


page1.html

>>HTML



Fetch Photos



Oops! looks like Flickr is down.









OnsenUI: How to Create Flickr Public Photos App in 5min

In this blog, I will walk through how to make an App that fetch photos from Flickr public photos api using Onsen UI. Plus how to use Button's spinner animation to make the App looks alive.




We will create the app below. Feel free to play with it.




1. Create the project from an Onsen minimum template



1. Go to Dashboard and click New Project






2. Choose Onsen UI Minimum Template





Name the project Flickr, and launch the IDE.


The template provides a navigator that manages two pages--page1.html and page2.html.






2. Write some codes



1. Delete page2.html


Since our app is a one page application, we do not need page2.html.
Right-click on page2.html and choose Delete.



2. Change navigator toolbar's title


Double click home_navigator.html and change title="Page 1" to title="Flickr"






3. Create a Controller for managing the feeds


Create a file called flickr.js in www folder.





function FlickrController ($scope) {

    $scope.fetchPhotos = function(){
        $scope.failed = false;        
        $scope.isFetching = true;

        $.ajax({
            url: "http://api.flickr.com/services/feeds/photos_public.gne?format=json",
            dataType: "jsonp",
            jsonpCallback: 'jsonFlickrFeed',            
            success: function(feeds){
                $scope.$apply(function(){
                    $scope.feeds = feeds;
                    $scope.isFetching = false;
                    $scope.failed = false;
                });
            },
            error: function(error){
                $scope.$apply(function(){
                    $scope.failed = true;                                   
                    $scope.isFetching = false;    
                });
            }
        });
    };
}



3. Linking flickr.js with index.html


Add this line to index.html





<script src="flickr.js"></script>






4. Modify page1.html to display the feeds in FlickrController


Open page1.html and replace the centent with the following codes:





<div ng-controller="FlickrController">
    <ons-list>
        <ons-list-item class="center">                          
                <ons-button type="cta" should-spin="{{isFetching}}" ng-click="fetchPhotos()">Fetch Photos</ons-button>
        </ons-list-item>

        <ons-list-item ng-animate="'zoom'" ng-show="failed">
            Oops! looks like Flickr is down.
        </ons-list-item>

        <ons-list-item ng-repeat="item in feeds.items">
            <img width="100%" ng-src="{{item.media.m}}">
        </ons-list-item>
    </ons-list>
</div>


5. How FlickrController and page1.html are connected


Onsen UI uses AngularJs under the hood. In AngularJs, we can link a controller to an element using ng-controller. The controller can provide data to DOM via scope as illustrated in the figure below:





1 We declare a controller called FlickrController by defining a function with $scope injected. We can then use the $scope to provide data to the DOM. We link the DOM to the controller via ng-controller


2 When the button is click, we tell Angular to call fetchPhotos() function of the scope.


3 We want the button to display a spinner when we are busy fetching photos from Flickr.


4 feeds.items is an array fetched from Flickr api. We use ng-repeat to display all items in that array.


5 Using ng-show we can show error message when the api call fails.



3. Wrap UP



  • Onsen UI makes it easy to write rich UI application with cool animation.

  • Using ng-controller, we can easily provide data to the DOM.



4. Complete source code


index.html





<!doctype html>
<html lang="en" ng-app="myApp">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <link rel="stylesheet" href="plugins/plugin-loader.css">     
  <script type="text/javascript" src="plugins/plugin-loader.js"></script>

  <script src="flickr.js"></script>

  <script>
    angular.module('myApp', ['onsen.directives']);

    document.addEventListener("deviceready", onDeviceReady, false);

    function onDeviceReady() {
        // Now safe to use the Cordova API
    }
  </script>    
</head>

<body>

  <ons-screen page="home_navigator.html"></ons-screen>

</body>
</html>



home_navigator.html




<ons-navigator title="Flickr" page="page1.html"></ons-navigator>


flickr.js




function FlickrController ($scope) {

    $scope.fetchPhotos = function(){
        $scope.failed = false;        
        $scope.isFetching = true;

        $.ajax({
            url: "http://api.flickr.com/services/feeds/photos_public.gne?format=json",
            dataType: "jsonp",
            jsonpCallback: 'jsonFlickrFeed',            
            success: function(feeds){
                $scope.$apply(function(){
                    $scope.feeds = feeds;
                    $scope.isFetching = false;
                    $scope.failed = false;
                });
            },
            error: function(error){
                $scope.$apply(function(){
                    $scope.failed = true;                                   
                    $scope.isFetching = false;    
                });
            }
        });
    };
}



page1.html



>>HTML



Fetch Photos



Oops! looks like Flickr is down.









safari4 betaで実装されたCSS Animationを使ってみました。

こんにちは。橋本です。

さて、今日は先日公開されたsafari4 betaで実装されたCSS Animationを使ってみたいと思います。(今回のサンプルはsafari4 beta、もしくはwebkitのnightlyビルドを使ってご覧ください)

CSS Animationとは何かと言いますと、文字通りCSSを使ってAnimation効果を表現する技術です。
まずこちらをご覧ください。

Falling Leaves 'Using CSS Animations and Transforms

これはwebkitの公式blogで紹介されていたサンプルなんですが、この美しく舞う落葉のアニメーション効果は全てCSSで定義されています。
では実際にどのようにアニメーション効果を定義するかを見ていきたいと思います。

まず、以下のように、キーフレームを定義します。
キーフレームの定義は、「@-webkit-keyframes」+「アニメーション名」で行います。



@-webkit-keyframes sample1 {
  from {
    top: 0px;
    left: 0px;
    animation-timing-function: ease-out;
    -webkit-transform:rotate(-50deg);
    background-color: #ffffff;
  }

  to {
    top: 480px;
    left: 320px;
    animation-timing-function: ease-out;
    -webkit-transform:rotate(50deg);
    background-color: #000000;
  }
}


キーフレームの中では、fromとtoという要素を用いて、アニメーションの始まりの状態と終わりの状態を定義します。
また、fromとtoの代わりに、「%」指定を用いて、経過時間毎の細かい変化を指定することもできます。



@-webkit-keyframes sample2 {
  0% {
    top: 0px;
    left: 0px;
  }

  50% {
    top: 100px;
    left: 100px;
  }
  
  100% {
    top: 200px;
    left: 200px;
  }
}


キーフレームで定義したアニメーションの状態については、一般的なcssのプロパティや「-webkit-transform」を用いた変化を指定出来る他、「animation-timing-function」という指定で、アニメーションの動きの速さの変化を定義することも出来ます。

これについては、ease、linear、ease-in、ease-out、ease-in-out、の四種類を既定値として指定出来る他、cubic-bezierという指定を用いて、独自の動きを定義することも出来ます。
animation-timing-functionについては、こちらのページが参考になります。

Cubic Bezier timing function

次に、定義したアニメーションを実際に使用する方法ですが、アニメーションを適用したい要素に対して、適用するアニメーション名や、オプションを指定していきます。



div {
  -webkit-animation-name: sample; //アニメーション名
  -webkit-animation-duration: 10s; //実行時間
  -webkit-animation-iteration-count: 5; //実行回数
  -webkit-animation-direction: alternate; //反復の有無
  -webkit-animation-play-state: running; //実行状態
  -webkit-animation-delay: 3s; //実行までの待ち時間

  width: 100px;
  height: 100px;
  position: absolute;
}


「-webkit-animation-name」は適用するアニメーションの名前です。
「-webkit-animation-name: sample1, sample2, sample3;」といった形で複数指定することも可能です。

「-webkit-animation-duration」はアニメーションを実行する時間です。
キーフレームで指定した「%」指定はは、ここで定義する時間に対する割合になります。
デフォルト値は「0」となっており、「0」の場合にはアニメーションはは実行されません。

「-webkit-animation-iteration-count」はアニメーションの実行回数です。「infinite」と指定すると、回数無制限に実行します。

「-webkit-animation-direction」は反復の有無です。
デフォルト値は「normal」です。「alternate」と指定することによって、fromからto(0%から100%)までアニメーションを実行した後、toからfromに対して、再度アニメーションを行うように出来ます。

「-webkit-animation-play-state」は実行状態です。「running」と指定することで、アニメーションを実行状態にし、「paused」と指定することで停止状態にすることができます。
javascriptを使ってアニメーションを制御するときに使用するのかもしれませんが、正直使い勝手がいまいち分かっていません(すみません)。

「-webkit-animation-delay」は実行までの待ち時間です。ここで指定した時間の経過後、アニメーションが実行されます。


以上をふまえて簡単にサンプルを作ってみました。
safari4 betaをお持ちの方は是非実行してみてください。
(一応iPhoneでもアニメーションを表示することは出来るのですが、少し挙動不信です。出来ればsafari4 betaを使って見ていただけたらと思います。)

サンプル

コードはこちらです。



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja" dir="ltr">
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, width=device-width">
    <title>shootingStar</title>
    <style type="text/css" media="screen">
	    @-webkit-keyframes fall{
	      from {
	        top: -10px;
	      }
	      to {
	        top: 400px;
	        left: 300px;
	      }
	    }
    
	    @-webkit-keyframes fadeout{
	      0% { opacity: 0;}
	      25% { opacity: 1;}
	      70% { opacity: 0.1;}
	      100% { opacity: 0;}
	    }
    
	    @-webkit-keyframes rotate{
	      0% { -webkit-transform: rotate(-180deg);}
	      100% { -webkit-transform: rotate(180deg);}
	    }
    
	    #main {
	      background: #ffffff url(images/bg_machi.jpg);
	      width: 320px;
	      height: 480px;
	    }

	    #star > div {
	      position: absolute;
	      top: -50px;
	      -webkit-animation-name: fall, fadeout, rotate;
	      -webkit-animation-iteration-count: infinite;
	      -webkit-animation-direction: normal;
	      -webkit-animation-timing-function: ease-in;
	    }
    
	    .shooting-star {
	      color: #ffff55;
	      font-size: 0.5em;
	      position: absolute;	
	    }
    
	    #star1 {
	      left: -10px;
	      -webkit-animation-duration: 1.5s;
	      -webkit-animation-delay: 5s;
	    }

	    #star2 {
	      left: 30px;
	    -webkit-animation-duration: 2s;
	    -webkit-animation-delay: 2s;	
	    }
    
	    #star3 {
	      left: 80px;
	      -webkit-animation-duration: 1s;
	      -webkit-animation-delay: 4s;
	    }
    
	    #star4 {
	      left: 150px;
	      -webkit-animation-duration: 1.5s;	
	    }
    
	    #star5 {
	      left: 200px;
	      -webkit-animation-duration: 2s;
	      -webkit-animation-delay: 5s;
	    }
    </style>
  </head>
  <body>
    <div id="main">
      <div id='star'>
        <?php for ($i = 1; $i < 5; $i++): ?> 
            <div id="star<?php echo $i ?>" class="shooting-star">★</div>
        <?php endfor; ?>
      </div>
    </div>
  </body>
</html>


javascriptと上手く組み合わせれば、さらに複雑で面白いアニメーション効果を作ることも出来ると思います。
皆さんも是非試してみてください。