Modifier の順番の大切さに気付いたのでメモ
気づき
ここでつくった、ドラッグできるフレームに対して、マウスの位置に合わせてカーソルを変更しようと思ったのがきっかけでした。
マウスの位置の変更に対する動作として、.onHover を使用することができます。
この .onHover を使って、入ったとき、出たときにカーソルを変えるようにしました。
onHover部分
.onHover(perform: { isIn in
isIn ? NSCursor.pointingHand.set() : NSCursor.arrow.set()
})
良い感じです。
全体で見るとこんな感じでした。
コード
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位置を調整したコード
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