画面を転換する - Kivy Advent Calendar 2013

5日目にCarouselを使いましたが、これはユーザのスライド操作で複数のウィジェットを見せていくことができます。これに対しScreenManagerは、それ自体はスライド操作を受け付けませんが、フェードイン、ワイプなどのさまざまな効果を持たせた画面転換ができます。


(/sdcard/kivy/screen/)

android.txt
main.py

(android.txt)

title=screen
author=cheeseshop
orientation=portrait

(main.py)

from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.screenmanager import ShaderTransition, SlideTransition, FadeTransition, WipeTransition

FADEINOUT_TRANSITION_FS = '''$HEADER$
uniform float t;
uniform sampler2D tex_in;
uniform sampler2D tex_out;

void main(void) {
float t1 = 0.45;
float t2 = 0.55;
vec4 cin = vec4(texture2D(tex_in, tex_coord0.st));
vec4 cout = vec4(texture2D(tex_out, tex_coord0.st));
vec4 frag_col = t < t1 ? vec4*1
            on_text: app.settr(self.text)
        Button:
            pos_hint: {'center_x':0.5, 'top':0.2}
            size_hint: (None, None)
            size: (200, 50)
            text: 'Back to home'
            on_press: root.manager.transition = app.tr1; root.manager.current = 'home'
''')

class FadeInOutTransition(ShaderTransition):
    fs = StringProperty(FADEINOUT_TRANSITION_FS)

class HomeScreen(Screen):
    pass

class SettingScreen(Screen):
    pass

class ScreenApp(App):

    trs = {
        'Slide_H': (SlideTransition(direction='right'),
                    SlideTransition(direction='left')),
        'Slide_V': (SlideTransition(direction='up'),
                    SlideTransition(direction='down')),
        'Swap':     SwapTransition(),
        'Fade':     FadeTransition(),
        'Wipe':     WipeTransition(),
        'FadeInOut':   FadeInOutTransition(),
    }

    def settr(self, tr):
        trs = self.trs[tr]
        if isinstance(trs, tuple):
            self.tr0 = trs[0]
            self.tr1 = trs[1]
        else:
            self.tr0 = trs
            self.tr1 = trs

    def build(self):
        self.sm = ScreenManager()
        self.sm.add_widget(HomeScreen(name='home'))
        self.sm.add_widget(SettingScreen(name='setting'))
        self.settr('Fade')
        return self.sm

if __name__ == '__main__':
    ScreenApp().run()

解説

このサンプルでは、「home」と「setting」の2つの画面間の移動をボタンで行います。setting画面には、6種類の画面効果を切り替えるオプションを用意しています。
まずScreenManagerを作り、そこに複数の画面を追加(add_widget)しておきます。transitionプロパティで効果を指定してから、currentプロパティに画面のnameを指定することで転換が行われます。
6種類のうち5つは組み込みで持っている画面の転換方法です。

transition arg
SlideTransition 'right' 'left' 水平方向にスライドして切り替える
SlideTransition 'up' 'down' 垂直方向にスライドして切り替える
SwapTransition 前後を入れ替えるようにして切り替える
FadeTransition じわじわと切り替える
WipeTransition ワイプして切り替える

最後の1つ「FadeInOut」はこのスクリプトの中で作成したオリジナルの画面効果です。

FadeInOutTransition フェードアウトしてからフェードイン

Pythonスクリプトなのに「void main(vold) {...}」とかC言語っぽい文字列がありますが、これがシェーダ効果を記述する言語(GLSL)です。ShaderTransitionのプロパティにセットするとOpenGL APIを通じて自動的にコンパイルされ、画面効果として使えるようになります。

追記

このサンプルでは使っていませんが、Kivy 1.8からは次の効果も使えるようです。

FallOutTransition 中心へ古い画面が落ち込んでいく
RiseInTransition 中心から新しい画面が広がってくる

どちらもiOSAndroidの画面転換としてはおなじみのものですね。

*1:1.0 - t / t1) * cout) : t > t2 ? vec4((t - t2) / (1.0 - t2) * cin) : vec4(0.0); gl_FragColor = frag_col; } ''' from kivy.lang import Builder Builder.load_string(''' : canvas.before: Color: rgb: 0.4, 0.3, 0.2, 1 Rectangle: pos: self.pos size: self.size FloatLayout: Label: pos_hint: {'center_x':0.5, 'top':0.8} size_hint: (None, None) size: (200, 50) text: 'Home' Button: pos_hint: {'center_x':0.5, 'top':0.2} size_hint: (None, None) size: (200, 50) text: 'Goto setting' on_press: root.manager.transition = app.tr0; root.manager.current = 'setting' : canvas.before: Color: rgb: 0.2, 0.3, 0.4, 1 Rectangle: pos: self.pos size: self.size FloatLayout: Label: pos_hint: {'center_x':0.5, 'top':0.8} size_hint: (None, None) size: (200, 50) text: 'Setting' Spinner: pos_hint: {'center_x':0.5, 'top':0.5} size_hint: (None, None) size: (200, 50) text: 'Slide_H' values: sorted(app.trs.keys(