Tabris.jsã¯ãå¥ã®ã¯ãã¹ãã©ãããã©ãŒã ïŒAndroidãIOSïŒã¢ãã€ã«ãã¬ãŒã ã¯ãŒã¯ã§ãã ãã®ãããªããŒã«ã®å€§éšåãšã¯ç°ãªããæšæºãŸãã¯ChromeããŒã¹ã®WebViewã®ã©ãããŒã§ã¯ãããŸããã Tabrisã¯ãjavascriptããå©çšå¯èœãªäžé£ã®ãã€ãã£ãã³ã³ããŒãã³ããæäŸããŸãã ç§ãç¥ã£ãŠããæãè¿ãé¡äŒŒç©ã¯ã
Telerik Native Script ã
Appcelerator ã
React Nativeã§ãã
ãã®ãããTabrisã¯äœããã©ãŒãã³ã¹ïŒãã ãéåžžã«äŸ¿å©ïŒã®HTML5 + WebViewããé¢ããiOSããã³Androidãã©ãããã©ãŒã çšã®åäžã³ãŒãããŒã¹ã§ã¢ããªã±ãŒã·ã§ã³ãå®å
šã«JavaScriptã§èšè¿°ã§ããããã«ãªããŸããã åæã«ãJSã©ã€ãã©ãªãnpmã¢ãžã¥ãŒã«ãããã³Cordovaãã©ã°ã€ã³ãå®å
šã«äœ¿çšã§ããŸãããã ããã¢ããªã±ãŒã·ã§ã³ã«ã¯ãªããããDOMã§åäœããªããã®ã®ã¿ã§ãã
ã¢ããªã±ãŒã·ã§ã³ãã³ã³ãã€ã«ã§ããŸãã
- ç¡æïŒGitHubã®å
¬éãªããžããªãã
- $ 5 /æïŒGitHubã®ãããªãã¯/ãã©ã€ããŒããªããžããªãã
- æé¡50ãã«ïŒGitHub +ããŒã«ã«ãã«ã
ã©ã®æéãã©ã³ã§ããæ©èœã¯åãã§ãã³ãŒãã«ã¯åœ±é¿ããããããžã§ã¯ãã®ã¢ã»ã³ããªã«ã®ã¿åœ±é¿ããŸãã ããŒã«ã«ãã«ãã®éãã¯ããããŸããããã¯ã©ãŠããã«ãã¯åçŽãªã¢ããªã±ãŒã·ã§ã³ã§æ°åããããŸããããã¯äžè¬çã«ã¯æ®éã®ããšã§ãã
äŒæ¥åãã®æéãã©ã³ããããŸãïŒçµç¹ïŒ-äŸ¡æ Œã¯å¹Žé5,000ãã«ããã§ãã ãããã®èšç»ã§ã¯ããœãŒã¹ãååŸãããããæ©èœãå€æŽã§ããŸãã ãµããŒããããŠãããœãŒã¹ã³ãŒãã®æäœã«ã€ããŠè©³ããåŠã¶æ¹ãè¯ãã§ããå
·äœçãªæ
å ±ã¯èŠã€ãããŸããã§ãããã
ãããã質åã§ã¯ç¬èªã®ãã©ã°ã€ã³ã®äœæã«ã€ããŠèª¬æããŠããŸãã
éçºãšãããã°ãé«éåããããã«ã
iOSãŸãã¯
Androidçšã®ã¢ããªã±ãŒã·ã§ã³ã䜿çšã§ããŸãã ãã°ã€ã³ã«ã¯GitHubã䜿çšããŸããã¢ããªã±ãŒã·ã§ã³ã«ã¯ç°¡åãªäŸããªã¢ãŒããµãŒããŒããã¢ããªã±ãŒã·ã§ã³ãå®è¡ããæ©èœïŒããŒã«ã«éçºã«äŸ¿å©ïŒãããã³Tabris Webãµã€ãã®ã¢ã«ãŠã³ãã«è¿œå ãããã¹ã¯ãªããã®åæãå«ãŸããŸãã ããã«ãã¢ããªã±ãŒã·ã§ã³ã«ã¯ãã«ã¡ã©ããã€ã¢ãã°ãããã€ã¹ã¢ãŒã·ã§ã³ãããŒã³ãŒãã¹ãã£ããŒãªã©ãããã€ãã®äŸ¿å©ãªCordovaãã©ã°ã€ã³ãæ¢ã«å«ãŸããŠããŸãã ãããã£ãŠãã€ã³ã¹ããŒã«ãå¿é
ããããšãªãéçºãéå§ã§ããŸã-è¿
éãªéå§ãšæ€èšŒã«æé©ã§ãã
ã¯ããã«
äœããæžãåã«-
ããã¥ã¡ã³ãã«ç²ŸéããŠãã ããã ç§ãã¡ã®äž»ãªé¢å¿ã¯ããã€ãã£ãã«å®è£
ãããã³ã³ããŒãã³ãã§ãããŠã£ãžã§ããã§ãã ã»ãšãã©ã®å Žåãã¡ã€ã³ã³ã³ããŒãã³ãã¯ããŒãžïŒããŒãžïŒã§ãããæ®ãã¯TextViewã§ããããå
éšã«å€ãã®èŠçŽ ãå«ãScrollViewã§ãããã«é¢ä¿ãªããæ®ãã¯æ¢ã«ããã«æ¥ç¶ãããŠããŸãã
ãµã€ããšã¢ããªã±ãŒã·ã§ã³å
ã®äž¡æ¹ã«å€ãã®ããææžåãããäŸãããã®ã§ãåã«ãHello World !!ããšåºåããã®ã¯å¥åŠã§ãã ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ãããå°ãè€éã«ããããå°ãå¹æçã«ããããšã§ãHTML5ããŒã¹ã®ã¢ããªã±ãŒã·ã§ã³ãšã®éããæããããšãã§ããããã«ãªããŸã-Flickrã§ãããªãã¯ã€ã¡ãŒãžãæ€çŽ¢ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®äœæã¯ãæå°éã®
package.jsonããå§ãŸããŸãã
{ "name": "flickr-search", "description": "Search Flickr public images by tag", "main": "app.js", "dependencies": { "tabris": "^1.2.0" } }
Flickr APIã«ãªã¯ãšã¹ããè¡ãå¿
èŠããããŸã
ãTabrisã«ã¯ã«ãŒãã«ã«
XMLHttpRequestãå«ãŸããŠããŸããããã䟿å©ãª
ãã§ããã¢ãžã¥ãŒã«ãæ¥ç¶ããŠPromiseãè¿œå ããããšã§ãäœåãªã³ãŒãè¡ãæšãŠãããšã奜ã¿ãŸãã ãããã£ãŠã
package.jsonã¯æ¬¡ã®åœ¢åŒãåããŸãã
{ "name": "flickr-search", "description": "Search Flickr public images by tag", "main": "app.js", "dependencies": { "tabris": "^1.2.0", "promise": "^6.1.0", "whatwg-fetch": "^0.9.0" } }
ãã®åŸã
npm installãå®è¡ãããšãã³ãŒããäœæããæºåãã»ãŒæŽããŸãã ããã«ããŒã«ã«ãµãŒããŒãäžãããã®ã¢ãã¬ã¹ãTabrisã¢ããªã±ãŒã·ã§ã³ã®URLã¿ãã«å
¥åããããšããå§ãããŸãã ãããã£ãŠãã³ãŒããèšè¿°ãããšããã«ã¢ããªã±ãŒã·ã§ã³ã衚瀺ã§ããŸãã
ããŒãhttp-serverãæ¢ã«ã€ã³ã¹ããŒã«ãããŠããå Žåã¯ããããžã§ã¯ããã©ã«ããŒã§åçŽã«
http-serverãã³ãã³ããããããããžã§ã¯ãã«ããŒã«ã«ã§ã€ã³ã¹ããŒã«ã§ããŸãã ãã¡ãããApacheãªã©ã䜿çšã§ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã¯åäžããŒãžã«ãªããæ€çŽ¢çšã®å
¥åè¡ãå¿
èŠã«ãªããŸãããã®çµæãç»åãšååã衚瀺ãããŸãã å
¥åè¡ã«éåžžã®
TextInputã䜿çšãã
CollectionViewã䜿çšããŠçµæã衚瀺ããŸãã åæåæã«ãã¢ããªã±ãŒã·ã§ã³ã¯Flickrããã®ã©ã³ãã ãªçµæã衚瀺ããŸãïŒã¿ã°ã«ããæ€çŽ¢ãªãïŒããããã£ãŠããŠãŒã¶ãŒãç»åãæŽæ°ã§ããããã«ã
Pull-to-Refreshã³ã³ããŒãã³ãã§
CollectionViewã䜿çšããŸãã
ã¢ãžã¥ãŒã«ãæ¥ç¶ããå¿
èŠãªã¬ã€ã¢ãŠããäœæããŸãã
app.jsã®ã¹ã¯ã©ãã Promise = require("promise"); require("whatwg-fetch"); var page = tabris.create("Page", { title: "Flickr Search", topLevel: true }); var tagInput = tabris.create("TextInput", { layoutData: { left: 8, right: 8, top: 8 }, message: "Search..." }).on("accept", loadItems).appendTo(page); var view = tabris.create("CollectionView", { layoutData: { left: 0, top: [tagInput, 8], right: 0, bottom: 0 }, itemHeight: 200, refreshEnabled: true, initializeCell: function(cell) { var imageView = tabris.create("ImageView", { layoutData: { top: 0, left: 0, right: 0, bottom: 0 }, scaleMode: 'fill' }).appendTo(cell); var titleComposite = tabris.create("Composite", { background: "rgba(0,0,0,0.8)", top: 0, right: 0, left: 0 }).appendTo(cell); var textView = tabris.create("TextView", { layoutData: { left: 30, top: 5, bottom: 5, right: 30 }, alignment: "center", font: "16px Roboto, sans-serif", textColor: "#fff" }).appendTo(titleComposite); cell.on("change:item", function(widget, item) { imageView.set("image", { src: item.media.m }); item.title ? textView.set("text", item.title) : textView.set("text", 'No Title'); }); } }).on("refresh", function() { loadItems(); }).appendTo(page); page.open(); function loadItems() { view.set({ refreshIndicator: true, refreshMessage: "loading..." }); }
ãã¹ãŠãã³ãŒãããéåžžã«ééçã§æ確ã§ã-ããŒãžïŒããŒãžïŒãäœæãããã®ã¿ã€ãã«ãä»ããæ€çŽ¢æååãå
¥åããããã®ããã¹ãå
¥åãè¿œå ããæ€çŽ¢ããŒã®äžã«é
眮ããŠ
CollectionViewãåæåããŸããã
CollectionViewã®åã»ã«ã¯é«ã
ã«èšå®ããã
Imageã³ã³ããŒãã³ãã
Compositeãããã³
TextViewã¬ã€ã€ãŒãã»ã«ã«ãè¿œå ããããŸããã
ImageViewãã»ã«ã®å¹
ãšé«ãå
šäœã«æ¡åŒµãïŒ{leftïŒ0ãrightïŒ0ãtopïŒ0ãbottomïŒ0}ãèšå®ïŒãã³ã³ãããŒããå¡ãã€ã¶ããã¢ãŒãã«èšå®ããŸãïŒ{scaleModeïŒ 'fill'}ïŒã
èæ¯ã«ç»åã®ååã衚瀺ããããã«ãå°ãéæ床ã®ããåæã¬ã€ã€ãŒïŒ{backgroundïŒ "rgbaïŒ0,0,0,0.8.8ïŒ"}ïŒãäœæãããã®ã¬ã€ã€ãŒã«å®éã®ããã¹ããé
眮ããŠãè²ãèšå®ãããµã€ãºãšäžå€®æãã
ãŸãã
å€æŽïŒã¢ã€ãã ãã³ãã©ãŒã§ã空çœãäœæããŠãAPIããã®ããŒã¿ãã»ã«ã«å
¥åããŸããã
loadItemsïŒïŒé¢æ°ã¯ããããŸã§ã«
Pull-to-RefreshèŠçŽ ã®æŽæ°ã€ã³ãžã±ãŒã¿ãŒã衚瀺ããã ããªã®ã§ãã¢ããªã±ãŒã·ã§ã³ãéããŠãã¹ã¯ã€ãããããšæ¬¡ã®ããã«è¡šç€ºãããŸãã
ã¢ããªã±ãŒã·ã§ã³ãã埩掻ããããããã«ãFlickr APIã«ãªã¯ãšã¹ããè¡ããŸãã Flickrã¯ããŸããŸãªåœ¢åŒã§ããŒã¿ãéä¿¡ã§ããç®çã®ã©ã€ãã©ãªã«æ¥ç¶ããŠãå°ãªããšãAtomãã£ãŒããå°ãªããšãCSVã解æã§ããŸããã
ãã ããJSONã䜿çšããæ¹ãã¯ããã«ç°¡åã§ãããäœåãªäŸåé¢ä¿ããã©ãã°ããå¿
èŠã¯ãããŸããã æªããã¥ãŒã¹ã¯ãFlickrãJSON-PãæäŸããŠããããšã§ãã ãã©ãŠã¶ã䜿çšããŠããªããããå®è¡ã®ããã«ã¹ã¯ãªããã<head />ã«æ¿å
¥ããããšã¯ã§ããŸããããŸãã
evalïŒïŒã䜿çšããããšãæé©ãªãªãã·ã§ã³ã§ã¯ãããŸããã
ç¹å®ã®ã±ãŒã¹ã§ã¯ã
evalïŒïŒã䜿çšããããšãã§ããŸã-Flickrãããæªæã®ãããã³ãŒããåãåãå¯èœæ§ã¯äœããå®è¡é床ãèããäœäžããããšã¯ã»ãšãã©ãããŸããïŒããŸããŸãªæé©åãªãã§ã³ãŒãå®è¡ãè¡ãããããšãå¿ããªãã§ãã ããïŒã
ãããã£ãŠã
Functionã³ã³ã¹ãã©ã¯ã¿ãŒã䜿çšããŠé¢æ°ãåçã«äœæããã®ã¯è¯ããã©ãŒã ã§ããããã«æããŸãã倧èŠæš¡ãªãããžã§ã¯ãã§ã¯ãã°ããŒãã«é¢æ°/å€æ°ã
åé€ããããšãã§ãã
try..catchã
ãã©ã¹ããŠãšã©ãŒãåŠçããããšã
ã§ããŸã -ããã«ãããéçºè
ã®ãããã°ãšç掻ãç°¡çŽ åãããŸãå
šäœã ãã®åçŽãªã¢ããªã±ãŒã·ã§ã³ã§ã¯ã
loadItemsïŒïŒé¢æ°ã®åœ¢åŒã¯æ¬¡ã®ãšããã§ãã
function loadItems() { view.set({ refreshIndicator: true, refreshMessage: "loading..." }); fetch("https://api.flickr.com/services/feeds/photos_public.gne?format=json&jsoncallback=JSON_CALLBACK&tags=" + tagInput.get('text')).then(function(response) { var dyn_function = new Function("JSON_CALLBACK", response._bodyInit); dyn_function(function(json) { if (json.items && json.items.length) { view.set({ items: json.items, refreshIndicator: false, refreshMessage: "refreshed" }); } else { navigator.notification.alert('Nothing found with tag: ' + tagInput.get('text'), null, 'Result'); view.set({ refreshIndicator: false, refreshMessage: "refreshed" }); } }) }).catch(function(error) { console.log('request failed:', error) }) }
Tabrisã¢ããªã±ãŒã·ã§ã³ã«ã¯ãã§ã«
org.apache.cordova.dialogsãå«ãŸããŠããããšãããã£ãŠãããããããã§ã¯
navigator.notification.alertïŒïŒã䜿çšããŸãã ãã«ãæã«ã¯ãäŸåãããã©ã°ã€ã³ãè¿œå ããå¿
èŠããããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®åæåäžã«loadItemsïŒïŒãèµ·åãããšã空ã®ãã©ã¡ãŒã¿ãŒã§æ€çŽ¢ãå®è¡ãããã©ã³ãã ãªç»åãååŸãããŸãïŒç©ºã®ã¿ã°ã§æŽæ°ãããã³ã«ïŒã
ã³ã¬ã¯ã·ã§ã³ã®ãã¹ãŠã®èŠçŽ ãã¢ãã¡ãŒã·ã§ã³åããŸãããã HTML5ã§ã®ãã®ãããªïŒç¹ã«ããŒãžã®ã¹ã¯ããŒã«æïŒåäœã¯ããã¹ã ãŒãºãã«ããŸãåäœããŸãããããã¯æãããªéãã§ãã åæã«éæ床ãé«ããªãããå³åŽã«ã·ã³ãã«ãªå€èŠ³å¹æãäœæããŸãã
function animateFadeInFromRight(widget, delay) { widget.set({ opacity: 0.0, transform: { translationX: 150 } }); widget.animate({ opacity: 1.0, transform: { translationX: 0 } }, { duration: 500, delay: delay, easing: "ease-out" }); }
ãããŠã
CollectionViewã»ã«ã«ãšãã§ã¯ããè¿œå ããŸãã
cell.on("change:item", function(widget, item) { animateFadeInFromRight(widget, 500); imageView.set("image", { src: item.media.m }); item.title ? textView.set("text", item.title) : textView.set("text", 'No Title'); });
ããã§ãããããçµäºããŸãïŒ
å®å
šãªãªã¹ãapp.js Promise = require("promise"); require("whatwg-fetch"); var page = tabris.create("Page", { title: "Flickr Search", topLevel: true }); var tagInput = tabris.create("TextInput", { layoutData: { left: 8, right: 8, top: 8 }, message: "Search..." }).on("accept", loadItems).appendTo(page); var view = tabris.create("CollectionView", { layoutData: { left: 0, top: [tagInput, 8], right: 0, bottom: 0 }, itemHeight: 200, refreshEnabled: true, initializeCell: function(cell) { var imageView = tabris.create("ImageView", { layoutData: { top: 0, left: 0, right: 0, bottom: 0 }, scaleMode: 'fill' }).appendTo(cell); var titleComposite = tabris.create("Composite", { background: "rgba(0,0,0,0.8)", top: 0, right: 0, left: 0 }).appendTo(cell); var textView = tabris.create("TextView", { layoutData: { left: 30, top: 5, bottom: 5, right: 30 }, alignment: "center", font: "16px Roboto, sans-serif", textColor: "#fff" }).appendTo(titleComposite); cell.on("change:item", function(widget, item) { animateFadeInFromRight(widget, 500); imageView.set("image", { src: item.media.m }); item.title ? textView.set("text", item.title) : textView.set("text", 'No Title'); }); } }).on("refresh", function() { loadItems(); }).appendTo(page); function loadItems() { view.set({ refreshIndicator: true, refreshMessage: "loading..." }); fetch("https://api.flickr.com/services/feeds/photos_public.gne?format=json&jsoncallback=JSON_CALLBACK&tags=" + tagInput.get('text')).then(function(response) { var dyn_function = new Function("JSON_CALLBACK", response._bodyInit); dyn_function(function(json) { if (json.items && json.items.length) { view.set({ items: json.items, refreshIndicator: false, refreshMessage: "refreshed" }); } else { navigator.notification.alert('Nothing found with tag: ' + tagInput.get('text'), null, 'Result'); view.set({ refreshIndicator: false, refreshMessage: "refreshed" }); } }) }).catch(function(error) { console.log('request failed:', error) }) } function animateFadeInFromRight(widget, delay) { widget.set({ opacity: 0.0, transform: { translationX: 150 } }); widget.animate({ opacity: 1.0, transform: { translationX: 0 } }, { duration: 500, delay: delay, easing: "ease-out" }); } loadItems(); page.open();
ãã«ãã«ã¯ãå
žåçãªCordova
config.xmlãäœæããå¿
èŠããã
ãŸã ãããã§ã¯ãå¿
èŠãªãã©ã°ã€ã³ãç°¡åã«æå®ã§ããŸãïŒã¯ã©ãŠãã³ã¬ã¯ã¿ãŒã¯å¿
èŠãªãã©ã°ã€ã³èªäœãã€ã³ã¹ããŒã«ããnpmã¢ãžã¥ãŒã«ã¯package.jsonããèªã¿åãããŸãïŒã
<?xml version='1.0' encoding='utf-8'?> <widget id="my.flickr_search.app" version="1.0.0"> <name>Flickr Search</name> <description> Search Flickr public images by tag </description> <preference name="Fullscreen" value="true" /> <plugin name="cordova-plugin-dialogs" version="1.1.1" /> </widget>
ãããžã§ã¯ããGithubã«ããã·ã¥ãããªããžããªãéžæããŠTabris管çãšãªã¢ã«ã¢ããªã±ãŒã·ã§ã³ãäœæããåŸïŒ
æ€èšŒåŸããã«ãèšå®ãå©çšå¯èœã«ãªããŸãã
Githubã³ãŒãã¢ããªã±ãŒã·ã§ã³ã®.apkãã¡ã€ã«ã¯çŽ10MBãæ¶è²»ããŸã-裞ã®CordovaïŒçŽ2ã3MBïŒãããå€ããChrome WebViewã䜿çšãããããžã§ã¯ãïŒçŽ19MBïŒãããå°ãªãã§ãã åæã«ããã€ãã£ãã³ã³ããŒãã³ãã§ããçç£çãªã¢ããªã±ãŒã·ã§ã³ã䜿çšã§ããŸãã
å©ç¹ã«ã¯ãéçºé床ãšãå€æ°ã®
js-modulesããã³cordovaãã©ã°ã€ã³ã®ãµããŒããå«ãŸããŸã ã ããšãã°ãReact Nativeã«ã¯ãããŒããŠã§ã¢ãæäœããããã®ãã©ã°ã€ã³ããŸã ã»ãšãã©ãããŸããã Tabrisã¯Cordovaãããžã§ã¯ããšäºææ§ããããããããšãã°å€§ããªãªã¹ãã®å Žåãªã©ãããã«ããã¯ã§äœ¿çšã§ããŸãã
ããŒã«ã«ãã«ãã®å¯èœæ§ã®ããã«50ãã«ãæ¯æããªããã°ãªããªãã®ã¯æ®å¿µã§ããã1ã€ã®ãããžã§ã¯ãã«ã€ããŠè©±ããŠããªãã®ã§ããã°ãããã¯çã«ããªã£ãŠãããšæããŸãã ãã ããã¯ã©ãŠãã§ã¯ãåãæ©èœãåããã¢ããªã±ãŒã·ã§ã³ãç°¡åã«æ§ç¯ã§ããŸãã
Tabrisã³ãã¥ããã£ã¯ããã»ã©çŽ æŽããããã®ã§ã¯ãããŸããããéèŠãããã°æé·ããŸãã
äžè¬ã«ãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ãšã²ãŒã ãéçºããããã®ããªã競äºåã®ãããã¬ãŒã ã¯ãŒã¯ããããåªããããã©ãŒãã³ã¹ãåããŠããŸããããã¯ãå°ãªããšããã¢ããããã¿ã€ããããã«ã¯æ¬æ Œçãªã¢ããªã±ãŒã·ã§ã³ã®éçºã«æšå¥šã§ããŸãã