特定の値をユーザーにプレゼントしたいときに、ちょっと楽しくしたいなーと思って、ルーレットで当たった数値をプレゼントしようかなーって思いつきました。
まさかFlutterのパッケージにルーレットなんて提供されていないよなーってダメ元で探してみると、結構いろんなパッケージが用意されていたんです。
flutter_spinning_wheel・・・却下
まず最初に見栄えだけで目をつけたのが、「flutter_spinning_wheel」です。
選んだ理由としては、
- 画像を使ってゴージャスなルーレットを回すことができるようです。
- 抽象クラスを使わずとも単独で使えるので、ProviderによるModel化も容易そう。
早速、サンプルプロジェクトを作ってExampleのソースをコピペして動かそうとすると、パッケージ自体が古く、Nullセーフ化されていないよーってエラーが出て、結局使えませんでした。
roulette_wheel_selection・・・却下
次に目をつけたのが、「roulette_wheel_selection」です。
選んだ理由としては、ExampleがすでにProvider化されているソースが記載されていたので、取り入れやすいかなーと思った。それだけ。見栄えはあまり良くない。
Exampleのソースは、括弧の数?が合わず少し修正しましたが、概ねそのまま動作しました。
しかし、ルーレット自体が回るのではなく、針だけが回るのが、見た目にしょぼい感が否めません。
また、ルーレットのスタートはどうすんの?って思って色々やってみたところ、ルーレットの真ん中をタップすると針が回るようです。これも説明書いておけばいいけど、何かルーレットっぽくない。
選択値のラベルが、ルーレット内ではなく、ルーレット外に表示されているのも、カッコ悪い。
あと、致命的なのが、「選択中…」などのタイトル的に表示される表記が中国語で、しかも固定で表示されて変更できない…
うーん、却下w
roulette・・・本命
次に目をつけたのが、王道の「roulette」です。
選んだ理由としては、
- 他の2つが却下になったため。
- ラベルもルーレット内にあり、見た目は悪くない。
- 針が回るのではなく、ルーレット自体が回るので悪くない。
ただ、Stateクラスにwith後付けするような使い方(Mixinsというらしい)のExampleなので、Provider化するのが面倒だなーって思っていますが、とりあえずこれしかないので、動かしてみることにしました。
ルーレットの結果は?
Exampleのソースで問題なく動かせたのですが、ルーレットの結果はどこにあるの?って思って、探していたのですが、よくわからず、小一時間かかってわかったのがココ。
floatingActionButton押下時にルーレットを回す「rollTo」メソッドが呼び出されているのですが、引数にリテラルで「3」と指定しているところ(int targetIndex)が、ルーレットの結果でした。
floatingActionButton: FloatingActionButton(
// Use the controller to run the animation with rollTo method
onPressed: () => _controller.rollTo(
3,
clockwise: _clockwise,
offset: _random.nextDouble(),
),
child: const Icon(Icons.refresh_rounded),
),
ん?先に結果を渡して回すんかい!出来レースだったみたいですw
で、clockwiseは時計回りか、反時計回りかを指定するところ。trueだと時計回りのよう。
offsetは何かというと、例えば「3」のところのど真ん中で止まってしまうと不自然なので、ちょっとずらして止めるところの指定みたいです。「0.5」だと「3」のど真ん中で止まります。
ルーレット終了イベントは?
ルーレットの回転が終わって、次の処理に進むときのイベントは、rollTo().then()で使えます。
6つの選択肢がある場合、結果(targetIndex)としては0〜5を指定します。
ランダムな値を生成して、ルーレットの結果を先に決めるため、「RandomUnion」というクラスを用意してみました。
RandomUnionはインスタンス作成時に、コンストラクターに選択肢の数を渡すと、それ以下の値のランダム値(randomValue)を生成します。ランダム値を整数部(randomValueInt)と小数点以下部(randomValueUnderPoint)に分けて取得できるようにしています。
整数部(randomValueInt)をtargetIndexに、小数点以下部(randomValueUnderPoint)をoffsetに渡してあげるようにしてみました。
floatingActionButton: FloatingActionButton(
// Run the animation with rollTo method
onPressed: () {
// 結果を先に生成する 0.0 <= result < 6.0
var result = RandomUnion(6);
// 結果を仕込んでルーレットを回す
_controller.rollTo(
result.randomValueInt, // ランダム値の整数部を結果とする
clockwise: _clockwise,
offset: result.randomValueUnderPoint, // ランダム値の小数点以下をオフセットとする
).then((_) => {
// ルーレットが止まった時の処理
debugPrint(result.randomValue.toString())
});
},
child: const Icon(Icons.refresh_rounded),
),
class RandomUnion {
// ランダムな数値 例:最大値=6 の場合 0.0 <= randomValue < 6.0
double randomValue = 0.0;
// ランダムな数値の整数部のみ
int randomValueInt = 0;
// ランダムな数値の小数点以下
double randomValueUnderPoint = 0.0;
/// コンストラクター
/// 最大値を渡す。例:最大値=6 の場合 0.0 <= randomValue < 6.0
RandomUnion(int lessThanValue) {
randomValue = lessThanValue * Random().nextDouble();
randomValueInt = randomValue.toInt();
randomValueUnderPoint = randomValue - randomValueInt;
}
}
あとは、このExampleソースをProvider化したいのですが。。。無理そうなら別ページで呼び出すようにしてみます。