Разработка мобильных приложений на Python
Станислав Каблуков

Kivy
Как это работает?
- Код на Python
- Фреймворк Kivy
- KV разметка
- Упаковка вместе с Сython
- Генерация нативного bootstrap
Python
- Python = 2.7 Python=3
- cPython
- PyGame
Kivy Framework
- Canvas(PyGame, X11, SDL, EGL)
- Native Events (HID, VM_Touch, Mac Touch ...)
- Modules
- GPU acceleration
- RAW OpenGL support
- MultiThread
- OpenSource
- MIT license
- Properties

- StringProperty
- NumericProperty
- ObjectProperty
- DictProperty
- ListProperty
- BooleanProperty
- ReferenceListProperty
Properties
Примеры
from kivy.properties import *
from date time import date
my_int = NumericProperty(42)
my_string = StringProperty('My string')
my_dict = DictProperty({'key': 'value'})
my_obj = ObjectProperty(date())
my_ref = referenceListProperty(
my_int, my_string, my_dict, my_obj
)
Layout System
- BoxLayout
- GridLayout
- StackLayout
- AnchorLayout
- FloatLayout
root = MyRootWidget() box = BoxLayout() box.add_widget(Button()) box.add_widget(Button()) root.add_widget(box)
KV Language
KV Language
MyRootWidget:
BoxLayout:
Button:
Button:
Это все еще Python
MyWidget: cols: len(some_data_from_python_file) on_size: my_callback_method pos: self.center_x / 2, self.center_y * 2
SOUNDBOARD
__version__ = '0.1' import kivy
from kivy.lang import Builder from kivy.uix.pagelayout import PageLayout kivy.require('1.0.8') from kivy.app import App from kivy.uix.button import Button from kivy.core.audio import SoundLoader from kivy.properties import StringProperty, ObjectProperty, NumericProperty from glob import glob from os.path import dirname, join, basename
__version__ = '1.19.1'
import kivy
from kivy.uix.pagelayout import PageLayout
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.audio import SoundLoader
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
from glob import glob
from os.path import dirname, join, basename
from kivy.uix.boxlayout import BoxLayout
class AudioButton(Button):
filename = StringProperty(None)
sound = ObjectProperty(None, allownone=True)
volume = NumericProperty(1.0)
def on_press(self):
if self.sound is None:
self.sound = SoundLoader.load(self.filename)
# stop the sound if it's currently playing
if self.sound.status != 'stop':
self.sound.stop()
self.sound.volume = self.volume
self.sound.play()
def release_audio(self):
if self.sound:
self.sound.stop()
self.sound.unload()
self.sound = None
class AudioBackground(PageLayout):
pass
class DownBanner(BoxLayout):
pass
class DownBannerToss(BoxLayout):
pass
class DownBannerTerr(BoxLayout):
pass
ZERG_LIST = []
TERRAN_LIST = []
PROTOSS_LIST = []
class AudioApp(App):
def build(self):
size = (80, 40)
background_down = 'images/Knopka_hit.png'
button_img = 'images/Knopka.png'
size_hint = (0.2, 0.2)
text_size = (None, None)
green = [0, 1, 0, 1]
# ROOT
root = AudioBackground(spacing=5)
# ==========================ZERG_BUTTON=========================================================================
for cat in glob(join(dirname(__file__), "Sound", "Zerg", "*")):
name_id = basename(cat).lower()
ZERG_LIST.append(name_id)
for fn in glob(join(cat, '*.wav')):
btn = AudioButton\
(background_normal=button_img, color=green, border=[0, 0, 0, 0],
text=basename(fn[:-4]).replace('_', ' '), filename=fn,
size_hint=size_hint, halign='justify',
size=size, text_size=text_size, font_size=14, background_down=background_down)
root.ids[name_id].add_widget(btn)
# ==========================PROTOSS_BUTTON=====================================================================
for cat in glob(join(dirname(__file__), "Sound", "Protoss", "*")):
name_id = basename(cat).lower()
PROTOSS_LIST.append(name_id)
for fn in glob(join(cat, '*.wav')):
btn = AudioButton(background_normal=button_img, color=green, border=[0, 0, 0, 0],
text=basename(fn[:-4]).replace('_', ' '), filename=fn, size_hint=size_hint,
halign='justify', size=size, text_size=text_size, background_down=background_down)
if name_id == "advisor":
root.ids.advisorp.add_widget(btn)
else:
root.ids[name_id].add_widget(btn)
# ==========================Terran_BUTTON=====================================================================
for cat in glob(join(dirname(__file__), "Sound", "Terran", "*")):
name_id = basename(cat).lower()
TERRAN_LIST.append(name_id)
for fn in glob(join(cat, '*.wav')):
btn = AudioButton(background_normal=button_img, color=green, border=[0, 0, 0, 0],
text=basename(fn[:-4]).replace('_', ' '), filename=fn, size_hint=size_hint,
halign='justify', size=size, text_size=text_size, background_down=background_down)
if name_id == "advisor":
root.ids.advisort.add_widget(btn)
else:
root.ids[name_id].add_widget(btn)
return root
def release_audio(self):
for id in ZERG_LIST:
for audiobutton in self.root.ids[id].children:
audiobutton.release_audio()
def release_audio_terr(self):
for id in TERRAN_LIST:
if id == "advisor":
id = "advisort"
for audiobutton in self.root.ids[id].children:
audiobutton.release_audio()
def release_audio_prot(self):
for id in PROTOSS_LIST:
if id == "advisor":
id = "advisorp"
for audiobutton in self.root.ids[id].children:
audiobutton.release_audio()
if __name__ == '__main__':
AudioApp().run()
class AudioButton(Button): filename = StringProperty(None) sound = ObjectProperty(None, allownone=True) volume = NumericProperty(1.0) def on_press(self): if self.sound is None: self.sound = SoundLoader.load(self.filename) # stop the sound if it's currently playing if self.sound.status != 'stop': self.sound.stop() self.sound.volume = self.volume self.sound.play()
#:kivy 1.8.0
#:import kivy kivy
<DownBanner>:
padding: 10
spacing: 10
size_hint_x: 0.8
size_hint_y: 0.2
Image:
size_hint: 0.2, 1
size: 64, 64
source: 'images/icon.png'
Image:
size_hint: 0.2, 1
size: 64, 64
source: 'images/sara.jpg'
Image:
size_hint: 0.5, 1
size: 64, 64
source: 'images/font/banner.bmp'
<DownBannerToss>:
padding: 10
spacing: 10
size_hint_x: 0.8
size_hint_y: 0.2
Image:
size_hint: 0.2, 1
size: 64, 64
source: 'images/zeal.png'
Image:
size_hint: 0.2, 1
size: 64, 64
source: 'images/zeal2.png'
Image:
size_hint: 0.5, 1
size: 64, 64
source: 'images/font/banner.bmp'
<DownBannerTerr>:
padding: 10
spacing: 10
size_hint_x: 0.8
size_hint_y: 0.2
Image:
size_hint: 0.2, 1
size: 64, 64
source: 'images/wrath.png'
Image:
size_hint: 0.2, 1
size: 64, 64
source: 'images/marine.png'
Image:
size_hint: 0.5, 1
size: 64, 64
source: 'images/font/banner.bmp'
<AudioBackground>:
BoxLayout:
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
source: 'images/fon/zerus.jpg'
size: self.size
orientation: 'vertical'
BoxLayout:
size_hint_x: 1
size_hint_y: 0.2
ToggleButton:
text: 'Loop'
size_hint_x: 0.4
size_hint_y: 1
id: btnloop
background_normal: "images/loop.png"
background_down: "images/loop_hit.png"
color: (0, 0, 0, 1)
Button:
text: 'Stop'
size_hint: 0.2, 1
background_normal: "images/stop.png"
on_press: app.release_audio()
color: (0, 1, 0, 1)
Button:
size_hint_x: 0.1
size_hint_y: 1
text: 'Prev'
background_normal: "images/next.png"
on_release: carousel.load_previous()
color: (0, 1, 0, 1)
Image:
size_hint: 0.1, 1
size: 64, 64
source: 'images/zerg/{}.gif'.format(carousel.index)
Button:
size_hint: 0.1, 1
text: 'Next'
background_normal: "images/next.png"
on_release: carousel.load_next()
color: (0, 1, 0, 1)
Carousel:
id: carousel
size_hint_x: 1
size_hint_y: 0.6
loop: btnloop.state == 'down'
StackLayout:
id: advisor
StackLayout:
id: avenger
StackLayout:
id: broodling
StackLayout:
id: bugguy
StackLayout:
id: defiler
StackLayout:
id: devourer
StackLayout:
id: drone
StackLayout:
id: egg
StackLayout:
id: guardian
StackLayout:
id: hydra
StackLayout:
id: larva
StackLayout:
id: lurker
StackLayout:
id: mutalid
StackLayout:
id: overlord
StackLayout:
id: queen
StackLayout:
id: ultra
StackLayout:
id: zergling
DownBanner:
BoxLayout:
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
source: 'images/fon/background.jpg'
size: self.size
orientation: 'vertical'
BoxLayout:
size_hint_x: 1
size_hint_y: 0.2
ToggleButton:
text: 'Loop'
size_hint: 0.4, 1
id: btnloops
background_normal: "images/loop.png"
background_down: "images/loop_hit.png"
color: (0, 0, 0, 1)
Button:
text: 'Stop'
size_hint_x: None
size_hint: 0.2, 1
background_normal: "images/stop.png"
on_press: app.release_audio_prot()
color: (0, 1, 0, 1)
Button:
size_hint_x: 0.1
size_hint_y: 1
text: 'Prev'
background_normal: "images/next.png"
on_release: carousels.load_previous()
color: (0, 1, 0, 1)
Image:
size_hint: 0.1, 1
size: 64, 64
source: 'images/protoss/{}.gif'.format(carousels.index)
Button:
size_hint: 0.1, 1
text: 'Next'
background_normal: "images/next.png"
on_release: carousels.load_next()
color: (0, 1, 0, 1)
Carousel:
id: carousels
size_hint_x: 1
size_hint_y: 0.6
loop: btnloops.state == 'down'
StackLayout:
id: advisorp
StackLayout:
id: arbiter
StackLayout:
id: archon
StackLayout:
id: carrier
StackLayout:
id: corsair
StackLayout:
id: darchon
StackLayout:
id: darktemplar
StackLayout:
id: dragoon
StackLayout:
id: intercep
StackLayout:
id: probe
StackLayout:
id: scout
StackLayout:
id: shuttle
StackLayout:
id: templar
StackLayout:
id: trilobyte
StackLayout:
id: witness
StackLayout:
id: zealot
DownBannerToss:
BoxLayout:
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
source: 'images/fon/terra.jpg'
size: self.size
orientation: 'vertical'
StackLayout:
size_hint: 1, 0.2
ToggleButton:
text: 'Loop'
id: btnloopt
size_hint: 0.4, 1
background_normal: "images/loop.png"
background_down: "images/loop_hit.png"
color: (0, 0, 0, 1)
Button:
text: 'Stop'
size_hint: 0.2, 1
on_press: app.release_audio_terr()
background_normal: "images/stop.png"
color: (0, 1, 0, 1)
Button:
size_hint_x: 0.1
size_hint_y: 1
text: 'Prev'
background_normal: "images/next.png"
on_release: carouselt.load_previous()
color: (0, 1, 0, 1)
Image:
size_hint: 0.1, 1
size: 64, 64
source: 'images/terran/{}.gif'.format(carouselt.index)
Button:
size_hint: 0.1, 1
text: 'Next'
background_normal: "images/next.png"
on_release: carouselt.load_next()
color: (0, 1, 0, 1)
Carousel:
id: carouselt
size_hint_x: 1
size_hint_y: 0.6
loop: btnloopt.state == 'down'
StackLayout:
id: advisort
StackLayout:
id: battle
StackLayout:
id: civilian
StackLayout:
id: dropship
StackLayout:
id: firebat
StackLayout:
id: frigate
StackLayout:
id: ghost
StackLayout:
id: goliath
StackLayout:
id: marine
StackLayout:
id: medic
StackLayout:
id: phoenix
StackLayout:
id: scv
StackLayout:
id: tank
StackLayout:
id: vessel
StackLayout:
id: vulture
DownBannerTerr:


Build and distribute
PyInstaller (Windows, OS X)
pip(Linux)
KV tool/ Python for android/ Buildozer(Android)

Build and distribute... iOS
Build and distribute... iOS
1.Compile Python and Modules
2. Create Xcode project
3. Insert your code in project
4. Link Python and modules
5. Customize (title, icons, etc)
6. Try build
Links
- http://kivy.org
- https://github.com/kivy
Kivy
By Станислав
Kivy
Kivy Python
- 859