THE PROBLEM:
I have an NSScrollView. I'm using it to implement a custom "Table View" with rows of data that are actually NSViews. (Note: this is not an instance of NSTableView.)
As I scroll vertically (there is no horizontal scrolling), I use a boundsChanged notification to add (as subviews of the scrollView's contentView) the NSViews that become visible (the ones with frames that intersect the scrollView's document visible rect) and to remove the ones that are no longer visible (frames outside of the scrollView's visible rect.)
The process works wonderfully except when it comes to inertial scrolling. If I have my cursor over cell X and I flick the trackpad to scroll downwards FAST with inertia, cell X quickly leaves the visible rect and, as such, is removed from the scrollView's contentView. BUT, that kills inertial scrolling. If I do NOT remove cell X as a subView, then inertial scrolling works perfectly.
WHAT I NEED:
A way to keep inertial scrolling while still removing the NSView that the cursor happened to be on top of when the user started the scrolling gesture.
WHAT I'VE TRIED:
I've looked at NSResponder's method:
-scrollWheel:(NSEvent *)theEvent
The default implementation passes scrollWheel to the next responder. So, I subclassed NSScrollView and implemented this method to try to stop it from passing the scrollWheel event to the individual subViews inside the scrollView's contentView. Didn't work.
So then I went into my NSViews (the ones I'm adding to the contentView) and overrode scrollWheel to pass the event back to the scrollView itself. Didn't work.
I still get scrolling in both cases, but not with inertia.
Any ideas? Thanks!
I haven't done this exact thing in Cocoa, but I'd probably be thinking about simply recycling your NSView object, as soon as its off the visible rect, by removing its subviews, then changing its frame to be in place to scroll back onto the visible rect from the top.
You can obviously do this by simply updating its frame, and avoid having to remove and re-add it to the NSScrollView.
Related
I have an NSPopover that I want to resize with animation. In my case, setContentSize works, but without animation (apple says that animation is not guaranteed).
I'm investigating the use of NSViewAnimation. With this approach, the popover does resize with animation, but this requires setting the popover (window) frame origin, not just its size.
Here lies the problem, I need to know the edge to which the popover is "attached" to its positionRect because this edge should not move during resizing.
To this end, have set a rather inelegant method that involves comparing the position of the popover to that of the view to which it is attached in screen space, but I'd like to know if there is a more elegant solution to reach my goal (suggestions in obj-c are preferred, I'm already old.)
I have an NSCollectionView with a vertical NSCollectionViewFlowLayout. I display rectangular icons in it.
I also have a slider in the UI, and when that changes, I adjust the minItemSize, which I then use in collectionView:itemForRepresentedObjectAtIndexPath: to create an equally sized NSImageView to the returned NSCollectionViewItem's imageView. Then I reload the view by invoking reloadData.
After that, the view shows the icons in the new size as intended.
The problem is, provided I have more data to show than fits into the current scoll view, that when the General System Preferences are set to Show scroll bars: When scrolling, the scrollbar disappears after reloading the collection view, and trying to scroll with the trackpad leads to a bounce that's telling me that the scroll view thinks that the content is just what's visible, nothing more to scroll.
But as soon as I resize the window, which also resizes the collection view inside, the scrollbars come back.
Curiously, if the System Prefs are set to Show scroll bars: Always, then the issue does not appear and the scrolling always works, and the scrollbars always remain visible.
I've tried a lot of things to trigger the re-calculation of the scroll view, such as invalidating the layout of the collection view's layout, the scroll view itself, its content view, and also tried to set their needsLayout to true. Nothing makes this work.
Update: The potential duplicate (NSCollectionView does not scroll items past initial visible rect), neither the collectionView.setFrameSize: nor the window.setFrame: suggestions work for my case (I tried adding these line before and after reloadData).
Even if I force a resize of the window like this, it doesn't bring the scrollbars back, only a manual dragging of the window edges does:
[self.collectionView.window setFrame:NSInsetRect(self.view.window.frame, 1, 1) display:YES];
Also note that in my case, initially the scrolling works, just not after resizing and reloading.
Another finding: When I call selectItemsAtIndexPaths:scrollPosition: after reloadData, then the scrollbar comes back. But only if I pass a non-empty NSSet for the paths. And since I may not have selected any items, this isn't a permanent solution.
If no other ideas come up, I'll try to make a demo project.
I've solved it:
I had to delay the call to reloadData, e.g. by calling it from within the block code of dispatch_async(dispatch_get_main_queue(), ^{ ... });
Before the fix, I did call reloadData right from the setSliderValue: handler, which is bound to the slider's value. It appears that this didn't go well together.
I making an ipad application with screen split in half. Each side contains a container and each container holds UIView.
In the left uiView i have a uiScrollView with multiple elements (customs uiview) inside, like a grid but with scroll, and each element support tap gesture.
When i tap each element they work fine and behave like they are suppose to. lets say they do a NSLog(#"tapped!").
Problem comes when i resize either the entire view that holds the scroll view or the Container like so:
navigationVC.view.frame = CGRectMake(0,0, 338,768);
The tap stops working! But if i resize back to its original frame, tap starts working again.
navigationVC.view.frame = CGRectMake(0,0, originalWidth ,768);
I thought the problem would be the elements re-arrange when i resize the scroll view, but in fact its not.
The frame is being resized when i swipe the entire application either left or right.
EDIT:
Behaviour diagram: http://i.imgur.com/4vKpHLQ.png?1
EDIT2: didnt figure it out yet, but i see now that element bound's are changing when the frame is resized.
Got it!
Problem was that when i resized the scrollView the elements.Bounds where changing too. Then i went digging why... could only be something like a anchor... i then started to change a few properties on my XIB.
Under "Simulated Metrics", changed the "Size" drop-down from "Freeform" (add 150, 45) to "Inferred".
Forced the size on initWithCoder, compiled, and it worked.
Thanks Burhanuddin Sunelwala for trying to debug this with me.
I'm trying to scroll the contents of a UIView using the contentOffset which so far I achieve handling touchesBegan: and touchesMoves: methods of the view, however I get a jumpy effect as I'm changing the bounds of the UIView manually (for example: current position +/- the change of the last position of the finger and the new position)
Is there any easy way to achieve this without manually changing the bounds of the UIView?
IMPORTANT NOTES: I'm not using a UIScrollView because the mentioned UIView has plenty of draggable subviews so if I use a UIScrollView I can't drag because the UIViewScroll scrolling event executes over the subviews events.
Animating the layer of the mentioned UIView causes the contents to move out of control, like if the point of reference had changed somehow.
However I'm always open to suggestions.
I would rather make a UIView container clipping subviews, add the content view which we will drag as a subview and change it's frame. I think it shouldn't have jumpy effect as it must be the same as animating the view frame change.
I have a UIPanGestureRecognizer on a view inside of a UIScrollView. Its function is to move its parent view around when panned. This works perfectly well at 1x and 2x zoom resolutions in the scroll view, but zooming in farther causes them to fail quite often - yet not always.
There is also a long press & double tap recognizer on the same view, which both work fine when zoomed in. Overriding the hitTest method on the scroll view shows that the UIGesture view does in fact receive touches when zoomed in (which is expected, given that these other recognizers work.)
I've tried several combinations of cancelContentTouches & other attributes on the scroll view with no success.
Does anyone have any suggestions?
One workaround I've tried: make your PanGesture'd views siblings of the scroll view, and update their position / scale manually via UIScrollViewDelegate didScroll. You will have to take the scroll view's transform into consideration whenever inspecting the PanGesture views, though (such as getting position information).
Obviously this is not ideal - if anyone else still has a better solution, I'd be happy to hear it!