実装方法が分かるまで迷うことが多かったので、方法を大雑把に共有します。
re-natalに関する記事ですが、react-nativeで作られる場合も参考になる部分があると思います。
使ったもの
- re-natalで作っているアプリ
re-natalとはreact-nativeをclojurescriptで開発できるフレームワークです。
re-natal-esp32control-appを開発しています。 - 上記アプリの開発環境
$ re-natal --version 0.4.0 $ react-native -v react-native-cli: 2.0.1 react-native: 0.43.4
コード
ジョイスティックのコードです。触れた場所によって、左上だと {:x -1 :y -1}、中心だと {x: 0 :y 0}、右上だと {:x 1 :y 0}のような値を、第1引数のon-moveに渡して実行します。
画面から手を離すと、第2引数のon-releaseを実行します。
(def ReactNative (js/require "react-native"))
(def view (r/adapt-react-class (.-View ReactNative)))
(def image (r/adapt-react-class (.-Image ReactNative)))
(defn rate-x-y [p-x p-y view-x view-y view-w view-h]
(let [harf-w (/ view-w 2)
harf-h (/ view-h 2)
rate-x (/ (- p-x view-x harf-w) harf-w)
rate-y (/ (- p-y view-y harf-h) harf-h)]
{:x rate-x :y rate-y}))
(defn joystick [on-move on-release]
(let [view-x (r/atom nil)
view-y (r/atom nil)
view-w 300
view-h 300
joystick-ref (r/atom nil)
update-view-x-y #(.measure @joystick-ref (fn [fx fy w h px py]
(reset! view-x px)
(reset! view-y py)))
action (fn [evt]
(-> (rate-x-y (.-pageX (.-nativeEvent evt))
(.-pageY (.-nativeEvent evt))
@view-x @view-y view-w view-h)
(on-move)))]
(r/create-class
{:reagent-render
(fn []
[image
{:source joystick-img
:style {:resize-mode "cover"
:background-color "#beb"
:align-self "center"}}
[view
{:ref "joystickArea"
:style {:width view-w
:height view-h}
:on-layout #(update-view-x-y)
:on-start-should-set-responder (fn [] true)
:on-move-should-set-responder (fn [] true)
:on-responder-grant #(action %)
:on-responder-move #(action %)
:on-responder-release #(on-release)}]])
:component-did-mount
#(reset! joystick-ref (-> (.-refs %)
(.-joystickArea)))})))
(defn joystick-action [{:keys [x y]}]
(prn :x x)
(prn :y y))
(defn [] some-page
..
[joystick joystick-action #(joystick-action {:x 0 :y 0})])
参考コミット
Add joystick
Add image for joystick
実装時の注意点: androidにおけるlocationXの不具合
react-native0.43.4のandroid環境では、on-responder-moveなどのイベントに含まれるnativeEventのlocationXとlocationYが更新されない不具合があります。[Android] onResponderMove nativeEvent locationX does not change
そのため、joystickの左上の座標をon-layoutで取得し、それを使ってpageXとpageYからlocationXとlocatoinYに相当する値を計算しています。
まとめ
viewのresponcer-moveを利用として、ジョイスティックを実現しました。locationXに関する不具合が解決すれば6行くらいコードを短くできますが、とりあえず欲しい機能を作れたので満足です。
共有する情報は以上です。
参考
Gesture Responder SystemReactNativeソースコードリーディング <View>
View
React-Native Tinder like cards
React Native: Getting the position of an element
[Orientation] Re-Layout on orientation change

0 件のコメント :
コメントを投稿