【Pythonista3】ActivityIndicatorの使い方

# Abstract

本記事では、日本語情報が皆無に近いPythonista3のuiモジュールの中でも特に情報が少ない`ui.ActivityIndicator`の使い方と注意点を共有します。本記事ではドキュメントに書かれている内容を日本語でサンプルコードと共に注意点を含めて紹介します。

## Pythonista3とは

(任意のPythonやってる人向け説明, リンクはApp store)

https://apps.apple.com/jp/app/pythonista-3/id1085978097

Pythonista3とは、Pythonが動く**スマホアプリ**です。それだけだと他の競合がいくつかありますが、Pythonista3はuiモジュールやsceneモジュールを提供しており、Pythonで比較的簡単に**スマホで動くGUIアプリを作ることができる**のです！！
1200円と少々高いですが、私は4,5年使っていますが価値はあったと十分に感じています。~~最近アプデがなくて不安です。~~

## 前提

- uiモジュール自体の説明は省略します
    - pyuiは使いません。`scene.Scene`の上に画面を作成します。
- Pythonのclass程度の文法を仮定します
- 環境
    - iPhone 14
    - iOS 16.0
    - Pythonista3 version 3.3

# Preliminary

## インジケーターとは

もう少し一般には、「プログレスインジケーター」とか呼ばれる、処理中であることをユーザーに示すUIのことです。

[プログレスインジケータの役割とは？デザイナーのためのインジケータ設計アイデア](https://goodpatch.com/blog/progress-indicator) では、様々なインジケーターのデザイン例が採用例と同時に紹介されています。

https://goodpatch.com/blog/progress-indicator

Pythonista3 でアプリを作るモチベとしては、携帯で簡単にAPIを叩いてその結果を可視化できるとか、まぁ多岐に渡ります。
しかしやはりAPIを叩くにしろ、**処理の待ち時間は長くなりがち**ですよね。個人的に使うにしろ、簡単に次の図のようなインジケーターは欲しいというニーズはありますよね(え…ありますよね...?)。

![サーキュラーインジケータ](https://goodpatch.com/blog/wp-content/uploads/circular.gif)
図: サーキュラーインジケータ, https://goodpatch.com/blog/progress-indicator より

気が利く Pythonista3 にはそのためのパーツ`ui.ActivityIndicator`が準備されています。しかしこれ、めちゃくちゃ端的にしかドキュメントが書かれていないので、**使い方が紹介されている日本語情報、多分ないです**。

## `scene.Scene`

Pythonista3 ではuiモジュール以外にも提供しているモジュールがあり、sceneモジュールもその一つです。
ゲームとかを作成する目的ですが、デフォルトでフルスクリーンに画面が描画されます。
今回例のコードはscene.Sceneの上に作成しますが、これは`ui.View`がモーダルウィンドウになるからです。完全に好みです。
またそもそも本質的な部分は`ui.View`でも変わらないので、安心して参考にしてください(?)。

↓ 昔書いた`scene.Scene`のタッチ関係メソッドの実装例です。何かの参考に。

https://qiita.com/take_me/items/f3d93e82843ffeb869a6

## `ui.in_background`

uiなどのGUI表示部分の処理とは異なるスレッドで処理させるデコレーションです。多分。
ボタンのactionなどのコールバック関数にデコレーションをすると、別スレッドで処理が走ります。
よくわかりゃん！！の場合は、下記のようにアクションを行う部分に@でつけるとだけ覚えておけばよいです。

```python
import ui

@ui.in_background
def btn_action(sender):
    # 何か重い処理
    pass

...    # ui.Buttonのactionに`btn_action`を登録する
```

デコレータについて詳しくなりたい方は、[Pythonのデコレータについて](https://qiita.com/mtb_beta/items/d257519b018b8cd0cc2e)を参照してください。

# `ui.ActivityIndicator`のサンプルコードとその補足

- `ui.in_background`で**デコレーションされた関数 / メソッドの中**で、`start()`する必要があります

```python
import time

import ui
import scene

class MyApp(scene.Scene):
    def setup(self):
        self.background_color = 'orange'

        # 画面中央の座標(x, y)
        c = ui.get_screen_size() / 2

        # ボタン
        btn = ui.Button(title='Start', action=self.btn_tapped)
        btn.center = (c[0], c[1] * 2/3)
        btn.bounds = (0, 0, 50, 50)
        self.view.add_subview(btn)

        # ローダー
        self.loader = ui.ActivityIndicator()
        self.loader.center = c
        self.view.add_subview(self.loader)

        return super().setup()

    @ui.in_background
    def btn_tapped(self, sender: ui.Button):
        # アニメーションスタート
        self.loader.start()

        # 何か長い処理
        time.sleep(3)

        # アニメーション終わり
        self.loader.stop()


def main():
    app = MyApp()
    scene.run(app)


if __name__ == '__main__':
    main()
```

コードを動かして、ボタンを押すと次の図のようなくるくる回るインジケーターが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/07d731b4-cf9b-223d-6363-669af2b3bcd0.png)

`ui.ActivityIndicator`には設定できるデザインが3つあります。以下の3つのうち1つを`style`属性にセットすることで変更できます。

- `ui.ACTIVITY_INDICATOR_STYLE_GRAY`
    - 灰色のスピナー。既定でこれ。サンプルコードもこれです。
- `ui.ACTIVITY_INDICATOR_STYLE_WHITE`
    - 白色のスピナー。
- `ui.ACTIVITY_INDICATOR_STYLE_WHITE_LARGE`
    - 大きな白色のスピナー。

```python
class MyApp(scene.Scene):
    def setup(self):
        ...

        # ローダー
        self.loader = ui.ActivityIndicator()
        self.loader.center = c
        self.loader.style = ui.ACTIVITY_INDICATOR_STYLE_WHITE    # ← こんな感じで設定
        self.view.add_subview(self.loader)

        return super().setup()

```
次の図の二つがそれぞれ白色のスピナーと大きな白色のスピナーに対応します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/bccd1b96-896c-f757-43ec-02a4b96907e2.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/28513132-1894-3ae0-f4ef-2b23a464bed4.png)

## 補足

あまり使うケースが想定できませんが、`ui.ActivityIndicator`は常に表示させることもできます。
`hides_when_stopped = False`とすると常に表示され(ただしアニメーションは動かない)、`start()`が呼ばれるとアニメーションが動き、`stop()`でアニメーションが止まります。

# まとめ

本記事では`ui.ActivityIndicator`のサンプルコードと注意点を紹介しました。
Pythonista3 は色々と便利ではありますが、日本語情報がないのが少しネックです。
日本人のPythonista3愛好家の集まるディスコがあるらしいので、そちらにアドバイスを求めていくのもよいでしょう。
~~そして何か知見が得られたら積極的に記事を書いてね！~~

というかこのインジケーター、カスタマイズできないのかな。カスタマイズ出来たら別記事書くかも。

Pythonista3でアプリを作る、誰かの役に立てば幸いです。