I've created an application for Mac that uses a horizontal resize view (technically a BWToolkit resize view) that is linked to a toggleCollapse button. After collapsing and expanding the panel a few times, this happens (see image) right table-view should be flush with panel divider. Any one have any info on why this is happening. I've carefully adjusted my alignment and anchors to be correct but it seems like this is a weird issue that bugs out the view?
EDIT: Is anyone NOT having this issue? Any input would be helpful! Maybe I just need to start fresh?
This is a known bug in BWSplitView itself, and is related to how view animation and timers interact in that view. The details are covered here:
http://bwalkin.lighthouseapp.com/projects/36323/tickets/34-split-view-doesnt-resize-subview-properly-during-a-toggle-uncollapse-after-manual-collapse
Basically, before the view is animated, autoresizesSubviews is unset, so that the view can be collapsed/expanded without affecting the contents; a timer is then scheduled to restore the autoresizesSubviews property for when the animation has completed. But (of course) the animation may sometimes finish ever so slightly earlier, or later, than the scheduled timer fires; so autoresizing is switched on before the animation has completed, resulting in a few pixels resize. As you've probably seen, the subviews tend to move around a bit as the view is collapsed and uncollapsed.
The "full" fix for this would be to restore autoresizing when the CAAnimation has completed using a callback, but this hasn't been implemented yet. However, in that thread "Robert Payne" has posted a version of BWSplitView.m which uses a slightly different approach - the view sizes are recorded before collapsing, and restored after expanding. I applied this patch myself (I think it won't compile at first - but it's a simple matter of an undeclared variable?) and can confirm it does fix the problem.
Let me know if you'd like a BWSplitView.m which compiles successfully, or a copy of the compiled framework.
Related
In Mavericks, Apple introduced responsive scrolling architecture in NSScrollView. This feature adds a smart way for generating overdraws and decouples handling of the incoming scroll events from the main event loop into a separate one. This topic is described in detail in the session 215 from WWDC 2013.
Because of the different event model, the scroll events no longer go through the scrollWheel(with:) method. In fact, if you override this method in the NSScrollView subclass, you opt-out from the responsive scrolling architecture completely and fall back to the legacy model.
In my NSScrollView I'd like to implement an interaction for magnification using scrolling while holding the command key. This can be observed in MindNode or OmniGraffle apps. The standard way to do this would be overriding scrollWheel(with:) and checking the modifierFlags on each scroll event. As described above, this would cause an opt-out from the responsive scrolling model.
I wonder whether there is a way to implement this interaction while also preserving the responsive scrolling?
What I have already achieved/tried:
In my NSScrollView subclass I have overridden scrollWheel(with:) and am returning true from the static property isCompatibleWithResponsiveScrolling in order to force the participation in responsive scrolling.
This way I am able to check the first scroll event for the modifier flags. If the command key is NOT pressed, I simply pass the event to super and let the NSScrollView do its thing. If the command key is pressed, I go a different route and track next scroll events on the window to do the magnification.
The problem is when one of these tracking loops is running and the user changes the press state of the command key (either presses it or releases it).
The switch from magnification to scrolling (on command key release) is simple, since the tracking loop is fully under my control.
The switch from scrolling to magnification (on command key press) is more tricky, because I cannot check the scroll events. I have overridden flagsChanged(with:) and can observe when this moment happens but I have not found a way to end the scrolling. This SO question asks about ending/disabling scrolling but has no answer yet.
I’m going to answer here instead of in comments, since I have more data.
There are two issues with “Responsive scrolling”:
(1) A few years ago there was a bug — a difference in how accelerated responsive scrolling was vs. legacy scrolling. By accelerated I mean the distance the document would travel for any given amount of movement of the fingers on the trackpad — legacy scrolling didn’t move the document as much so it felt sluggish. I reported this and it seems to have been fixed in 10.14, at least.
⑵ As near as I can tell from my research and talking to Apple people “Responsive scrolling” was designed to make scrolling more consistent even when an application is hogging the main thread (which would normally block the flow of events) — it processes scroll wheel events on a background thread instead and then messages the main thread with them. Since this still involves the main thread being called per scrolling event (or scrolling events being coalesced) I’m not clear what situations this is a win in. There may be some extra magic where the scrollview will draw more of the document from the cached content of you implement the optional caching stuff.
In my app I’m actually using the scrollview with a dummy (transparent) document and I take its scroll events and move around a SceneKit camera. Since my scene changes dramatically as you scroll around there’s no benefit to trying to pre-render outside the visible rect.
So in my case I no longer perceive any performance difference between responsive and legacy scrolling (although I did back when I filed the bug).
It seems that my view-based OutlineView try to re-render text every time user scrolling. I think that was because it tried to save memory by re-using rows that fall outside of visible rectangle, then re-render new data to those old views. How can I disable this? I'm willing to sacrifice memory to archive this so that I can get better scrolling performance. (I have tried with various optimize like layer or so, but no luck).
EDIT: There is another question with same purpose as mine here How to make NSTableView not reuse TableCellViews, but no answer yet :(
I think you are confused -- it doesn't re-render the text. The table only shows views for the visible area (caveat below), and pulls in new views as you scroll -- potentially re-using old views.
You provide the view. Use the delegate method viewForTableColumn:row: and return your own cached view for a given row.
But that isn't going to prevent drawing; the view will likely still get marked dirty and draw.
I don't think you are asking the right question. It sounds like you have a performance problem. To help you with that, we'd have to see samples or instrument traces.
Caveat: Responsive Scrolling will pull in views that are in the non visible area. See the AppKit release notes about this.
corbin
I'm experiencing what I think is a very strange issue.
First and foremost, my application moves UI elements around the screen using the following example command:
[view setFrame:NSRectFromCGRect(CGRectMake(0, 0, 0, 0))];
I give my users the possibility to resize the application's NSWindow to one other size with this command:
[self.window setFrame:NSRectFromCGRect(CGRectMake(0, 0, 0, 0)) display:YES animate:YES];
When in 'resized mode', I obviously change every single setFrame command to the appropriate coordinate system.
However, there is an issue: when (if) the user switches back to the original NSWindow size by clicking on the button again, and the application performs the UI movements again, the views that are moved around are not in the location they are supposed to be in.
To clarify: my UI movement code runs fine, over and over, either in normal or resized mode. However, if I switch from one to the other, some items (not all) are shifted.
What could be causing this strange behavior? I'm using the same exact commands (within each screen resolution), and NSLogs confirm the UI elements are in the location that I specified; however, this location is clearly not the one I'm attempting to move to.
Has anyone experienced a similar issue here?
You've probably set some sort of autoresizing mask in Interface Builder that's interfering with your manual placements. Go in to your nib and remove all the springs and struts in the Size inspector. Although if possible you should let autosizing handle the placement, or move to Auto Layout which was introduced in 10.7.
After days and days of trying to figure this out, I've come to the following conclusion: the resizing code simply wasn't working.
I confirmed this by using NSLog after I resized my window. In the end, I changed my resizing code by adding the following line after the traditional setFrame: method:
[self.window setContentSize:NSSizeFromCGSize(CGSizeMake(desiredWidth, desiredHeight))];
I think this is a new spin on an old question, but I'm completely stuck here.
In my app, I have a UITableView with 650 cells, each with a custom 16x16 RGB icon. On most recent iOS devices, loading all of those icons into memory before displaying the table works totally fine, but on older hardware, I'd like to implement a lazy load system that only loads icons it needs.
I've implemented the Apple LazyTableImages example, (which uses a UIScrollView delegate to determine when the table stops moving to load the visible icons), but I've run into another snag.
My UITableView also has a section index display (ie the list of labels on the right hand side you can swipe up and down to scroll quickly), and the LazyTableImages example hasn't taken this into account.
If I scroll using the index, the images won't lazy-load. :(
As far as I can see, the scroll index doesn't actually have any delegate events it triggers.
So I'm wondering, has anyone else tried to implement lazy-loading on a table with a scroll index? Is there any way to track the index and find out if the user has interacted with it?
Thanks!
After buzzing around a few of my iOS developer buddies, I came up with a solution that worked well enough.
I set it up so that in addition to the icons being loaded from the UIScrollView delegates, an NSTimer object will periodically call a method that checks the currently visible table cells ([UITableView indexPathsForVisibleRows]) every .5 seconds, and loads any icons on the screen that haven't been loaded yet in a single separate thread.
I tried to make the solution as efficient as possible, so I made sure the timer was only active when the tableView was visible and stationary, and I liked it since it meant that every visible icon regardless was addressed.
One thing I discovered was that if the tableView was reloaded while the thread was looping through the visible cells (rare, but was possible), it would crash. The solution to this was to make sure each cell data source entry was retained while the icon was being loaded.
I have a custom-subclassed NSWindow which is made into a fullscreen borderless window with NSBordelessWindowMask. It works perfectly, and as far as I can see, there are no problems or anything strange about the window itself.
What I am trying to figure out why exactly a custom-subclassed NSView within the aforementioned window is respoding to setFrame: requests in an odd manner. Rather than simply taking the requests as they are, it seems they are going through some sort of change - for example, setting the x coordinate to 25 and the width to 800 does not put the right edge of the view at 825 as one would expect. Instead, the width/height grow along with the x and y coordinates, even though they report the proper numbers when asked by [view frame].size.width with an NSLog.
The sizing masks should not be an issue, as I have disabled them entirely and get the same result with several different configurations.
Has anybody else experienced this type of behavior?
Without seeing the code that you're using to create the window/view it's hard to know what might be causing this. That said, if you're targeting Leopard of later, there's a built in way to make a view go fullscreen which might help. The method is enterFullScreenMode:withOptions: on NSView. If you want the entire window to go fullscreen you can call this on the contentView of the the window. This may not fix your bug, but it should simplify things a bit at least.