Mobile Anwendungen für iOS, Android und BlackBerry Touch

Sencha Touch
Kommentare

Auf Basis von Ext JS und HTML 5 hat die Firma Sencha mit Sencha Touch ein Framework auf die Beine gestellt, mit dem sich sehr einfach mobile Anwendungen für touch-fähige Geräte (Smartphones und Tablets) entwickeln lassen. Wie das funktioniert, zeigt Ihnen dieser Artikel.

Für mobile Geräte zu entwickeln, ist nicht leicht. Viele unterschiedliche Displaygrößen und -auflösungen machen Designern und Entwicklern das Leben schwer. Das wäre an sich nicht so dramatisch, wären die Displays nur nicht so klein. Umso mehr bietet sich deswegen hier die Verwendung eines Frameworks an. Sencha Touch ist dabei etwa neben jQuery Mobile eine Möglichkeit, solche Anwendungen zu entwickeln, beschränkt sich dabei aber, wie der Name schon sagt, auf Geräte mit Touchscreens. Prinzipiell sind die Anwendungen auf allen Browsern mit WebKit-Basis lauffähig; für die volle User Experience sollten es dann aber schon iPhones, Android-Phones oder Tablets sein, auch BlackBerrys Touch-Geräte werden mittlerweile (seit Version 1.1.0) unterstützt. Da die Browser von iOS, Android und neuerdings auch BlackBerry auf WebKit basieren, ist es relativ einfach, Sencha-Touch-Anwendungen ohne ständige Verwendung eines mobilen Gerätes zu entwickeln, indem man z. B. einfach Google Chrome oder Safari verwendet, die auch beide nativ die notwendigen Entwicklertools besitzen. Lediglich zum Anpassen der Browsergröße an mobile Geräte empfiehlt es sich, Add-ons wie Resizer (Safari) bzw. Window Resizer (Chrome) zu verwenden. Für die Entwicklung unerlässlich ist die API-Dokumentation. Obwohl Sencha Touch bereits die Version 1.0 erreicht hat, ist sie leider (immer noch) stellenweise unvollständig oder fehlerhaft. Bei Bedarf sollte daher die Ext-JS-API-Dokumentation verwendet werden. Die Beispielanwendung, die ich im Laufe dieses Artikels aufbauen werde, basiert auf Datensätzen der Film-Community Score11. Die vollständigen Quelltexte sowie Sencha Touch 1.1.0 finden Sie, wie gewohnt, auf der Heft-CD. Um die Anwendung zu testen, kopieren Sie sie auf Ihren Rechner und entpacken die Sencha-Touch-Library in den Ordner js/senchatouch/ (sodass die Dateisencha-touch.js direkt im Root von js/senchatouch liegt). Zum Ausführen öffnen Sie einfach die Datei index.html. Eine Internetverbindung wird benötigt, da Daten vom Score11-Server nachgeladen werden. Zuletzt noch der Hinweis, dass es von großer Hilfe für das Verständnis dieses Artikels ist, wenn Sie zumindest grob verstanden haben, wie Vererbung von Klassen in Ext gehandhabt wird. Lesen Sie sich dafür am besten die Anleitung von Sencha selber durch . Diese ist zwar für Ext JS verfasst, die Vererbung funktioniert in Sencha Touch jedoch vollkommen identisch.

Testgeräte organisieren

Da es eine schier unüberschaubare Anzahl an Geräten gibt, wird es womöglich problematisch und teuer, alle Geräte auf Vorrat zu halten. Zum Glück gibt es hierfür aber günstige und sogar kostenlose Varianten: Statt einem iPhone können Sie auch einfach einen iPod touch verwenden. Haben sie kein Android-Gerät zur Hand, wird es sogar noch einfacher: Das kostenlose Android SDK (erhältlich für Linux, Mac und Windows) wird mit einem Emulator ausgeliefert, den Sie sowohl mit unterschiedlichen Android-Versionen als auch unterschiedlichen Auflösungen starten können. Was Sie tun müssen, um diesen in Betrieb zu nehmen, können Sie hier nachlesen. Alternativen für BlackBerry Touch sind mir leider nicht bekannt.

