画面遷移と保存
pop / push_scene / change_scene / launch_app / content_rect / args / store_load / store_save
pico.pop
自分を起動した画面(ランチャ、または push_scene の呼び出し元)へ戻ります。実際に戻るのはそのフレームの終わりです。
result(任意)を渡すと、push_scene の呼び出し元の画面の on_result(result) に渡されます(画面の間で値を受け渡す 参照)。result はJSONにできる値(テーブル・文字列・数値・真偽値)で、JSONにして1KiB未満である必要があります。大きすぎる・JSONにできない値はエラーです。ランチャから起動した画面など、戻り先がLuaの画面でなければ結果は捨てられます。
pico.push_scene
path(SDの絶対パス)の Lua スクリプトを新しい画面として開きます。新しい画面で pico.pop() すれば今の画面へ戻れます。同じアプリとして、権限とアプリのフォルダはそのまま引き継がれます。
args(任意)は新しい画面の pico.args() で受け取れます。pico.pop の result と同じく、JSONにできる値で1KiB未満です。
pico.change_scene
path の Lua スクリプトへ画面を置き換えます。スタックを消費しないため、今の画面へは戻れません(pico.pop() すると、今の画面を開いた側まで直接戻ります)。権限は push_scene と同じく引き継がれます。args も同じ。置き換えた先の pico.pop(result) は、元の画面を開いた側の on_result に届きます。
pico.args
push_scene / change_scene で渡された args を返します。何も渡されなければ nil。null は pico.json_null になります。
pico.launch_app
ランチャにあるアプリ(OS標準のアプリを含む)を名前で探して開きます。見つからなければ false、見つかれば true です。開いたアプリは、そのアプリ自身の権限で動きます。
pico.content_rect
ステータスバーを除いた、アプリが使える範囲を返します。
画面の大きさは本体によって違います(既定は240x320。ビルド時に320x480等にできる)。ウィジェットや絵の位置は、240や320を直接書かずにこの値から決めてください。画面全体の大きさは定数 pico.SCREEN_WIDTH / pico.SCREEN_HEIGHT です。
local x, y, w, h = pico.content_rect()
local btn = pico.create("Button")
pico.set(btn, "x", x + w - 64) -- 右端に寄せる(画面の幅によらない)
画面の間で値を受け渡す
push_scene で別の画面へ移って pop で戻ると、元の画面のスクリプトは最初から実行し直されます。値を受け渡すための仕組みが3つあります。
| やりたいこと | 使うもの |
|---|---|
| 子の画面に値を渡す | push_scene(path, args) → 子で pico.args() |
| 子の画面から結果を受け取る | 子で pico.pop(result) → 親の on_result(result) |
| 離れる前の状態を戻ったあとに復元する | on_suspend() が返したテーブル → on_resume(state) |
-- main.lua(親)
local selected = nil
function on_suspend() -- 画面を離れる直前に呼ばれる
return { selected = selected } -- 返したテーブルが持ち越される(JSONで2KiB未満)
end
function on_resume(state) -- 戻ってきて setup() の後に呼ばれる
selected = state.selected
end
function on_result(r) -- 子が pico.pop(result) したとき、on_resume の後に呼ばれる
selected = r.color
pico.set(label, "text", "選んだ色: " .. r.color)
end
pico.on(pick_btn, "press_start", function()
pico.push_scene("/lua/apps/demo/picker.lua", { title = "色を選ぶ" })
end)
-- picker.lua(子)
local args = pico.args()
pico.on(red_btn, "press_start", function()
pico.pop({ color = "red" })
end)
- 呼ばれる順序は
setup()→on_resume(state)→on_result(result)です。どれも定義は任意で、無ければ何も起きません。 on_suspendは画面を離れるたび(push_sceneで別の画面へ移るとき、popで戻るとき)に呼ばれます。返す値が無い(nil)ときは何も保存されません。ここでエラーになってもダイアログは出ず、ログに残るだけです。on_resultは、pico.pop(result)から約3秒以内に親が実際に戻ったときだけ呼ばれます。子の画面からpico.pop()した(結果を渡さなかった)ときは呼ばれません。- 持ち越した状態が残るのは、その画面がスタックに積まれている間(メモリ上)だけです。アプリを閉じた後も残したい値は
store_saveを使ってください。
pico.store_load / pico.store_save
アプリのフォルダの store.json に値を1つ保存・読み込みます(最高得点・設定・途中経過など)。sd_read/sd_write と json_encode/json_decode を組み合わせた便利関数です。
local save = pico.store_load() or { best = 0 }
if score > save.best then
save.best = score
pico.store_save(save)
end
- 保存できるのは JSON にできる値で、16KiBまでです。JSONにできない値(関数など)を渡すとエラー、大きすぎる・書き込めないときは
falseを返します。 - 一時ファイルに書いてから差し替えるので、書き込み中に電源が切れても前の内容は壊れません。
- ファイルが無い・壊れている・SDが使えないときは
nilを返します。 - アプリのフォルダの外には書きません(
sd_outside_app_dirの権限に関わらず固定です)。
暗号化して保存する
opts.encrypt = true で、JSONを暗号化して store.json に書きます(password だけ渡しても暗号化されます)。読むときは自動で見分けます。パスワード付きで保存したものは、store_load({ password = ... }) が必要で、無い/違うと nil, 理由 を返します。暗号化したときの上限は12KiB(平文のJSONの大きさ)です。鍵の決め方と守れる範囲は 暗号化 を読んでください。
pico.store_save({ token = "abc" }, { password = "ながいあいことば" })
local data = pico.store_load({ password = "ながいあいことば" })
pico.on_back / pico.go_back
「戻る」の操作を横取りします。EscキーとコントローラーのHOMEで fn() が呼ばれます(画面に自前の「戻る」ボタンがあるなら、そこから pico.go_back() を呼びます)。fn が false を返すと「取らなかった」扱いで既定の動き(pico.pop())になります。それ以外(何も返さない場合を含む)は取った扱いです。nil で解除。
pico.on_back(function()
if not dirty then return false end -- そのまま戻る
local d = pico.show_message("保存していません。戻りますか?", "いいえ", "はい")
pico.on(d, "closed", function(_, ok) if ok then dirty = false; pico.pop() end end)
end)