Comparatif ionic / Kivy – match retour

Introduction

Suite à l’article visant à comparer ionic et Kyvi, je suis allé plus loin dans la création d’une application mobile avec ionic (ben oui, je lui ai donné une bonne note, alors j’ai creusé !). Finalement, je vais pouvoir appuyer mes propos sur des exemples concrets, en faisant une deuxième copie d’une application Kivy, mais avec ionic (écrans proches et fonctionnalités similaires).

Pour rappel, le framework ionic part d’une bonne base : utiliser les connaissances d’un développeur web pour faire des applications mobiles. Il s’avère que (à mon avis) Kivy s’en sort mieux, même avec ses points faibles. Voici les notes du match retour, sur 20.

 

Comparatif de l’installation

Notes du match aller : Kivy 18/20 ; ionic : 15/20

Après plusieurs applications créées avec ionic, ces notes ne changent pas. La documentation des débutants servira pour les prochains développements. Je trouve relativement dommage que les fichiers de configuration des plates-formes soient avec le projet. On n’est plus dans le crossplatform (ou « platform independant ») dès le début, mais on va s’arranger avec les plates-formes cibles.

Verdict : Kivy 18/20 ; ionic : 15/20

 

Editeur de code (ou IDE)

Notes du match aller : 18/20 pour les deux

Même avec Eclipse et des plugins (JS, HTML, CSS), je n’ai pas réussi à configurer rapidement l’IDE sur un projet ionic pour me faire gagner plus de temps qu’un simple éditeur de texte avec coloration syntaxique (genre Notepad++). Les recherches de dépendances (F3, CRTL-Clic) ne fonctionnent pas, c’est la cata. Heureusement que les applications sont simples.

Avec Eclipse, les classes Phyton sont reconnues et facilement retrouvées. Il ne manque que l’interprétation du langage kv pour avoir un 20/20.

Verdict : Kivy 18/20 ; ionic : 10/20

 

Documentation et exemples

Notes du match aller : 18/20 pour les deux

Après quelques écueils, je doit reconnaître que la documentation ionic (cordova et ses copains) ne sont pas si facilement applicables. Des exemples et explications sont disponibles, mais il faut mettre la frontale. De longues recherches et tests sont nécessaires pour investiguer sur un terrain inconnu. Gare aux culs de sac.

Verdict : Kivy 18/20 ; ionic : 15/20

 

Le premier « Hello world »

Notes du match aller : Kivy 18/20 ; ionic : 15/20

Attention, si on part avec de mauvaises bases et structuration du code, ca devient vite un gros bordel. Le framework ne cadre pas du tout les composants (Services, Factory, Modèles, etc) : tout peut être dans un seul fichier de 600 ko de code. Pour débuter avec une première application, ces bases sont presque obligatoires (par exemple avec CodeIgniter en PHP, qui est un régal à comparer d’ionic). Je trouve dommage que les exemples « clé en main » soient dépourvus de cette structuration.

Kivy propose plus de contrainte, car il se base sur Python qui défini déjà des packages et des modules (ce qui doit aider grandement Eclipse à retrouver les sources des classes).

Verdict : Kivy 18/20 ; ionic : 12/20

 

Développement d’une application sur un PC

Notes du match aller : Kivy 18/20 ; ionic : 12/20

Pour ce cas, je pense avoir plutôt bien jugé mes notes. Le développement est relativement laborieux avec ionic. Heureusement qu’avec un plugin pour Chrome, on arrive à avoir un rendu potable et avancer dans la création des applications. Les logs sont dans la console Javascript du navigateur, mais il n’y a pas tout. Comparé à Kivy, où tout sort dans la console d’Eclipse, c’est bien moins confortable.

Verdict : Kivy 18/20 ; ionic : 12/20

 

Déploiement sur mobile (Android)

Notes du match aller : 18/20 pour les deux

Avec ionic, on peut profiter du live-reload pour pallier aux problèmes d’utilisation des ressources présentes uniquement sur le device (ex: Base de données SQLite). Le déploiement est facile pour les deux frameworks, même avec une structuration complexe et des fichiers divers.

Verdict : 18/20 pour les deux

 

Développements sans appels au device

Notes du match aller : 18/20 pour les deux

Les développements ionic nécessitent une « boite » simulant le mobile. C’est faisable avec un navigateur comme Chromium et un plugin ;  c’est un peu bricolé. Avec Kivy, c’est une vraie fenêtre de l’OS qui s’ouvre.

Verdict : Kivy 18/20 ; ionic : 15/20

 

Appels aux fonctionnalités du device

Notes du match aller : Kivy 12/20 ; ionic : 18/20

Le désenchantement d’ionic continue lors de développements faisant appel au fonctionnalités du device (GPS, Base de données, caméra, etc.). Il n’est plus possible de se passer d’un device et de tout tester sur le mobile. On arrive aux limites de la magie du crossplatform. Il en fallait bien quelques unes, ce n’est pas du code natif et il n’y a pas de façade pour s’en abstraire (ca commence à arriver sur Kivy).

