特定の値をユーザーにプレゼントしたいときに、ちょっと楽しくしたいなーと思って、ルーレットで当たった数値をプレゼントしようかなーって思いつきました。

まさかFlutterのパッケージにルーレットなんて提供されていないよなーってダメ元で探してみると、結構いろんなパッケージが用意されていたんです。

flutter_spinning_wheel・・・却下

まず最初に見栄えだけで目をつけたのが、「flutter_spinning_wheel」です。

選んだ理由としては、

  1. 画像を使ってゴージャスなルーレットを回すことができるようです。
  2. 抽象クラスを使わずとも単独で使えるので、ProviderによるModel化も容易そう。

早速、サンプルプロジェクトを作ってExampleのソースをコピペして動かそうとすると、パッケージ自体が古く、Nullセーフ化されていないよーってエラーが出て、結局使えませんでした。

roulette_wheel_selection・・・却下

次に目をつけたのが、「roulette_wheel_selection」です。

選んだ理由としては、ExampleがすでにProvider化されているソースが記載されていたので、取り入れやすいかなーと思った。それだけ。見栄えはあまり良くない。

Exampleのソースは、括弧の数?が合わず少し修正しましたが、概ねそのまま動作しました。

しかし、ルーレット自体が回るのではなく、針だけが回るのが、見た目にしょぼい感が否めません。

また、ルーレットのスタートはどうすんの?って思って色々やってみたところ、ルーレットの真ん中をタップすると針が回るようです。これも説明書いておけばいいけど、何かルーレットっぽくない。

選択値のラベルが、ルーレット内ではなく、ルーレット外に表示されているのも、カッコ悪い。

あと、致命的なのが、「選択中…」などのタイトル的に表示される表記が中国語で、しかも固定で表示されて変更できない…

うーん、却下w

roulette・・・本命

次に目をつけたのが、王道の「roulette」です。

選んだ理由としては、

  1. 他の2つが却下になったため。
  2. ラベルもルーレット内にあり、見た目は悪くない。
  3. 針が回るのではなく、ルーレット自体が回るので悪くない。

ただ、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化したいのですが。。。無理そうなら別ページで呼び出すようにしてみます。

About The Author

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA