Modifier の順番の大切さに気付いたのでメモ
気づき
ここでつくった、ドラッグできるフレームに対して、マウスの位置に合わせてカーソルを変更しようと思ったのがきっかけでした。
マウスの位置の変更に対する動作として、.onHover を使用することができます。
この .onHover を使って、入ったとき、出たときにカーソルを変えるようにしました。
onHover部分
1 2 3 4 5 |
.onHover(perform: { isIn in isIn ? NSCursor.pointingHand.set() : NSCursor.arrow.set() }) |
良い感じです。
全体で見るとこんな感じでした。
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
struct FrameView: View { @State private var frameOffset: CGSize = CGSize.zero @State private var frameSize: CGSize = CGSize(width: 300, height: 200) @State var dragStartPosition: CGPoint = CGPoint.zero @State var isDragging:Bool = false var body: some View { Rectangle() .fill(Color.gray.opacity(0)) .border(Color.red, width: 3) .contentShape(Rectangle().inset(by: -10)) .frame(width: frameSize.width, height: frameSize.height) .offset(frameOffset) .gesture(DragGesture() .onChanged { gesture in if self.isDragging == false { self.dragStartPosition = CGPoint(x: self.frameOffset.width, y: self.frameOffset.height) self.isDragging = true } self.frameOffset = CGSize(width: gesture.translation.width + self.dragStartPosition.x, height: gesture.translation.height + self.dragStartPosition.y) } .onEnded { gesture in self.isDragging = false }) .onHover(perform: { isIn in _ = isIn ? NSCursor.pointingHand.set() : NSCursor.arrow.set() }) } } |
.onHover の位置は特に考えずに、なんとなく(汗)最後に追加していたんですが、問題が発生しました。
一度 Rectangle をドラッグで移動させた後に、マウスを Hover 位置に移動させても、期待と違う場所でマウスカーソルが変わるんです。
期待通りに変更されていないとき
期待してないのに変更されているとき
問題分析
よ〜くみてみると、Rectangleを移動した後も、どうやら、Rectangleの初期位置に対して、マウスカーソルが制御・変更されているようだと気づきました。
で、コードを確認してみると、そうです、onHover が一番最後にあり、offsetで移動された後のRectangle(というかborder)に対して処理しているのでした。
解決策: onHover を適用する順番大事
問題点はわかったので、解決策は簡単です。onHover を offset の前に移動させて解決。
onHover位置を調整したコード
# ついでに、ドラッグ中のカーソルも調整してます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
Rectangle() .fill(Color.gray.opacity(0)) .border(Color.red, width: 3) .contentShape(Rectangle().inset(by: -10)) .frame(width: frameSize.width, height: frameSize.height) .onHover(perform: { isIn in isIn ? NSCursor.pointingHand.set() : NSCursor.arrow.set() }) .offset(frameOffset) .gesture(DragGesture() .onChanged { gesture in if self.isDragging == false { self.dragStartPosition = CGPoint(x: self.frameOffset.width, y: self.frameOffset.height) self.isDragging = true NSCursor.pointingHand.set() } self.frameOffset = CGSize(width: gesture.translation.width + self.dragStartPosition.x, height: gesture.translation.height + self.dragStartPosition.y) } .onEnded { gesture in self.isDragging = false NSCursor.arrow.set() }) |
まとめ:位置に関係する modifier は、offset 等の modifier との適用順番に注意することが必要
Modifier の適用順序で background や fill で色が塗られる位置が変わることは知っていましたが、改めて再認識ました。
ということのメモでした。
Sponsor Link