SwiftUI onHover doesn't register mouse leaving the element if mouse moves too fast
I resolved this issue today with a tracking area on an empty NSView. This is tested in a semi-complex and quickly refreshing grid view, which previously had the same behavior you pictured. About 75 views have this modifier applied in the GIF capture in this gist, most with zero border to each other.
Sugar for call site
import SwiftUI
extension View {
func whenHovered(_ mouseIsInside: @escaping (Bool) -> Void) -> some View {
modifier(MouseInsideModifier(mouseIsInside))
}
}
Representable with empty tracking view
struct MouseInsideModifier: ViewModifier {
let mouseIsInside: (Bool) -> Void
init(_ mouseIsInside: @escaping (Bool) -> Void) {
self.mouseIsInside = mouseIsInside
}
func body(content: Content) -> some View {
content.background(
GeometryReader { proxy in
Representable(mouseIsInside: mouseIsInside,
frame: proxy.frame(in: .global))
}
)
}
private struct Representable: NSViewRepresentable {
let mouseIsInside: (Bool) -> Void
let frame: NSRect
func makeCoordinator() -> Coordinator {
let coordinator = Coordinator()
coordinator.mouseIsInside = mouseIsInside
return coordinator
}
class Coordinator: NSResponder {
var mouseIsInside: ((Bool) -> Void)?
override func mouseEntered(with event: NSEvent) {
mouseIsInside?(true)
}
override func mouseExited(with event: NSEvent) {
mouseIsInside?(false)
}
}
func makeNSView(context: Context) -> NSView {
let view = NSView(frame: frame)
let options: NSTrackingArea.Options = [
.mouseEnteredAndExited,
.inVisibleRect,
.activeInKeyWindow
]
let trackingArea = NSTrackingArea(rect: frame,
options: options,
owner: context.coordinator,
userInfo: nil)
view.addTrackingArea(trackingArea)
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
static func dismantleNSView(_ nsView: NSView, coordinator: Coordinator) {
nsView.trackingAreas.forEach { nsView.removeTrackingArea($0) }
}
}
}
Change mouse cursor over inactive NSWindow
Now I finally found a solution that works. I don't know if this will bite me in the tail in the future but at least this seem to work when testing.
Thanks Wil for the example it got me half way there. But it was only when I finally combined it with resetCursorRects and also defined a cursor rect in each view with the specific cursor. This took me a long time to figure out and I don't know if the solution is optimal (suggestions of improvement are welcome)
Below is the full example that made it work for me in the end (self.cursor is an instance of the cursor)
- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil];
[self addTrackingArea:trackingArea];
[self.window invalidateCursorRectsForView:self];
}
- (void)resetCursorRects {
[super resetCursorRects];
[self addCursorRect:self.bounds cursor:self.cursor];
}
- (void)mouseEntered:(NSEvent *)theEvent {
[super mouseEntered:theEvent];
[self.cursor push];
}
- (void)mouseExited:(NSEvent *)theEvent {
[super mouseExited:theEvent];
[self.cursor pop];
}
Hover leaving Animation
I saw so a right answers above but here is another solution by JavaScript using mouseover
and mouseleave
events, but I notice you to use .hover
, because it's simple.
div {
width: 50px;
height: 50px;
background: purple;
transition: all 1s;
}
<div id="d"></div>
const d = document.getElementById("d");
d.addEventListener("mouseover",()=>{
d.style.boxShadow = "5px 5px 2px black";
})
d.addEventListener("mouseleave",()=>{
d.style.boxShadow = "0px 0px 0px";
})
Javascript and Database Connectivity
It is possible!
with the new html5 feature, js can connect through WebSql.
a live example : http://html5demos.com/database
the syntax is similar to all the other sql wrappers :
var db = openDatabase('mydb', '1.0', 'my first database', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE foo (id unique, text)');
});
it is currently supported by chrome, safari and opera
here's a tutorial : http://html5doctor.com/introducing-web-sql-databases/
How to prevent sticky hover effects for buttons on touch devices
Since this part of CSS Media Queries Level 4 has now been widely implemented since 2018, you can use this:
@media (hover: hover) {
button:hover {
background-color: blue;
}
}
Or in English: "If the browser supports proper/true/real/non-emulated hovering (e.g. has a mouse-like primary input device), then apply this style when button
s are hovered over."
For browsers that do not have this implemented (or didn't at the time of this original answer), I wrote a polyfill to deal with this. Using it, you can transform the above futuristic CSS into:
html.my-true-hover button:hover {
background-color: blue;
}
(A variation on the .no-touch
technique) And then using some client-side JavaScript from the same polyfill that detects support for hovering, you can toggle the presence of the my-true-hover
class accordingly:
$(document).on('mq4hsChange', function (e) {
$(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
Make div appear and change the whole html to be darker
HTML--
<a id="some-button" href="#">click me</a>
<div id="overlay-back"></div>
<div id="overlay"><span>YOUR HTML GOES HERE</span></div>
CSS--
html, body {
width : 100%;
height : 100%;
}
#overlay-back {
position : absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
background : #000;
opacity : 0.6;
filter : alpha(opacity=60);
z-index : 5;
display : none;
}
#overlay {
position : absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
z-index : 10;
display : none;
}
JS--
$('#some-button').on('click', function () {
$('#overlay, #overlay-back').fadeIn(500);
});
Then just add your youtube video embed code to the overlay
div and style it appropriately to put it where you want on the page.
Here is a demo: http://jsfiddle.net/EtHbf/1/
Related Topics
What Is 'Where Self' in Protocol Extension
How to Make Apple Sign in Revoke Token Post Request
Swift Programming Nserrorpointer Error etc
Swift - How to Create a View with a Shape Cropped in It
How to Change the Uinavigationbar Title's Position
How to Use Dispatch Groups to Wait to Call Multiple Functions That Depend on Different Data
Target Parameter in Dispatchqueue
Cannot Read the Nfc Chip of the Epassport Using iOS13
My Data Changes in Uitableviewcell When I Scroll Down and Get Back
iOS 11 Uirefreshcontrol with Navigationbar Largetitle and Searchcontroller Disappearing
Transparent Nscollectionview Background
Animate the Fractioncomplete of Uiviewpropertyanimator for Blurring the Background
Why Does Swift Return an Unexpected Pointer When Converting an Optional String into an Unsafepointer
How to Represent Magnitude for Mass in Swift