Das Grundgerüst

Ähnlich wie bei Ext JS braucht man nicht viel, um loslegen zu können: Grundlage ist ein leeres HTML-Dokument mit dem Include einer JavaScript- und einer CSS-Datei (Listing 1). Die Applikation selbst wird in JavaScript geschrieben, auf reines HTML werden Sie eher selten zurückgreifen müssen. Auf der Heft-CD finden Sie den kompletten (und eben doch recht kurzen) Quelltext in der Datei index.html. Listing 1 lädt die Debug-Variante der Sencha-Touch-Bibliothek, für den Livebetrieb sollte sinnvollerweise die Non-Debug-Variante sencha-touch.js geladen werden. Für das Stylesheet gibt es mit sencha-touch-debug.css übrigens ebenfalls eine Debug-Variante, erfahrungsgemäß brauchen Sie diese aber eher seltener. Um das visuelle Grundgerüst für eine Sencha-Touch-Anwendung zu erstellen, benötigen wir einfach ein beliebiges Panel mit der Configoption fullscreen: true. Je nach Anwendung kann das ein normales Panel, ein FormPanel (für Formulare) oder, wie in unserem Fall, ein TabPanel sein. TabPanels verwalten – wie bei Ext JS – mehrere Panels über Tabs getrennt. Über die ConfigoptiontabBar legen sie zusätzlich noch fest, wo die Tabs angezeigt werden sollen (dock), sowie die vertikale Positionierung der Tabs (layout). Wird tabBar nicht festgelegt, so werden die Tabs standardmäßig oben und linksbündig positioniert. Um das Look & Feel von üblichen Smartphone-Apps zu verwenden, bietet es sich an, die Tabs unten zu positionieren. Wie ein solches TabPanel geschrieben wird, sehen Sie in Listing 2, den vollständigen Quelltext finden Sie in der Datei js/lib/MainWindow.js. Hat man das Panel festgelegt, muss man es nur noch erstellen. Um Probleme zu vermeiden, erstellt man es idealerweise erst, wenn der DOM zur Verfügung steht. Wie Sie das mit Hilfe vonExt.setup erreichen, sehen Sie in Listing 3. Ext.setup hat übrigens auch noch weitere nützliche Parameter, die Sie am besten der API-Dokumentation [2] entnehmen. Wie die fertig konfigurierte Beispielanwendung dieses Artikels aussieht, zeigt Ihnen Abbildung 1.
Score11.Mobile.MainWindow = Ext.extend(Ext.TabPanel, {
fullscreen: true,
layout: 'card',
tabBar: {
dock: 'bottom',
layout: {
pack: 'center'
}
}
});
Ext.setup({
onReady: function() {
window.score11Mobile = new Score11.Mobile.MainWindow();
window.score11Mobile.show();
}
});
Abb. 1: Unsere komplett konfigurierte Sencha-Touch-Anwendung

Abb. 1: Unsere komplett konfigurierte Sencha-Touch-Anwendung

Einrichten der Panels

