LoginSignup
8
3

More than 5 years have passed since last update.

PowerAppsで円スライダーを作った話

Last updated at Posted at 2018-12-02

PowerAppsに標準で用意されているスライダーは1方向です。
勉強中に2次元いけるんじゃない?って思って試したら出来たので共有します。
ちょっと動きが不安定なので改善の余地はありますが、考え方が伝わればよいかなと思います。

こんなのできました

円のスライダー
円スライダー2.gif

どうやって作ったか

スライダーの位置をずらしながら円の上を操作しているように見せかけています。
スライダーを透明にしているので、実際に見えているボタンとレールは単なるアイコンで実際にそれを操作しているわけではありません。

円スライダー解説用1.gif

詳細

初期設定をどこかで行います。
今回はReset用のボタンを挿入してOnSelectに配置しました。

btnReset.Onselect
UpdateContext({Const:{sRight:1,sTop:2,sLeft:3,sBottom:4}});
UpdateContext({radius:100,angle:180,centerX:500,centerY:300,sliderPos:Const.sLeft,sliderThickness:50,tStart:false});
Reset(Slider);
UpdateContext({nicoX:1000,nicoY:300}) // スマイルアイコン用

スライダーの位置をボタンとともに動かす

ボタンを表示している位置とスライダーの位置を合わせるため、ボタンに重なるようにスライダー動かします。
また1方向にしか動かせないスライダーを2方向に動かすため、一定条件を満たしたときに縦と横を切り替えます。
今回はSlider.Max=145、Slider.Min=35としたため、Slider.Vale>135、Slider.Vale<45の時に縦と横を切り替えるようにしました。スライダーの上下左右の情報はsliderPosに保管しています。
また、切り替えはスライダーだけでは実装できないのでタイマーを挿入して以下のように設定しスライダーを監視させます。
タイマーがsliderPosを変更していきます。

SliderPosTimer
Start = tStart
Duaration = 10
Repeat = true
OnTimerStart = If(Slider.Value>135,If(sliderPos=Const.sTop || sliderPos =Const.sLeft,UpdateContext({sliderPos:Mod(sliderPos,4)-1}),UpdateContext({sliderPos:Mod(sliderPos,4)+1})));
               If(Slider.Value<45 ,If(sliderPos=Const.sTop || sliderPos =Const.sLeft,UpdateContext({sliderPos:Mod(sliderPos,4)+1}),UpdateContext({sliderPos:Mod(sliderPos+2,4)+1})));
               UpdateContext({angle: Switch(sliderPos,Const.sRight,Mod(Slider.Value-90,360),Const.sTop,-Slider.Value+180,Const.sLeft,-Slider.Value+270,Const.sBottom,Slider.Value+180)})

sliderPosの値を受けて、スライダーを動くようにします。

Slider
X = centerX + Switch(
    sliderPos,
    Const.sRight,
        Cos((-Slider.Value+90)/180 * Pi()) * radius-sliderThickness/2,
    Const.sLeft,
        Cos((Slider.Value+90)/180 * Pi()) * radius-sliderThickness/2,
    -radius
)
Y = centerY + Switch(
    sliderPos,
    Const.sTop,
        Sin((-Slider.Value)/180 * Pi()) * radius-sliderThickness/2,
    Const.sBottom,
        Sin((Slider.Value)/180 * Pi()) * radius-sliderThickness/2,
    -radius
)
Width  = If(Mod(sliderPos,2)=1,sliderThickness,radius*2)
Height = If(Mod(sliderPos,2)=0,sliderThickness,radius*2)
Layout = If(Mod(sliderPos,2)=1,Vertical,Horizontal)
Visible = false // テスト中はtrueのほうがよい
Onselect = UpdateContext({tStart:false}); 
           UpdateContext({tStart:true})  // タイマーを起動する
OnChange = UpdateContext({tStart:false}) // タイマーを停止する
Min = 35
Max = 145

見せかけのボタンとレールを追加する。

円を二つ用意してボタンとレールのようにします。

SliderBtnCircle
X = centerX-15 + Cos(
    Switch(
        sliderPos,
        Const.sRight,
            Mod(Slider.Value-90,360),
        Const.sTop,
            -Slider.Value + 180,
        Const.sLeft,
            -Slider.Value + 270,
        Const.sBottom,
            Slider.Value + 180
    )/180 * Pi()
) * radius
Y = centerY-15-Sin(
    Switch(
        sliderPos,
        Const.sRight,
            Mod(Slider.Value-90,360),
        Const.sTop,
            -Slider.Value + 180,
        Const.sLeft,
            -Slider.Value + 270,
        Const.sBottom,
            Slider.Value + 180
    )/180 * Pi()
) * radius
SliderRailCircle
X = centerX-radius
Y = centerY-radius

以上で円のスライダーが完成します。

スマイルマークを動かす

ここからは蛇足ですが、スマイルマーク(iconSmile)を動かすには以下の設定をすればOKです。

SliderPosTimer.OnTimerEnd
UpdateContext({nicoX:nicoX+Cos(angle/180*Pi())*10});
UpdateContext({nicoY:nicoY-Sin(angle/180*Pi())*10})
iconSmile
X = nicoX
Y = nicoY

課題

スライダーの円をなぞる分には問題がないのですが、ちょっとずれたりするとボタンが暴れます。
もう少し位置や縦横の切り替えタイミングを調整すれば解決できるかもしれません。
仕組みもまだまだ複雑なのでもっと簡略化したいです。手ごろに使えるようなところまで落とし込みたいですね。
(行列使えばいける・・・?)

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3