Verdict : Kivy 12/20 ; ionic : 12/20

 

Design et interface

Notes du match aller : Kivy 4/20 ; ionic : 18/20

Sauf nouveauté coté Kivy, ionic reste très pratique pour les interfaces nécessitant un design très travaillé.

Avec des widgets prédéfinis et réutilisables (et paramétrables), Kivy sort quand même la tête hors de l’eau, sans avoir de solution miracle. Il faut donc prévoir de faire des interfaces simples avec Kivy…

Verdict : Kivy 8/20 ; ionic : 18/20

 

Conclusion

Voici un rappel des notes obtenu par nos deux coureurs :

  • Installation : Kivy 18/20 ; ionic : 15/20
  • IDE : Kivy 18/20 ; ionic : 10/20
  • Documentation : Kivy 18/20 ; ionic : 15/20
  • Hello World : Kivy : 18/20 ; ionic : 12/20
  • Développement sur PC : Kivy 18/20 ; ionic : 12/20
  • Déploiement sur mobile : 18/20 pour les deux
  • Développements sans appels aux device : Kivy 18/20 ; ionic : 15/20
  • Appels aux fonctionnalités du device : Kivy 12/20 ; ionic : 12/20
  • Design et interface : Kivy 8/20 ; ionic : 18/20

Total (après utilisation plus approfondie) : Kivy 146 pts (+4 pts) ; ionic : 127 pts (-23pts)

Pour ma prochaine application mobile, si l’interface doit être simple, elle sera en Kivy. Si elle doit avoir une interface plus travaillée, ce sera avec ionic, mais elle ne sera pas trop complexe (fonctions simples).

 

SoundBox avec ionic

Introduction

Après avoir réalisé une boite à sons avec Kivy, j’ai tenté de faire la même chose avec ionic. Les réflexes sont les mêmes, la méthode de travail est un peu différente.

 

Ajout du plugin Media

Pour faire jouer un son sur le mobile, il est nécessaire d’installer le plugin Cordova « Media ». Malheureusement, il ne fonctionne pas sous le navigateur du développeur. Il faudra faire le test sur le device mobile. Seule différence notable avec Kivy, qui permet de jouer un son presque de la même façon depuis le PC ou depuis le mobile.

 

Structuration du code

Même s’il n’y a pas grand chose, je tiens à avoir le code le plus structuré et le plus propre possible. L’application se découpe en 2 pages : la liste des catégories (page #1) et la liste des sons de la catégorie choisie (page #2).

Je me suis fortement inspiré du code de cette application : https://github.com/angular-app/angular-app/tree/master/client/src/app

Voici le contenu du répertoire www :

  • app : Répertoire de l’application
    • intro : Répertoire des fichiers de la vue « intro », page #1 de l’application
      • intro.js : Controller de la page « intro »
      • intro.tpl.html : Vue de la page « intro »
    • sounds : Répertoire de la page #2
      • sounds.js : Controller de la page des sons
      • sounds.tpl.html : Vue de la page des sons
    • app.js : Définition des services et du routage des pages
  • css : Répertoire vide pour les CSS spécifiques à l’application
  • js : Répertoire vide pour bibliothèques JS spécifiques à l’application
  • lib : Répertoire des plugins ajoutés pour l’application (géré par cordova)
  • mp3 : les sons

 

Détail du code

Il y a 6 fichiers importants pour que l’application fonctionne correctement.

index.html

<body ng-app="starter">
    <ion-nav-view></ion-nav-view>

    <script src="lib/media/Media.js"></script>
    <script src="lib/media/MediaError.js"></script>

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

    <script src="app/intro/intro.js"></script>
    <script src="app/sounds/sounds.js"></script>
</body>

 

app.js

angular.module('soundBox.services', [])
.factory('CategoryService', function() {
    // Might use a resource here that returns a JSON array
    var categories = {
            "Animaux": ["Aigle", "Cigales"],
            "Divers": ["Claque", "Dentiste", "Klaxon", "PopDing", "Pouic", "Sieste bebe"],
            "Humain": ["Applaudissements", "Ramirez - alors ausweis papier svp - au trot", "Ramirez - hop hop hop hop", "Ramirez - jai dit ausweis"],
            "Objets": ["Canette Coca", "Casse assiette", "Cloche hotel", "Guitare", "Matrix_phone", "Telephone_Ancien", "Toy telephone", "Corne de brume", "Jouet de chien", "Sirene Alarme", "Telephone_x2"],
            "TV": ["Thames TV", "The Benny Hill Show"]
        };
    return {
        all: function() {
            return Object.keys(categories);
        },
        get: function(aCategory) {
            return categories[aCategory];
        }
    };
})
;

var app = angular.module('starter', ['ionic', 'ui.router', 'soundBox.services'])

.config(function($stateProvider, $urlRouterProvider) {

  $stateProvider.state('intro', {
    url: '/',
    templateUrl: 'app/intro/intro.tpl.html',
    controller: 'IntroCtrl'
  });

  $stateProvider.state('sounds', {
    url: '/sounds/:category',
    templateUrl: 'app/sounds/sounds.tpl.html',
    controller: 'SoundsCtrl'
  });

  $urlRouterProvider.otherwise('/');

});

Ce fichier aurait pu être découpé en 2 : le service et le routage.

 

intro.tpl.html

<ion-view title="Sound Box">
    <ion-nav-bar type="bar-positive"
        animation="nav-title-slide-ios7"
        back-button-type="button-icon button-clear"
        back-button-icon="ion-ios7-arrow-back">
        <ion-nav-back-button>
            <i></i> Back
        </ion-nav-back-button>
    </ion-nav-bar>

    <ion-content>
        <ion-list>
            <ion-item ng-repeat="item in items" href="#/sounds/{{item}}">
                {{item}}
                <i></i>
            </ion-item>
        </ion-list>
    </ion-content>
</ion-view>

 

intro.js

app.controller('IntroCtrl', function($scope, $location, $state, CategoryService) {
    $scope.items = CategoryService.all();
})
;

 

sounds.tpl.html

<ion-view title="Sound Box">
    <ion-nav-bar type="bar-positive"
        animation="nav-title-slide-ios7"
        back-button-type="button-icon button-clear"
        back-button-icon="ion-ios7-arrow-back">
        <ion-nav-back-button>
            <i></i> Back
        </ion-nav-back-button>
    </ion-nav-bar>

    <ion-content>
        <ion-list>
            <ion-item ng-repeat="item in items" ng-click="selectSound('{{item}}')">
                {{item}}
            </ion-item>
        </ion-list>
    </ion-content>
</ion-view>

 

sounds.js

app.controller('SoundsCtrl', function($scope, $state, $location, $stateParams, $ionicPlatform, CategoryService) {

    var sounds = CategoryService.get($stateParams.category);
    $scope.items = sounds;

    $scope.selectSound = function(sound) {
        var src = "/mp3/"+sound+".mp3";
        if(ionic.Platform.isAndroid()){
            src = "/android_asset/www" + src;
        }
        if($scope.media){
            $scope.media.stop();
        }
        $scope.media = new Media(src, function(){console.log("successfuly played "+ sound);}, function(e){console.log(e);});
        $scope.media.play();
        // ne pas faire d'autres interprétations du click
        return false;
    };

    $ionicPlatform.onHardwareBackButton(function(){
        if($scope.media){
            $scope.media.stop();
            $scope.media = null;
        }
    });
});

 

Conclusion / comparaison avec Kivy

Le code doit être rigoureusement écrit. Par exemple le tag « <ion-view> » doit être le seul dans la vue, sinon l’affichage est un peu cassé.

Selon le formalisme utilisé, les fichiers sont multiples mais courts et bien classés, ce qui est très agréable à maintenir.

Le design n’a pas été fait de manière aussi complète que l’application réalisée avec Kivy, mais j’imagine que les CSS et images seront faciles à manipuler, comme pour un site web.

Vivement d’autres applications pour mieux comparer les frameworks dans une application plus complète.

 

Téléchargement de l’APK

SoundBox-ionic-debug.apk

Comparatif ionic / Kivy

Introduction

Après quelques applications réalisées avec Kivy, je me rends compte des possibilités et des limites de ce Framework pour réaliser des applications mobiles cross-platform. Je me suis orienté vers une technologie en vogue : Cordova, plus précisément ionic.

Remarque : cet article est le « match aller ». Un autre article « match retour » apporte des précisions.

 

Ionic : Description rapide

Ionic est un Framework pour les développeurs de Javascript. L’objectif est de faire un petit serveur web avec des pages HTML et du code JS. Cordova fourni le serveur web qui sera lancé sur mobile et encapsule le code. Les appels JS à destination du device sont interceptés pour être interprétés selon l’OS (Android, iOS, etc).

L’avantage est que beaucoup de développeurs connaissent le trio HTML + JS + CSS.

D’autres Frameworks sont disponibles avec ces technologies, comme jQuery Mobile et à coupler avec une surcouche, comme Backbone.js pour plus de rigueur. Après une tentative infructueuse, j’ai renoncé à me salir d’avantage les mains.

 

Comparatif de l’installation

Avec Kivy, l’installation est rapide sous Linux car Python est déjà installé. Le téléchargement des fichiers SDK d’Android sont assez rapide car Kivy cible ce qu’il faut télécharger. Ma note : 18/20

Avec ionic, l’émulateur est nécessaire et là, il faut prévoir de faire autre chose pendant les téléchargements. Ma note : 15/20

Mon vainqueur : Kivy

 

Editeur de code (ou IDE)

Il est facile de trouver un IDE : Eclipse avec les plugins pour coder en Python ou en HTML/JS/CSS. Ils peuvent cohabiter dans le même workspace sans souci.

Mon vainqueur : ex-equo

Ma note pour les deux : 18/20

 

Documentation et exemples

Kivy a élevé le niveau avec son API très complète disponible sur le site http://kivy.org ainsi que des projets complets open-source sur GitHub.

Malgré tout, ionic n’est pas en reste, avec un grande communauté de développeurs, le site qui présente son API est assez complète. Il faut parfois jongler entre l’API de Cordova et l’API de ionic pour trouver ses petits.

Mon vainqueur : ex-equo

Ma note pour les deux : 18/20

 

Le premier « Hello world »

Le site de Kivy présente les 6 lignes de code nécessaires à ce test basique. Le principe est facile à comprendre. Facile. Ma note : 18/20

Ionic propose de faire une installation d’une application basique en une ligne de commande. Facile à faire (tout est téléchargé et pré-configuré), moins facile à comprendre comment ca fonctionne dans le détail. Ma note : 15/20

Mon vainqueur : Kivy, d’une courte tête

 

Développement d’une application sur un PC

Kivy lance Python directement depuis Eclipse (après une configuration minimale). Les amateurs de Java ne seront pas déçus. Les logs sont récupérés dans la console d’Ecplise, le mode debug fonctionne à merveille (point d’arrêt, avancée pas à pas, consultation des valeurs des variables, etc). L’application Kivy s’ouvre dans une fenêtre à part pour qu’on puisse interagir. Ma note : 18/20

Pour ionic, il faut lancer une commande qui démarre un serveur web (sur un port libre) et qui ouvre le navigateur par défaut. Chrome est préconisé avec le plugin ADT (pour android). Toute interaction se fait alors dans Chrome. L’IDE devient inutile, il ne sert que d’éditeur de texte. Dommage. Je n’ai pas trouvé le moyen de mettre un point d’arrêt, de consulter les valeurs des variables en temps réel. Au moins, la console de Chrome fonctionne. Ma note : 12/20

Mon vainqueur : Kivy

 

Déploiement sur mobile (Android)

Un outil « magique » est associé à Kivy pour faire l’APK : buildozer. Il faut produire un fichier de configuration pour les autorisations d’accès, le nom du package, le splash screen, l’icone, la version, etc. (un fichier de base est généré avec beaucoup de doc, façon « httpd.conf », très facile à comprendre). A mon avis, un atout très fort. Ma note : 18/20

Ionic n’est pas en reste. Il a lui aussi sa ligne de commande avec le fichier XML de configuration. Moins simple qu’avec buildozer quand même. Ma note : 18/20

Le temps de packaging et l’installation sur le smartphone est aussi rapide.

Mon vainqueur : ex-equo (sans compter la configuration)

 

Développements sans appels au device

La puissance de Python permet de faire beaucoup de choses simplement, avec très peu de code. C’est encore une force de Kivy.

Exemples : lecture de fichier XML ou JSON, appels HTTP-GET ou HTTP-POST, manipulation de chaînes de caractères, tableaux, dictionnaires, appels aux serveurs de cartographie (Google maps, Open Street map, BlueMarble), etc…

Le découpage en couches est facile avec l’utilisation de modules et packages Python pour définir les classes. Ma note : 18/20

Pour ionic, le Javascript permet aussi de faire beaucoup sans faire appel à d’autres choses, peut-être avec un peu plus de complexité. Les bibliothèques JS sont très nombreuses pour aller plus vire. Ionic profite des années de développements JS pour le web.

Pour garantir un code maintenable, ionic s’appuie sur Angular, pas trop complexe à utiliser dans un premier temps. Ma note : 18/20

Mon vainqueur : ex-equo

 

Appels aux fonctionnalités du device

Dans cette catégorie, je comprends une base de données (SQLite), le GPS, le vibreur, la caméra, etc.

Selon le cas, Kivy penne à sortir son épingle du jeu. Il faut utiliser des modules complémentaires pour accéder aux spécificités du smartphone. Par exemple, « plyer » permet de faire beaucoup de choses simplement, mais il est encore en cours de développements pour proposer une panoplie complète. La page de support des fonctionnalités selon l’OS montre pas mal de trous. Ma note : 12/20

Testé et fonctionne très bien : Base de données SQLite, jouer un son MP3, prendre une photo, obtenir la position GPS, bouton Back d’Android

Testé et ne fonctionne pas (encore) : Réalité augmentée

Pour ionic, Cordova semble prendre en charge un grand nombre de fonctionnalités. Cette brique est indispensable, même si je ne pense pas qu’elle puisse faire comme une application native. Ma note : 18/20

Testé et fonctionne bien : jouer un son MP3

Mon vainqueur : ionic (il sera certainement plus performant que Kivy dans ce domaine)

 

Design et interface

Avis aux WebDesigners, Kivy est une torture. Pour ceux qui ont fait du CSS, c’est horrible. Le langage KV est obligatoire et rédhibitoire (tellement que je me suis intéressé à d’autres Frameworks). Il faut prévoir ÉNORMÉMENT de temps pour comprendre comment fonctionne le principe d’affichage. L’option est de faire des widgets (composant graphique) simples à composer entre eux pour composer l’écran. Ma note : 4/20

Avec ionic, on reste sur du CSS (presque) classique. En plus, avec les thèmes déjà tout prêts, les WebDesigners retrouvent leurs marques. Ma note : 18/20

Mon vainqueur : ionic, largement en tête

 

Conclusion

Après avoir réalisé une application similaire avec Kivy et ionic (soundbox), je suis encore resté sur ma faim avec ionic. Je pense qu’il faudra que j’utilise SQLite, la position GPS, et d’autres fonctionnalités pour affiner mes notes.

Si on compte les points, voici mon résultat :

  • Installation : Kivy 18/20 ; ionic : 15/20
  • IDE : 18/20 pour les deux
  • Documentation : 18/20 pour les deux
  • Hello World : Kivy : 18/20 ; ionic : 15/20
  • Développement sur PC : Kivy 18/20 ; ionic : 12/20
  • Déploiement sur mobile : 18/20 pour les deux
  • Développements sans appels aux device : 18/20 pour les deux
  • Appels aux fonctionnalités du device : Kivy 12/20 ; ionic : 18/20
  • Design et interface : Kivy 4/20 ; ionic : 18/20

Total : Kivy 142 pts ; ionic : 150 pts

 

Snippet kv : IconTextCounter

Présentation

Pour aller plus loin avec le widget IconText cité dans un article de ce site, j’ai ajouté un indicateur avec un compteur, tel qu’on peut le voir dans des applications. Kivy ne proposant que des widgets basiques, voici une construction qui répond au problème.

 

Composition

Ce widget hérite de FloatLayout pour placer les éléments de manière relative, l’un au dessus de l’autre. Il contient :

  • un widget IconText
  • un widget Label, avec en image de fond le bleu avec des coins arrondis

 

Code kv

<IconTextCounter>:
	_icontext: _icontext_id
	_counter: _counter_id
	IconText:
		id: _icontext_id
		text: "dummy"
		icon: "images/ic_action_star.png"
		pos_hint: {'x':0, 'top':1}

	Label:
		canvas.before:
			Color:
				rgba: 1,1,1, 1
			Rectangle:
				pos: self.pos
				size: self.size
				source: "kvx_widgets/images/counter_bg.png"
		id: _counter_id
		text: "x"
		pos_hint: {'center_x':0.95, 'top':0.65}
		size_hint: (None, None)
		size: (self.texture_size[0]+sp(16), self.texture_size[1]+sp(8))
		font_size: sp(12)

Une astuce pour avoir un fond qui prend toute la taille du libellé : définir la taille à partir de la texture + un petit espace.

size: (self.texture_size[0]+sp(16), self.texture_size[1]+sp(8))

 

Code Python

class IconTextCounter(FloatLayout):
    counter = StringProperty("")
    counter_position = StringProperty("")
    counter_background = StringProperty("")

    text = StringProperty("")
    icon = StringProperty("")
    icon_size = NumericProperty(sp(80))
    font_size = NumericProperty(sp(18))
    text_color = VariableListProperty([0,0,0,1])
    forced_width = NumericProperty(sp(80))

    def __init__(self, **kwargs):
        super(IconTextCounter, self).__init__(**kwargs)
        self.bind(counter = IconTextCounter.set_counter,
                counter_position = IconTextCounter.set_counter_position,
                counter_background = IconTextCounter.set_counter_background,
                text = IconTextCounter.set_text,
                icon = IconTextCounter.set_icon,
                icon_size = IconTextCounter.set_icon_size,
                font_size = IconTextCounter.set_font_size,
                text_color = IconTextCounter.set_text_color,
                forced_width = IconTextCounter.set_forced_width
                )

    def set_counter(self, aValue):
        self._counter.text = aValue

    def set_counter_position(self, aPosition):
        delta = 0.15
        center_x = 0.5
        top = 0.80
        if aPosition == 'top-left':
            center_x -= delta
            top += delta
        elif aPosition == 'top-right':
            center_x += delta
            top += delta
        elif aPosition == 'bottom-left':
            center_x -= delta
            top -= delta
        elif aPosition == 'bottom-right':
            center_x += delta
            top -= delta

        self._counter.pos_hint = {'center_x':center_x, 'top':top}

    def set_counter_background(self, aSourceImage):
        self._counter.canvas.before.children[1].source = aSourceImage

    ## define all IconText methods
    def set_text(self, aText):
        self._icontext.text = aText

    def set_icon(self, aSourceImage):
        self._icontext.icon = aSourceImage

    def set_icon_size(self, aWidthHeight):
        self._icontext.icon_size = aWidthHeight

    def set_font_size(self, aFontSize):
        self._icontext.font_size = aFontSize

    def set_text_color(self, aColor):
        self._icontext.text_color = aColor

    def set_forced_width(self, aWidth):
        self._icontext.forced_width = aWidth

 

Ce widget est utilisé dans une grille :

picto = IconTextCounter()
picto.text = aCategory.catlblib
picto.icon = 'images/category_%s.png' % aCategory.catcdcode
picto.counter = "%s" % nb_pois
picto.counter_position = 'top-right'
self.grid_widget.add_widget( picto )

 

Snippet kv : ListIconItemButton

Présentation

Kivy propose un widget qui sert d’item dans une liste : « ListItemButton« . Cet item est cliquable, mais son utilisation est relativement complexe. Surtout si on désire ajouter des icones à gauche ou à droite du libellé, ca commence à devenir un casse tête.

Voici une autre implémentation du même besoin, avec des icones de chaque côté du label :

 

Composition

Ce widget hérite de GridLayout, avec, en une ligne :

  • Un Label pour le padding à gauche
  • Un Label pour l’image de gauche
  • Un Label pour le libellé
  • Un Label pour l’image de droite
  • Un Label pour le padding à droite

Si l’image de gauche est spécifiée à None, aucune icône n’apparaît (1er exemple de cet article).

Ce Widget doit être inséré dans un GridLayout, lui même dans un ScrollView:

	ScrollView:
		GridLayout:
			id: list_items_id
			cols: 1
			size_hint_y: None

 

Code kv

<ListIconItemButton>:
	_label_text: _label_text_id
	_padding_right: _padding_right_id
	_padding_left: _padding_left_id
	_left_icon: _left_icon_id
	_right_icon: _right_icon_id
	rows: 1
	size_hint_y: None
	height: sp(50)

	Label:
		id: _padding_left_id
		text: ""
		size_hint_x: None
		width: sp(4)
	Label:
		canvas.before:
			Color:
				rgba: 1,1,1, 1
			Rectangle:
				pos: self.pos
				size: self.size
				source: "images/ic_action_star.png"
		id: _left_icon_id
		text: ""
		size_hint_x: None
		width: sp(50)

	Label:
		id: _label_text_id
		text: "dummy"
		size_hint_x: 1
		halign: 'left'
		valign: 'middle'
		text_size: self.size

	Label:
		canvas.before:
			Color:
				rgba: 1,1,1, 1
			Rectangle:
				pos: self.pos
				size: self.size
				source: "images/ic_action_next.png"
		id: _right_icon_id
		text: ""
		size_hint_x: None
		width: sp(25)

	Label:
		id: _padding_right_id
		text: ""
		size_hint_x: None
		width: sp(4)

 

Code Python

class ListIconItemButton(ButtonBehavior, GridLayout):
	text = StringProperty("")
	text_color = VariableListProperty([0,0,0,1])
	font_size = NumericProperty(sp(18))
	index = NumericProperty(0)
	padding = VariableListProperty([sp(2),sp(2)])
	left_icon_width = NumericProperty(sp(50))
	right_icon_width = NumericProperty(sp(50))
	left_icon = StringProperty("")
	right_icon = StringProperty("")

	def __init__(self, **kwargs):
		super(ListIconItemButton, self).__init__(**kwargs)
		self.bind(text = ListIconItemButton.set_text,
				text_color = ListIconItemButton.set_text_color,
				font_size = ListIconItemButton.set_font_size,
				index = ListIconItemButton.set_index,
				padding = ListIconItemButton.set_padding,
				left_icon_width = ListIconItemButton.set_left_icon_width,
				right_icon_width = ListIconItemButton.set_right_icon_width,
				left_icon = ListIconItemButton.set_left_icon,
				right_icon = ListIconItemButton.set_right_icon
				)

	def set_text(self, aText):
		self._label_text.text = aText

	def set_index(self, aNumber):
		self.item_index = aNumber

	def get_index(self):
		return self.item_index

	def set_padding(self, aPadding):
		if isinstance(aPadding, (float,int,long,float)):
			self._padding_left.width = aPadding
			self._padding_right.width = aPadding
		else:
			self._padding_left.width = aPadding[0]
			self._padding_right.width = aPadding[1]

	def set_font_size(self, aSize):
		self._label_text.font_size = aSize

	def set_text_color(self, aColor):
		self._label_text.color = aColor

	def set_left_icon_width(self, aWidth):
		self._left_icon.width = aWidth

	def set_right_icon_width(self, aWidth):
		self._right_icon.width = aWidth

	def set_left_icon(self, aSourceImage):
		if aSourceImage == "" or aSourceImage is None:
			self.remove_widget(self._left_icon)
		else:
			self._left_icon.canvas.before.children[1].source = aSourceImage

	def set_right_icon(self, aSourceImage):
		if aSourceImage == "" or aSourceImage is None:
			self.remove_widget(self._right_icon)
		else:
			self._right_icon.canvas.before.children[1].source = aSourceImage

Snippet kv : Scrollable text

Présentation

Kivy permet d’implémenter un texte trop long et qui nécessite de scroller vers le bas, mais avec une composition de beaucoup de widgets pour l’intégrer à une page ainsi qu’une configuration assez difficile.

 

Composition

Ce widget hérite de la classe ScrollView qui permet le scrolling et contient un GridLayout, sur 3 lignes :

  • 1ère ligne : un label pour faire le padding-top
  • 2ème ligne : un autre GridLayout, sur 3 colonne :
    • 1ère colonne : un label pour faire le padding-left
    • 2ème colonne : le texte sous forme d’un Label
    • 3ème colonne : un label pour faire le padding-right
  • 3ème ligne un label pour faire le padding-bottom

 

Code kv

<ScrollableText>:
	_text_widget: _text_widget_id
	_padding_top: _padding_top_id
	_padding_left: _padding_left_id
	_padding_right: _padding_right_id
	_padding_bottom: _padding_bottom_id
	canvas.before:
		Color:
			rgba: self.background_color
		Rectangle:
			pos: self.pos
			size: self.size
	GridLayout:
		cols: 1
		height: _text_widget_id.height + _padding_top_id.height + _padding_bottom_id.height
		size_hint_y: None

		Label:
			id: _padding_top_id
			text: " "
			size_hint_y: None
			height: sp(4)

		GridLayout:
			rows: 1
			Label:
				id: _padding_left_id
				text: " "
				size_hint_x: None
				width: sp(8)
			Label:
				id: _text_widget_id
				text: "no text yet"
				font_size: '18sp'
				color: (0.1,0.1,0.1, 1)
				valign: 'top'
				# make it scrollable
				text_size: (self.width, None)
				size_hint_y: None
				size: (self.parent.width, self.texture_size[1] )
			Label:
				id: _padding_right_id
				text: " "
				size_hint_x: None
				width: sp(8)
		Label:
			id: _padding_bottom_id
			text: " "
			size_hint_y: None
			height: sp(4)

Astuce : la propriété « background_color » est directement utilisée dans le KV et non dans le python (comme la taille du texte par exemple).

 

Code Python

class ScrollableText(ScrollView):
    text = StringProperty("")
    background_color = VariableListProperty([1,1,1,0])
    text_color = VariableListProperty([0,0,0,1])
    padding = VariableListProperty([sp(8), sp(8), sp(8), sp(8)])
    font_size = NumericProperty(sp(18))

    def __init__(self, **kwargs):
        super(ScrollableText, self).__init__(**kwargs)
        self.bind(text = ScrollableText.set_text,
                text_color = ScrollableText.set_text_color,
                padding = ScrollableText.set_padding,
                font_size = ScrollableText.set_font_size
                )

    def set_text(self, aText):
        self._text_widget.text = aText

    def set_text_color(self, aColor):
        self._text_widget.color = aColor

    def set_padding(self, aPadding):
        """Top, Right, Bottom, Left
        """
        if isinstance(aPadding, (float,int,long,float)):
            self._padding_top.height = aPadding
            self._padding_right.width = aPadding
            self._padding_bottom.height = aPadding
            self._padding_left.width = aPadding
        if len(aPadding) == 4:
            self._padding_top.height = aPadding[0]
            self._padding_right.width = aPadding[1]
            self._padding_bottom.height = aPadding[2]
            self._padding_left.width = aPadding[3]
        elif len(aPadding) == 2:
            self._padding_top.height = aPadding[0]
            self._padding_right.width = aPadding[1]
            self._padding_bottom.height = aPadding[0]
            self._padding_left.width = aPadding[1]

    def set_font_size(self, aSize):
        self._text_widget.font_size = aSize

 

Snippet kv : icone et texte

Présentation

L’affichage d’une icône, comme représentée sur le bureau Windows n’est pas si simple à réaliser avec kivy.

 

Composition

Ce composant hérite de BoxLayout pour définir une série de widgets disposés verticalement :

  • ligne 1 : l’icône
  • ligne 2 : le texte

Attention, avec un BoxLayout, l’image risque de perdre son ratio (hauteur / largeur) d’origine pour être déformée.

Pour l’icone, le redimensionnement de l’image en conservant le ratio (pour les écrans HD), il faut utiliser un Label avec un background et forcer la taille hauteur et largeur.

 

Code kv

<Icon_Text>:
	size_hint_y: None
	height: sp(100)
	_text_widget: _text_widget_id
	_icon_widget: _icon_widget_id
	Label:
		canvas.before:
			Color:
				rgba: 1,1,1, 1
			Rectangle:
				pos: self.pos
				size: self.size
				source: "images/dummy.png"
		id: _icon_widget_id
		text: " "
		size_hint: (None, None)
		size: (sp(80), sp(80))
		pos_hint: {'center_x':0.5, 'top':0}

	Label:
		id: _text_widget_id
		text: "dummy"
		font_size: '18sp'
		color: (0.2,0.2,0.2, 1)

Le fichier kv contient donc 2 labels : un pour l’icône et un pour le texte.

 

Code Python

class Icon_Text(BoxLayout):
	text = StringProperty("")
	icon = StringProperty("")
	icon_size = NumericProperty(sp(80))
	font_size = NumericProperty(sp(18))
	text_color = VariableListProperty([0,0,0,1])

	def __init__(self, **kwargs):
		super(Icon_Text, self).__init__(**kwargs)
		self.orientation = 'vertical'
		self.bind(text=self.set_text,
				icon=self.set_icon,
				icon_size=self.set_icon_size,
				font_size=self.set_font_size,
				text_color=self.set_text_color)

	def set_text(self, aText):
		self._text_widget.text = aText

	def set_icon(self, aSourceImage):
		self._icon_widget.canvas.before.children[1].source = aSourceImage

	def set_icon_size(self, aWidthHeight):
		self._icon_widget.size = (aWidthHeight, aWidthHeight)

	def set_font_size(self, aFontSize):
		self._text_widget.font_size = aFontSize

	def set_text_color(self, aColor):
		self._text_widget.color = aColor

 

Ce widget est utilisable de la même façon que ceux fournis dans Kivy :

picto = Icon_Text()
picto.set_text( "%s : x %s" % (aCategory_name, nb_pts) )
picto.set_icon( 'images/category_%s.png' % aCategory_code )
self.grid_widget.add_widget( picto )

 

Snippet kv : ActionBar

Présentation

Le Widget « ActionBar » a été ajouté dans la version 1.8 de Kivy et nécessite une petite configuration pour ressembler aux jolies applications iOS ou Android.

 

Composition

 

Pour réaliser ce composant, il faut :

  • Ajouter une image de fond sur l’ActionBar « PNG noire avec une transparence de 25% » (elle peut faire 1×1 pixel). Elle nous permettra de voir l’image de fond (en dessous) et de faire une séparation nette de l’entête.
  • Ajouter les widgets dans l’ActionView :
    • ActionPrevious
    • ActionOverflow
    • ActionButton

Le widget « ActionOverflow » prendra toute la place nécessaire pour pousser le dernier widget « ActionButton » le plus à droite possible.

 

Code kv

ActionBar:
	background_image: "images/empty-25b.png"
	pos_hint: {'top':1}
	ActionView:
		use_separator: True
		ActionPrevious:
			title: 'Localité'
			previous_image: "images/ic_action_previous_item.png"
			app_icon: "images/app-icon.png"
			on_press: root.go_back()

		ActionOverflow:

		ActionButton:
			text: 'Refresh'
			icon: "images/ic_action_refresh.png"
			on_press: root.refresh()

 

 

 

 

LocalGuide

Description

LocalGuide est une application qui liste les points d’intérêt d’une localité avec une position GPS et une description. Une carte présente les points ainsi que la position actuelle de l’appareil.

Les points d’intérêt sont regroupés par catégorie pour faciliter la lecture de la carte.

Il est possible d’utiliser cette application pour des visites d’une ville avec des lieux à découvrir ou pour un parc avec des points de vue remarquables (roseraie, beaux arbres, jardin potager, orangerie, etc.)

 

Screenshots

         

 

Particularités

Cette application utilise KiviMaps pour la cartographie (ici OpenStreeMap) et Plyer pour récupérer la position GPS de l’appareil.

Une application Back-Office permet de configurer les localités et les points d’intérêt. Les données sont récupérées depuis cette application hébergée sur un serveur de free.fr puis stockées sur le mobile dans une base SQLite.

 

Reste à faire

  • Débugger l’interface (des petits bugs d’affichage sont à terminer avec le langage kv ==> pas simple)
  • Ajouter la visualisation des photos (disponibles en Back-Office)
  • Ajouter l’écoute d’un fichier audio sur un point d’intérêt (disponibles en Back-Office)
  • Configurer d’autres localités ou compléter celles existantes
  • Cacher des points selon une catégorie (exemple : ne pas faire afficher les points relatif au sport)
  • Améliorer la visibilité de la situation actuelle de l’appareil sur la carte (actuellement : un point bleu)
  • Trouver une voix pour enregistrer les descriptions audio des points d’intérêt

 

Sources

Disponibles sur GitHub :

https://github.com/jchome/LocalGuide-Mobile

Télécharger et installer

http://julien.coron.free.fr/apk/LocalGuide-0.1-debug.apk

SoundBox

Description

SoundBox est une application mobile qui joue un court son MP3. Totalement inutile, donc extrêmement indispensable.

 

Screenshots

  

 

Particularités

Son aspect très moderne pose les bases des applications grand public que peu proposer Kivy. Les images et polices utilisées pour cette application seront réutilisables pour d’autres applications.

 

Reste à faire

  • Certaines images peuvent être améliorées
  • Il faut absolument que je trouve un son de jouet pour chien !!!

 

Sources

Disponibles sur GitHub :

https://github.com/jchome/SoundBox

 

Télécharger et installer

SoundBox-0.1-debug.apk