Die beschrifteten Icons (Home, Bookmarks, Detailansicht), die Sie im unteren Bereich von Abbildung 1 sehen, ist die eben erwähnte TabBar. Die Beschriftung und das Icon sind jeweils Eigenschaften der konfigurierten Panels (Configoptionen title und iconCls). Für die Icons liefert Sencha Touch bereits eine Vielzahl nützlicher Icons, die Sie über iconCls: bookmarks nutzen können. Eine vollständige Liste finden Sie z.B. in der generell sehr hilfreichen Kitchen-Sink-Demo. Wie die Definition des Home-Panels mit Titel und Icon aussieht, zeigt Listing 4. Den kompletten Quelltext finden Sie in der Datei js/lib/Home.js.
Score11.Mobile.Home = Ext.extend(Ext.form.FormPanel, {
iconCls: 'home',
title: 'Home'
});
Listen
Wie Sie in Abbildung 1 bereits sehen können, wird auf der Startseite eine Liste mit Filmtiteln angezeigt. Diese Listen sind in mobilen Apps und Anwendungen recht geläufig und können in Sencha Touch sehr einfach erstellt werden. Seit Version 1.1.0 bietet Sencha Touch zudem auch noch zwei sehr nützliche Plug-ins für die Listen: Paging und PullRefresh. Wie Sie solche Listen erstellen und wofür die Plug-ins gut sind, sollen Sie als Nächstes erfahren. Prinzipiell besteht so eine Liste aus zwei Komponenten: der Liste selber und einem Store, also einer Komponente, welche die Daten lädt und bereitstellt. In der Beispielanwendung erstelle ich erst einmal den Store, der anschließend beim Erstellen des Home-Panels als Argument mitgegeben wurde. Somit kann die Liste an anderer Stelle problemlos mit einem anderen Store verwendet werden. Ein Store benötigt an sich nur zwei Configoptionen, um lauffähig zu sein: Model und Proxy. Das Model gibt die Struktur der Daten an, der Proxy kümmert sich um die Beschaffung und Bereitstellung der Daten (das wird meistens ein AJAX-Proxy sein, kann aber auch Memory für lokal gespeicherte Daten, Script-Tag u.v.a. sein). Ebenfalls im Proxy wird der Reader definiert, der entsprechend dem Datenformat konfiguriert sein muss. In unserem Fall haben wir in der Liste im Home-Panel einen Script-Tag-Proxy (theoretisch wäre es ein AJAX-Proxy, aufgrund der Same Origin Policy von XHR musste ich allerdings auf den Script-Tag-Proxy zurückgreifen) mit einem JSON-Reader, die Daten liegen in etwa folgendem Format vor: {movies: [{„movieID“:“48054″,“title“:“Merlin – Vergifteter Kelch“,“year“:“2008″},{…}, total: 5}. Für den Script-Tag-Proxy bedurfte es einer minimalen Änderung aufgrund der Implementation des Proxies, Genaueres dazu finden Sie in der Sencha Touch-API-Dokumentation. Da wir später in der Anwendung zwei Stores haben werden, die dasselbe Model verwenden, habe ich noch eine Abstraktionsebene eingezogen. Wie ein Store dafür aussehen würde, sehen Sie in Listing 5.1 und Listing 5.2, auf der Heft-CD finden Sie den vollständigen Store in den Dateien js/store/RemoteMovieList.js und js/store/AbstractMovieList.js. Eine kleine Anmerkung noch zur Funktionalität: Das angegebene PHP-Script liefert immer 25 zufällige Filmtitel.
Ext.ns('Score11.Mobile.Store');

Score11.Mobile.Store.AbstractMovieList = Ext.extend(Ext.data.Store, {
modelName: 'Movielist',
pageSize: 25,
clearOnPageLoad: false,
constructor: function(passedConfig) {
if (!passedConfig) {
passedConfig = {};
}
this.createStoreModel();
config = this.getDefaultConfig();
Ext.apply(config, passedConfig);
Score11.Mobile.Store.AbstractMovieList.superclass.constructor.call(this, config);
},
createStoreModel: function() {
// Nichts machen, falls das Model bereits registriert wurde
if(Ext.ModelMgr.isRegistered(this.modelName)) {
return false;
}
Ext.regModel(this.modelName, {
fields: [
{name: 'movieID', type: 'int'},
{name: 'title', type: 'string'},
{name: 'year', type: 'int'}
]
});
return true;
}
});
Ext.ns('Score11.Mobile.Store');

Score11.Mobile.Store.RemoteMovieList = Ext.extend(Score11.Mobile.Store.AbstractMovieList, {
getDefaultConfig: function() {
return {
model: this.modelName,
autoLoad: true,
proxy: {
type: 'scripttag',
url: 'http: //www.score11.de/germanTitles.php',
reader: {
type: 'json'
}
}
};
}
});
Falls Sie bereits Erfahrung mit Ext JS gemacht haben, wird Ihnen sicherlich aufgefallen sein, dass das Model nicht, wie in Ext JS, per fields-Attribut im Store gesetzt wird, sondern dass hier ein Model-Manager verwendet wird, in dem das Model nur einmal definiert werden muss und dem Store nur noch der Modelname mitgeteilt wird. Für einmalige Models ist das sicherlich minimal mehr Tipparbeit, für den (gar nicht so unwahrscheinlichen Fall) identischer Models innerhalb der Applikation ist das aber schon ziemlich nützlich. Nun, da wir den Store für die Liste fertig konfiguriert haben, können wir die Liste selber erstellen. Wie beim Store ginge auch das mit nur zwei Configoptionen (store und itemTpl). Da unsere Liste aber auch scrollbar sein soll, ist es nur mit den zwei Optionen nicht getan. Das Attribut itemTpl definiert, welche Informationen aus dem Store (definiert im Model) als Anzeige verwendet werden sollen. Variablen aus dem Store werden mit {} umklammert, Kombinationen wie {year} – {title} (Film) sind also problemlos möglich. Wie die Liste mit dem Store aus Listing 5.1 und 5.2 aussieht, zeigt Listing 6.
this.list = new Ext.List({
height: '100%',
scroll: 'vertical',
itemTpl: '{title}',
store: this.movieStore
});

Plug-ins für Listen

Seit Sencha Touch 1.1.0 gibt es zwei Plug-ins für Listen: PullToRefresh und Paging. Ersteres fügt der Liste eine Funktionalität hinzu, durch die sie neu geladen wird, wenn man sie weit genug nach oben zieht, ähnlich wie man es etwa von der Facebook- und Twitter-App für das iPhone kennt. Das Paging-Plug-in wiederum erweitert die Liste um (wie der Name bereits verrät) Paging. Standardmäßig wird dann einfach am Ende der Liste ein „Load More …“ ausgegeben, das beim Antippen die nächste Seite lädt (genauer wird eine Ladeoperation auf den Store getriggert, die die Parameter start und limit mit übermittelt – das Limit haben wir bereits vorher im Store mit dem Attribut pageSize festgelegt, siehe Listing 5.1). Das Paging-Plug-in ermöglicht es aber auch die nächste Seite automatisch zu laden, sobald man weit genug heruntergescrollt hat. Dazu muss man das Plug-in lediglich mit autoPaging: true konfigurieren. Erwähnt sei zudem noch, dass das Paging standardmäßig den Store jedes Mal leert und dann die neue Seite anzeigt. Möchte man eine fortlaufende Liste, muss man den Store mit clearOnPageLoad: false konfigurieren, was in Listing 5.1 bereits geschehen ist. Dann wird der Store nur noch beim PullToRefresh geleert. Beim Laden einer neuer Seite werden die Elemente unten angehängt. Um die Plug-ins nun der Liste zu übergeben, müssen wir sie in der Configoption plugins übergeben. Wie die Listendefinition dadurch aussieht, zeigt Listing 7, wie das PullToRefresh-Plug-in in Aktion aussieht, sehen Sie in Abbildung 2, das Paging-Plug-in in Abbildung 3.
this.list = new Ext.List({
height: '100%',
scroll: 'vertical',
itemTpl: '{title}',
store: this.movieStore
});
Abb. 2: Das PullToRefresh-Plug-in in Aktion

Abb. 2: Das PullToRefresh-Plug-in in Aktion

 
Abb. 3: Das Paging-Plug-in in Aktion

Abb. 3: Das Paging-Plug-in in Aktion

Gruppierte Listen

Bevor wir nun Verhalten für die Filmliste definieren, benötigen wir erst noch die Bookmarks-Liste. Ziel ist es, Filme von der Liste bookmarken zu können und dadurch – technisch gesehen – Datensätze von einem Store in den anderen zu kopieren. Die Store-Definition spare ich mir aus Platzgründen an dieser Stelle (Sie finden sie in den Dateien js/store/LocalMovieList.js undjs/store/AbstractMovieList.js – hier ist also der vorhin erwähnte zweite Store), interessanter wird es bei der Liste: Diese ist nämlich alphabetisch gruppiert und zeigt außerdem einen Buchstabenindex an (Abbildung 4).
Abb. 4: Die fertig konfigurierte Bookmarks-Liste

Abb. 4: Die fertig konfigurierte Bookmarks-Liste

  Um die Gruppierung für die Liste zu aktivieren, muss man einerseits die Liste mit grouped: true konfigurieren und andererseits im jeweiligen Store die Methode getGroupString implementieren, in der man den Teil aus dem (als Parameter übergebenen) Datensatz extrahieren muss, nach dem gruppiert werden soll (in unserem Fall ist das einfach nur der erste Buchstabe des Filmtitels). Den Buchstabenindex aktivieren Sie zunächst, indem sie die Liste einfach mit indexBar: true konfigurieren. Es gibt zudem aber auch die Möglichkeit, ein Objekt zu übergeben, indem man den Buchstabenindex genauer konfigurieren kann, etwa an welcher Stelle er angedockt werden soll (links oder rechts), ob er vertikal oder horizontal verlaufen oder ob ein Zeichen vorangestellt werden soll (z.B. #, falls die Liste auch numerische Einträge enthält). Die konfigurierte Liste sehen Sie in Listing 8, die Methode getGroupString des Stores finden Sie aus Platzgründen auf der Heft-CD in der Datei js/lib/AbstractMovieList.js.
this.list = new Ext.List({
height: '100%',
scroll: 'vertical',
grouped: true,
indexBar: {
dock: 'right',
listPrefix: '#'
},
itemTpl: '{title}',
store: this.movieStore
});

Filme bookmarken

Jetzt, da beide Listen fertig konfiguriert sind, soll als Nächstes die Bookmark-Funktionalität implementiert werden. Hierfür müssen also die beiden Panels irgendwie miteinander agieren: Dafür müssen wir über das anfangs definierte TabPanel Score11.Mobile.MainWindow gehen, da dort beide Panels im selben Scope definiert wurden und wir sie daher miteinander agieren lassen können. Angefangen bei der Liste des Home-Panels müssen wir zunächst einmal abfangen, wenn ein Film angetippt wird. Hierbei feuert die Liste praktischerweise das Event itemtap. Da sich die Liste aber im Panel befindet, sind wir noch eine Ebene zu tief. Um das Event weiter nach oben durchzureichen, müssen wir dem Home-Panel als Erstes sagen, dass es jetzt ebenfalls Events des Typs itemtap feuern kann, das erledigen wir über die Methode addEvents(). Anschließend müssen wir nur noch das Event itemtap auf der Liste abfangen und entsprechend weiterleiten. Wie daraufhin das Panel, das wir ursprünglich in Listing 4 definiert haben, aussieht, sehen Sie in Listing 9.
Score11.Mobile.Home = Ext.extend(Ext.Panel, {
iconCls: 'home',
title: 'Home',
movieStore: null,
constructor: function(config) {
this.addEvents('itemtap');
Score11.Mobile.Home.superclass.constructor.call(this, config);
},
initComponent: function() {
this.list = new Ext.List({
height: '100%',
scroll: 'vertical',
itemTpl: '{title}',
store: this.movieStore,
listeners: {
itemtap: Ext.createDelegate(function(list, index, item, event) {
this.fireEvent('itemtap', list, index, item, event);
}, this)
},
plugins: [
new Ext.plugins.ListPagingPlugin({
autoPaging: true
}),
new Ext.plugins.PullRefreshPlugin()
]
});
}
});
Mit Ext.createDelegate() teilen wir dem Event Callback mit, dass es im Kontext des aktuellen Objekts ausgeführt werden soll. Selbstverständlich lassen sich Event Listener auch wie bei Ext JS über die on()-Methode registrieren, ein Beispiel dazu sehen Sie gleich. Nachdem das Event nun nach oben durchgereicht wurde, lässt es sich im MainWindow abfangen und dem User kann eine Abfrage angezeigt werden, ob er den Film bookmarken möchte oder nicht. Dafür eignet sich hervorragend ein sog. ActionSheet, welches Sie in Abbildung 5 sehen können.
Abb. 5: ActionSheet

Abb. 5: ActionSheet

  An sich kann man beliebige Komponenten in ein ActionSheet packen, am besten eignet es sich aber für Buttons. Ähnlich wie die iconCls bei den Panels gibt es über die ui-Configoption die Möglichkeit, Buttons zu stylen; in der Regel bedeutet das nur, wie das Format des Buttons aussieht (abgerundet, mit einer spitzen Seite etc.) und welche Farben es verwendet. Die vollständige Liste der Möglichkeiten für ui finden Sie, wie die Icons für iconCls, in der Kitchen-Sink-Demo und den Code für das in Abbildung 5 angezeigte ActionSheet in Listing 10.
Ext.ns('Score11.Mobile');

Score11.Mobile.BookmarkMovieActionSheet = Ext.extend(Ext.ActionSheet, {
initComponent: function() {
this.addEvents('bookmarkmovie');

this.deleteMovie = new Ext.Button({
text: 'Film bookmarken',
ui: 'confirm',
// Callback, wenn der User den Button anklickt
handler: function(button) {
// User informieren, dass der Bookmark hinzugefuegt wurde
Ext.Msg.alert(
'Bookmark',
'Der Bookmark wurde hinzugefügt.'
);
this.fireEvent('bookmarkmovie');
this.hide();
},
// Scope, in welchem der handler() Callback aufgerufen wird
scope: this
});

this.cancelRemoval = new Ext.Button({
text: 'Abbrechen',
ui: 'decline',
handler: function(button) {
this.hide();
},
scope: this
});

Ext.apply(this, {
items: [
this.deleteMovie,
this.cancelRemoval
]
});

Score11.Mobile.BookmarkMovieActionSheet.superclass.initComponent.apply(this, arguments);
}
});
Wie Sie dem Listing sicherlich entnehmen konnten, wird auch hier wieder ein Event (bookmarkmovie) gefeuert, sobald sich der User dazu entschlossen hat, den Film zu bookmarken. Das können wir wieder im MainWindow abfangen und eine entsprechende Aktion durchführen. In dem Fall lautet die Aktion: Bookmark speichern, Meldung ausgeben und den BadgeText der Bookmarks aktualisieren. Der BadgeText ist die Anzeige, dass sich in einem Objekt etwas geändert hat – meistens handelt es sich dabei um eine Zahl. IPhone-User kennen etwa die rot eingekreiste Zahl auf der Mail-Applikation bei neuen E-Mails. Den BadgeText bei einem Panel können Sie über panel.tab.setBadge(text) setzen. Die in Listing 11 verwendete increaseBadge-Methode habe ich selber dem Bookmarks-Panel hinzugefügt und behandle dort die automatische Erhöhung des BadgeTextes um 1 – setBadge nimmt nämlich auch Text an. Wie so ein BadgeText aussieht, zeigt Abbildung 6, die increaseBadge-Methode finden Sie in der Datei js/lib/Bookmarks.js.
/**
* list : Die Filmliste des Home Panels
* localMovieStore : Der Store, der mit den Bookmarks verknuepft ist
*/
this.homePanel.on('itemtap', function(list, index, item, event) {
var actionSheet = new Score11.Mobile.BookmarkMovieActionSheet();

actionSheet.on('bookmarkmovie', function() {
var movie = list.getStore().getAt(index);
localMovieStore.add(movie.data);
// Liste neu sortieren, sonst ist das neue Element immer am Ende der Liste
localMovieStore.sort();
// Originaleintrag deselecten
list.deselect(movie);
// Badge der Bookmarks um 1 erhoehen
this.bookmarksPanel.increaseBadge();
}, this);

actionSheet.show();
}, this);
Abb. 6: Bookmarks-Icon mit BadgeText

Abb. 6: Bookmarks-Icon mit BadgeText

Formular mit Suche

Sicherlich ist Ihnen in Abbildung 4 die Lupe oben links aufgefallen. Dahinter versteckt sich eine recht rudimentäre Suchfunktion, mit der man die Bookmarks durchsuchen kann. Zuerst wird bei Klick auf die Lupe eine Suchmaske geöffnet, die im Bookmark-Panel als Toolbar definiert wurde (dockedItems). In dieser kann der User anschließend Text eingeben und die Bookmarks filtern (Abbildung 7). Prinzipiell ist das einfach; damit aber wie in Abbildung 7 unten rechts „Suchen“ angezeigt wird, muss man drei Dinge beachten:
  1. Das Textfeld muss ein Suchfeld sein (Ext.form.Search).
  2. Das Suchfeld muss sich in einem Formular befinden (Ext.form.FormPanel).
  3. Das Formular sollte idealerweise nicht das Standardverhalten beibehalten (Formular als normalen HTTP Request absenden).
Punkt eins und zwei sollten an sich selbsterklärend sein, Punkt drei lässt sich ganz einfach umsetzen, indem man das FormPanel mit dem Attribut submitOnAction: false konfiguriert.
Abb. 7: Suche richtig konfiguriert – die Suche muss nur noch manuell getriggert werden.

Abb. 7: Suche richtig konfiguriert – die Suche muss nur noch manuell getriggert werden.

  Wie Sie die Suchtoolbar im Panel als Toolbar für oben definieren, sehen Sie in verkürzter Form in den Listings 12.1 und 12.2, auf der Heft-CD finden Sie dies vollständig in den Dateienjs/lib/Bookmarks.js und js/lib/BookmarksSearchToolbar.js. Die Leiste, in der Score11 steht, die Sie bisher auf jedem Screenshot gesehen haben, ist ebenfalls eine solche Toolbar, die im MainWindow definiert wurde. Die in der Beispielanwendung implementierte Suche macht schlussendlich nichts anderes, als die Methode filter() auf dem entsprechenden Store auszuführen. Den Code dazu finden Sie ebenfalls in der Datei js/lib/BookmarksSearchToolbar.js.
Ext.ns('Score11.Mobile');

Score11.Mobile.BookmarksSearchToolbar = Ext.extend(Ext.Toolbar, {
dock: 'top',
ui: 'light',
initComponent: function() {
var searchField = new Ext.form.Search({
// Wird angezeigt, solange nichts eingegeben wurde
placeHolder: 'Film suchen',
name: 'searchfield'
});
}
});
Score11.Mobile.Bookmarks = Ext.extend(Ext.form.FormPanel, {
iconCls: 'bookmarks',
title: 'Bookmarks',
initComponent: function() {
this.searchToolbar = new Score11.Mobile.BookmarksSearchToolbar() ;
Ext.apply(this, {
dockedItems: [
this.searchToolbar
]
});
}
});

Detailansicht

Die Detailansicht implementiert hauptsächlich viele bereits gezeigte Funktionen, ich werde daher nicht weiter auf sie eingehen. Werfen Sie bei Interesse einfach einen Blick in die Dateijs/lib/DetailView.js.

Alles dreht sich

Als Letztes möchte ich Ihnen noch zeigen, wie Sie das Drehen des Gerätes durch den Benutzer abfangen können. Sencha Touch bietet hierfür das Event orientationchange. Da das Feuern dieses Events recht weit oben in der Vererbungskette, nämlich in Ext.Component, implementiert ist, lässt sich für jede visuelle Komponente eine Orientierungsänderung abfangen. Wie das mitsamt Auslesen der Orientierung (portrait oder landscape) beispielhaft funktioniert, sehen Sie in Listing 13, das Ergebnis davon zeigt Abbildung 8. Die tatsächliche Implementierung für orientationchangein der Beispielanwendung finden Sie in der Datei js/lib/MainWindow.js.
Ext.apply(this, {
listeners: {
orientationchange: function(component, orientation, width, height) {
if (orientation == 'landscape') {
Ext.Msg.alert(
'Ausrichtung geändert',
'Diese Anwendung funktioniert hochkant am besten.'
);
}
}
});
Abb. 8: Abfangen, wenn der User sein Gerät quer hält

Abb. 8: Abfangen, wenn der User sein Gerät quer hält

 

Das war erst der Anfang

Trotz des Umfangs konnte dieser Artikel nur einen Bruchteil der Möglichkeiten von Sencha Touch aufzeigen. Überzeugen Sie sich am besten selber von der Fülle an Möglichkeiten anhand der Kitchen-Sink-Demo. Aktuell hat Sencha Touch zwar bereits den Milestone 1.0 überschritten, einige Features funktionieren aber dennoch nur auf bestimmten Geräten. Man darf davon ausgehen, dass sich das im Laufe der Zeit ändert.
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -