Jak za jeden týden připravit kompletní aplikaci pro Windows 8 s použitím technologií HTML5, CSS3 a JavaScript – den 3
MyWindows.cz
Jak za jeden týden připravit kompletní aplikaci pro Windows 8 s použitím technologií HTML5, CSS3 a JavaScript – den 3
Na dnešním menu je integrace vaší aplikace do platformy Windows 8 Metro.
Tuto integraci už částečně zajišťuje přichycené zobrazení a možnosti nastavení, ale nyní je načase tento úkol dokončit pomocí:
- Kontrakt Hledání
- Kontrakt Sdílení
- Kontrakt Výběr souboru
- Živá dlaždice
- Sekundární dlaždice
Těchto pět témat je skutečně důležitých pro symbiózu platformy Windows 8 Metro a vaší aplikace.
Předchozí díly samozřejmě najdete zde:
A jako obvykle je kompletní řešení k dispozici zde: http://www.catuhe.com/msdn/urza/day3.zip
Celý projekt byl následně aktualizován pro Release Preview verzi Windows 8 (z Customer Preview), pro kompletní seriál (dny 0 - 4, bude popsáno v dalších článcích), je k dispozici zde: https://mywindows.cz/media/urza/UrzaGatherer.zip
Říkáte „kontrakty“?
Kontrakt (http://msdn.microsoft.com/en-us/library/windows/apps/hh464906.aspx) je definice technického rozhraní mezi vaší aplikací a platformou Windows 8 Metro. Je to rozhodně důležité téma, protože vaší aplikaci poskytuje další vstupní body nad rámec její dlaždice.
Vaše aplikace se pak může zapojit do některých důležitých služeb platformy Windows 8 Metro, jako je například vyhledávání, sdílení dat nebo výběr souborů.
Při vytváření své aplikace nesmíte na podporu kontraktů zapomenout, protože když je opomenete, mohli byste zklamat své uživatele.
Aplikace UrzaGatherer náhodou (!!) může snadno podporovat tři hlavní kontrakty.
Kontrakt Hledání
Kontrakt Hledání umožňuje uživatelům vyhledávat položky ve vaší aplikaci, ale s použitím globálního společného rozhraní:
Jsou zde uvedené všechny aplikace, které podporují kontrakt Hledání (a které uživatel povolil), v pořadí od těch nejčastěji používaných. Jak vidíte, na stejném místě je k dispozicí také vyhledávání aplikací, nastavení a souborů.
Aby systém Windows vaši aplikaci rozpoznal jako poskytovatele hledání, je nutné ji jako takovou deklarovat s použitím manifestu aplikace:
Pro hledání je možné definovat speciální cílovou stránku, ale protože v aplikaci UrzaGatherer potřebuji nejprve načíst data a nechci měnit celou svou architekturu, není nutné speciální stránku poskytovat.
Je pak důležité aktualizovat soubor default.js, aby bylo možné zjistit, zda byla aplikace spuštěna z podokna vyhledávání:
app.onactivated = function (eventObject) { if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch || eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.search ||
Pokud byla aplikace spuštěna z podokna vyhledávání, je nutné uložit text dotazu:
switch (eventObject.detail.kind) { case Windows.ApplicationModel.Activation.ActivationKind.search: UrzaGatherer.QueryText = eventObject.detail.queryText; break;
Je-li definován text dotazu, při načtení stránky home.html je pak možné přejít na stránku vyhledávání (stránka home.html je v tom případě použita pouze pro načtení dat):
if (UrzaGatherer.QueryText) { var queryText = UrzaGatherer.QueryText; delete UrzaGatherer.QueryText; nav.navigate("/pages/search/search.html", { queryText: queryText }); }
Dále je nutné zohlednit skutečnost, že vyhledávání může být zahájeno, když už je vaše aplikace spuštěná. Z toho důvodu je nutné vytvořit naslouchací proces pro speciální událost modulu WinRT:
// Search var searchPane = Windows.ApplicationModel.Search.SearchPane.getForCurrentView(); searchPane.addEventListener("querysubmitted", function (e) { nav.navigate("/pages/search/search.html", { queryText: e.queryText }); }, false);
Jak vidíte, při odeslání požadavku je nutné přejít na stránku vyhledávání (a předat jí text dotazu).
Stránka vyhledávání je klonem stránky rozšíření, ale namísto zobrazení karet rozšíření zobrazuje karty obsahující text dotazu:
Všimněte si, že stránka vyhledávání obsahuje také filtry, které v případě potřeby umožňují vyhledávání upřesnit.
Vaše aplikace také může vyhledávání vylepšit tím, že uživateli při zadávání dotazu poskytne návrhy vyhledávání.
V tom případě je nutné vytvořit naslouchací proces pro další událost:
// Register to Handle Suggestion Request searchPane.addEventListener("suggestionsrequested", function (e) { var query = e.queryText; var maxNumberOfSuggestions = 5; var suggestionRequest = e.request; for (var i = 0, len = UrzaGatherer.Cards.length; i < len; i++) { if (UrzaGatherer.Cards[i].name.substr(0, query.length).toLowerCase() === query) { suggestionRequest.searchSuggestionCollection.appendQuerySuggestion(UrzaGatherer.Cards[i].name); if (suggestionRequest.searchSuggestionCollection.size === maxNumberOfSuggestions) { break; } } } }, false);
Kontrakt Sdílení
Kontrakt Sdílení je opravdu užitečný kontrakt, protože odstraňuje nutnost implementovat klienta pro všechny služby sdílení dat, které chcete podporovat (Facebook, Twitter, e-mail, …).
Pomocí kontraktu Sdílení je možné aplikace definovat jako zdroj nebo cíl sdílení:
Na tomto snímku obrazovky mohu například sdílet svou kartu na Facebooku nebo Twitteru pomocí aplikace FlipToast nebo ji mohu odeslat e-mailem s použitím aplikace Courrier.
Vaše aplikace se nyní může soustředit pouze na svou vlastní činnost.
V případě aplikace UrzaGatherer může každá karta zveřejnit ve službě sdílení dat svůj obrázek. Každý z cílů sdílení se pak může rozhodnout, jak s ním naložit (publikovat ho na Twitteru, odeslat e-mailem apod.), když jej uživatel vybere.
Pro zajištění těchto možností stačí vytvořit naslouchací proces pro událost datarequested ze třídy DataTransferManager:
// Share var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView(); dataTransferManager.addEventListener("datarequested", shareFunction
Je použita následující funkce:
var shareFunction = function (e) { var request = e.request; var deferral = request.getDeferral(); request.data.properties.title = card.name + UrzaGatherer.Tools.GetString("ShareTitle")
+ card.expansion.name; request.data.properties.description = UrzaGatherer.Tools.GetString("ShareDescription"); UrzaGatherer.Tools.GetCardFile(card).then(function (file) { var streamReference = Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(file); request.data.properties.thumbnail = streamReference; request.data.setStorageItems([file]); request.data.setBitmap(streamReference); deferral.complete(); }); };
Ve funkci stačí pouze naplnit požadavek informacemi z karty. Všimněte, že je použita funkce getDeferral, protože tato funkce je asynchronní (což znamená, že proces naplnění není při návratu z funkce ještě dokončen).
Kontrakt Výběr a otevírání souborů
Kontrakt pro výběr souborů umožňuje aplikaci poskytovat soubory jiným aplikacím (aplikace Skydrive například umožňuje uživatelům vybrat soubor v cloudu, jako by se jednalo o místní soubor). Existuje také kontrakt Výběr a ukládání souborů, který umožňuje získávat soubory od jiných aplikací (aplikace Skydrive například umožňuje uživatelům ukládat soubory v cloudu).
V případě aplikace UrzaGatherer můžete pro každou kartu poskytnout obrázek. Počínaje například emailovou aplikací:
Můžete se rozhodnout vybrat obrázek v aplikaci UrzaGatherer a přidat ho jako přílohu:
Protože aplikace UrzaGatherer je poskytovatel souborů, zobrazuje se v seznamu zaregistrovaných poskytovatelů (na stejné úrovni jako SkyDrive). Když ji uživatel vybere, aplikace UrzaGatherer je spuštěna v rámci uživatelského rozhraní systému Windows pro výběr souboru a uživatel může vybrat kartu a získat soubor s jejím obrázkem:
Chcete-li svou aplikaci zaregistrovat jako poskytovatele souborů, můžete postupovat podobně jako v případě kontraktu Hledání:
Z hlediska vašeho kódu je to snadné. Ze všeho nejdříve musíte vzít v úvahu, že aplikace může být spuštěna při výběru souborů:
app.onactivated = function (eventObject) { if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch || eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.search || eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.fileOpenPicker){
Dále je nutné uložit odkaz na uživatelské rozhraní pro výběr souborů, aby bylo možné následně soubory přenést:
switch (eventObject.detail.kind) { case Windows.ApplicationModel.Activation.ActivationKind.fileOpenPicker: UrzaGatherer.FileOpenPickerUI = eventObject.detail.fileOpenPickerUI; break; default:
Když poté uživatel na stránce rozšíření klikne na určitou kartu, namísto přechodu na stránku karty stačí získat příslušný soubor:
itemInvoked: function (eventObject) { if (UrzaGatherer.FileOpenPickerUI) { var item = eventObject.detail.itemPromise.then(function (invokedItem) { var card = invokedItem.data; UrzaGatherer.Tools.GetCardFile(card).then(function (file) { UrzaGatherer.FileOpenPickerUI.addFile(card.name, file); }); }); return; } nav.navigate("/pages/card/card.html", { cardIndex: eventObject.detail.itemIndex, cards: filtered }); },
K získání souboru z karty slouží následující funkce:
var getCardFile = function (card) { // HTTP ? if (card.logo.substring(0, 5).toLowerCase() == "http:") { var uri = new Windows.Foundation.Uri(card.logo); var thumbnail = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(uri); return Windows.Storage.StorageFile.createStreamedFileFromUriAsync(card.name + ".jpg", uri, thumbnail); } // Local ? return Windows.Storage.ApplicationData.current.localFolder.getFileAsync(card.alt); }
Živá dlaždice
Styl Windows 8 Metro je nyní založen na dlaždicích pro spouštění aplikací. Dlaždice je něco jako superikona (http://msdn.microsoft.com/en-us/library/windows/apps/hh779724.aspx), která je dynamická a je možné ji různými způsoby aktualizovat (pomocí aplikace, úlohy na pozadí nebo služby oznámení):
Zaslání aktualizace na dlaždici
Hlavní dlaždice aplikace UrzaGatherer je aktualizována při každém přechodu na stránku karty. Slouží k tomu následující kód:
var updateTile = function (card) { var Notifications = Windows.UI.Notifications; var Imaging = Windows.Graphics.Imaging; var tileXml = Notifications.TileUpdateManager.getTemplateContent( Notifications.TileTemplateType.tileWideSmallImageAndText02); var tileTextAttributes = tileXml.getElementsByTagName("text"); tileTextAttributes[0].appendChild(tileXml.createTextNode("UrzaGatherer")); tileTextAttributes[1].appendChild(tileXml.createTextNode(card.name)); tileTextAttributes[2].appendChild(tileXml.createTextNode(card.expansion.name)); tileTextAttributes[3].appendChild(tileXml.createTextNode(card.expansion.block.name)); var filename = card.alt.replace(".jpg", "_small.png"); rescaleImage(card.logo, 150, 150, filename, true, function (appDatafilename) { // Image var tileImageAttributes = tileXml.getElementsByTagName("image"); tileImageAttributes[0].setAttribute("src", appDatafilename); // Square var squareTileXml = Notifications.TileUpdateManager.getTemplateContent( Notifications.TileTemplateType.tileSquareImage); var squareTileImageAttributes = squareTileXml.getElementsByTagName("image"); squareTileImageAttributes[0].setAttribute("src", appDatafilename); var node = tileXml.importNode(squareTileXml.getElementsByTagName("binding").item(0), true); tileXml.getElementsByTagName("visual").item(0).appendChild(node); // Update var tileNotification = new Notifications.TileNotification(tileXml); tileNotification.tag = card.id; var tileUpdater = Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication(); tileUpdater.enableNotificationQueue(true); tileUpdater.update(tileNotification); }); }
Nejprve je nutné zvolit konfiguraci karty s použitím funkce Notifications.TileUpdateManager.getTemplateContent (http://msdn.microsoft.com/en-us/library/windows/apps/hh761491.aspx).
Tato funkce vrací objekt XML, který je nutné naplnit informacemi pro aktualizaci dlaždice.
Vygenerování nového obrázku pro dlaždici
Jedním z problémů, které jsem musel vyřešit při vytváření kódu pro aktualizaci dlaždice, byla velikost očekávaných obrázků. Musel jsem změnit velikost obrázku tak, aby odpovídala formátu dlaždice. Použil jsem k tomu následující funkci:
var rescaleImage = function (src, destinationWidth, destinationHeight, localfilename, fillAlpha, then) { var Imaging = Windows.Graphics.Imaging; var image = new Image(); // lors du chargement image.addEventListener('load', function () { var canvas = document.createElement('canvas'); canvas.width = destinationWidth; canvas.height = destinationHeight; var targetWidth; var targetHeight; if (this.width > this.height) { var ratio = destinationWidth / this.width; targetWidth = destinationWidth; targetHeight = this.height * ratio; } else { var ratio = destinationHeight / this.height; targetWidth = this.width * ratio; targetHeight = destinationHeight; } var context = canvas.getContext('2d'); if (fillAlpha) context.clearRect(0, 0, canvas.width, canvas.height); else { context.fillStyle = "#fff"; context.fillRect(0, 0, canvas.width, canvas.height); } context.drawImage(this, (canvas.width - targetWidth) / 2, ( canvas.height - targetHeight) / 2, targetWidth, targetHeight); Windows.Storage.ApplicationData.current.localFolder.createFileAsync(localfilename, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) { file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) { Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream).then( function (encoder) { encoder.setPixelData(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, canvas.width, canvas.height, 96, 96, new Uint8Array(context.getImageData(0, 0, canvas.width, canvas.height).data)); encoder.flushAsync().then(function () { stream.flushAsync().then(function () { stream.close(); if (then) then("ms-appdata:///local/" + localfilename.replace("\\", "/")); }); }); }); }); }); }, false); // Chargement image.src = src; }
Pracuje následujícím způsobem:
- Vytvoří obrázek HTML a naslouchací proces pro událost load.
- Jako zdroj obrázku nastaví adresu URL zdrojového obrázku.
- Po
načtení obrázku jej vykreslí v elementu canvas správné velikosti. - Načte pixely elementu canvas pomocí funkce getImageData.
- Vytvoří objekt BitmapEncoder pro vygenerování souboru rastrového obrázku.
- S použitím typovaného pole (Uint8Array) zkopíruje (bez jakéhokoli převodu) pixely elementu canvas do objektu BitmapEncoder s použitím funkce setPixelData.
- Uloží data do souboru, a hotovo!
Postupné zobrazení celé řady aktualizací
Pomocí objektu tileUpdater (prostřednictvím funkce Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication) můžete zaregistrovat aktualizaci své dlaždice.
Můžete dokonce definovat frontu upozornění a vytvořit tak pro svou dlaždici zajímavý cyklický efekt (jakousi frontu FIFO aktualizací).
Pro snížení místa na disku, které tento systém vyžaduje, je nutné ukládat cestu ke všem generovaným obrázků, aby je bylo možné posléze odstranit:
// Store and clean var previousTilesValue = Windows.Storage.ApplicationData.current.localSettings.values["previousTiles"]; var previousTiles = []; if (previousTilesValue) previousTiles = JSON.parse(previousTilesValue); previousTiles.push(filename); if (previousTiles.length > 5) { var toRemove = previousTiles.shift(); Windows.Storage.ApplicationData.current.localFolder.getFileAsync(toRemove).then(function (file) { file.deleteAsync().done(); }); } Windows.Storage.ApplicationData.current.localSettings.values["previousTiles"] = JSON.stringify(previousTiles);
Sekundární dlaždice
Sekundární dlaždice fungují stejně jako hlavní dlaždice, ale poskytují uživatelům možnost vytvořit odkaz na hlubší úroveň v aplikaci. Místo odkazu na kořenovou stránku (default.html) mohou předávat argumenty a odkazovat se na libovolnou část aplikace.
V případě aplikace UrzaGatherer mohou stránky rozšíření vytvářet sekundární dlaždice prostřednictvím svého panelu aplikace (spodního panelu):
Nejdříve je nutné vytvořit panel aplikace:
<!--App bar--> <div data-win-control="WinJS.UI.AppBar" data-win-options=""> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'pinButton',
icon:'pin',section:'global'}"> </button> </div>
Poté je nutné zajistit reakci na kliknutí na tlačítko na panelu aplikace:
var pinByElementAsync = function (then) { var tileID = expansion.id; var shortName = expansion.name; var displayName = expansion.name; var tileOptions = Windows.UI.StartScreen.TileOptions.showNameOnWideLogo; var tileActivationArguments = expansion.id; UrzaGatherer.Tools.RescaleImage(expansion.logo, 150, 150,
expansion.logoPath.replace(".png", "_uri.png"), false, function (uriLogo) { var tile = new Windows.UI.StartScreen.SecondaryTile(tileID, shortName, displayName,
tileActivationArguments, tileOptions, new Windows.Foundation.Uri(uriLogo)); tile.foregroundText = Windows.UI.StartScreen.ForegroundText.dark; UrzaGatherer.Tools.RescaleImage(expansion.logo, 310, 150,
expansion.logoPath.replace(".png", "_wide.png"), false, function (wideLogo) { tile.wideLogo = new Windows.Foundation.Uri(wideLogo); var element = document.getElementById("pinButton"); var selectionRect = element.getBoundingClientRect(); tile.requestCreateAsync({ x: selectionRect.left, y: selectionRect.top }).then(then); }); }); };
Všimněte si opětovného použití funkce RescaleImage pro změnu velikosti loga.
K dlaždici je přidružen argument (tileActivationArguments), který je předán aplikaci, když uživatel na dlaždici klikne.
Tento argument je možné načíst pomocí následujícího kódu:
app.onactivated = function (eventObject) { if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch || eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.search || eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.fileOpenPicker) { switch (eventObject.detail.kind) { case Windows.ApplicationModel.Activation.ActivationKind.search: UrzaGatherer.QueryText = eventObject.detail.queryText; break; case Windows.ApplicationModel.Activation.ActivationKind.fileOpenPicker: UrzaGatherer.FileOpenPickerUI = eventObject.detail.fileOpenPickerUI; break; default: UrzaGatherer.Arguments = eventObject.detail.arguments; break; }
Po načtení stránky home.html můžete zkontrolovat, zda má vlastnost UrzaGatherer.Arguments jinou hodnotu než null a v takovém případě přejít přímo na stránku rozšíření:
if (UrzaGatherer.Arguments) { var expansionID = parseInt(UrzaGatherer.Arguments); delete UrzaGatherer.Arguments; var expansion; for (var index = 0; index < UrzaGatherer.Expansions.length; index++) { var exp = UrzaGatherer.Expansions.getAt(index); if (exp.id == expansionID) { expansion = exp; break; } } nav.navigate("/pages/expansion/expansion.html", { expansion: expansion }); }
Vaše aplikace tak může mít celou řadu přidružených dlaždic na výchozí obrazovce:
Sekundární dlaždice je přirozeně možné aktualizovat stejně jako hlavní dlaždici.
Anglický originál tohoto článku od David Catuhe je dostupný na MSDN.
win8 soutěž win8 vývoj
Navigace v komentářích
načíst novější komentáře ⇒ | přejít na konec →