NSVisualEffectView behind NSScrollView - objective-c

I'm trying to get my NSScrollView (and thus a contained NSOutlineView) to use a blurred NSVisualEffectView with behind-window blending effect.
I've successfully made NSVisualEffectView the container view and placed my scroll view as a subview. This seems to work fine (as long as I make all my table cells, table, nsscrollview etc transparent).
However I've now turned 'Reduce transparency' ON under Accessibility options and all of a sudden I have a black background behind my NSScrollView. I tried subclassing the visual effect view in order to override the drawRect method so that I can draw my own background, but I've just learned this isn't possible or recommended.
How do I detect that Reduce Transparency is ON and how do I make my scrollview opaque dynamically?

Took me a while to find it, but there are a couple of new methods on NSWorkspace that you can use to find out about the preferences for OS X Yosemite’s new accessibility features. -[NSWorkspace accessibilityDisplayShouldReduceTransparency] is the one you want.
By Listening for NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification you can find out when that preference changes. Note that you’ll have to register for that notification on the correct NSNotificationCenter, that is [[NSWorkspace sharedWorkspace] notificationCenter].

It seems as for now I've ended up overriding a parent NSView that contains everything and set a background color for that. This way, when Reduce Transparency is ON, the NSVisualEffectView becomes transparent and the color I end up getting is the one visible below it. This seems to work fine for now.

Despite we have SwiftUI nowadays, in classic Cocoa you can still subclass a custom NSScrollView and use ...
-(NSColor *)backgroundColor {
return NSColor.clearColor;
}
-(BOOL)drawsBackground {
return NO;
}
or set properties of your NSScrollView accordingly if you don't want to subclass like...
yourscrollview.drawsBackground = NO;
yourscrollview.backgroundColor = NSColor.clearColor;
this forces your view to show what is below, and with it also the blurEffect or opaque color of your View or Window that is enclosing your NSScrollView.
This solution has the benefit that you do not have to observe the Workspace for some Notification or VibrancyEffect.

Related

What really happens when a UIView becomes hidden?

This may sound like a weird question, but what exactly happens when it becomes hidden. It would be great to see the UIView source code, but that isn't going to happen.
Here why I'm wondering:
I'm trying to add a UIWindow (a transparent one with userinteractionenabled set to NO) above my application to tint the screen. It works perfectly fine until the user tries to share by SMS using Apples MessageUI.framework. When this happens and the MFMessageComposeViewController or MFMailComposeViewController appears, these view controllers won't receive user input. I've tried tons of thing and the only things that worked, allowing the user to interact with the views, was setting the UIWindow (the one I added) to either an alpha of 0 or set hidden to YES. I want to replicate this without hiding the view, which is why I want to know exactly what happens when the UIWindow (which is a subclass of UIView) is hidden.
There is usually only one window in iOS apps. You're better off using just a UIView for this task instead of a UIWindow. UIWindow adds some view hierarchy and event management capabilities to the UIView class. This functionality is interfering with the expected behavior in your app. I think it will just work if you change the class of this view to UIView instead of UIWindow.

How to disable touch detection on a UIImage?

I am working on an app, which actually works like MSPaint (something to draw lines, etc...).
I got a white UIView, basically where the user draws. On top of this UIView I set up a UIImage, which is gray, with a 0,4 alpha. I want this UIImage to be used as a blotting paper. The idea is to disable touch when the user put the palm of his hand on this area, so it's more comfortable to draw (multitouch is disabled, and with this "blotting paper" you won't draw something accidentally with your palm...)
Even if I bring the UIImage to the front, on top of the view, and even if I disable user interactions on this UIImage, it is still possible to draw on the UIView. , behind the UIImage (kind of strange!)
I do not understand what's happening, because, it seems that the image is transparent, and that the UIView "behind" is still active, even if she's overlaid by the UIImage?!
Any help/indication/idea would be much appreciated! Thank you :-)
Have you set the "userInteractionEnabled" property of the UIImage to "NO" ?
You may actually want to do the opposite. When you disable user interaction or touches, the view basically becomes invisible to touches and they are passed on to the next view.
In your case you do want userInteractionEnabled because you want the view to catch those touches.
You have to disable the user interaction on the UIImageView not the UIImage and it should work.
Edit:
Or you could be sneaky and just add an empty view over it. Use the same frame size so it overlaps perfectly and thats it. You'll be able to see everything you need and it's not a subview of it so there will eb no interaction and touches will get registered but won't have any effect. :P
No better ideas unless you post some of your code...
OK, so I managed to do what I wanted to! YAY!
I got 3 different classes :
StrokesViewController (UIViewController)-the view controller
StrokesView (UIView) - the view where the user draws the strokes.
BlottingPaper (UIView) - the blotting paper.
I got a XIB file "linked" to all three.
I created this new class, called "BlottingPaper", typed UIView. the .h and .m file are actually empty (I do import #import < Foundation/Foundation.h >)
User interaction is enable on BlottingPaper.
I do not use the exclusive touch on this class.
On the XIB file, I just put a view on top of StrokesView. I link it to BlottingPaper (modify the alpha as I want, blablabla...)
And that's it! When I put the palm of my hand on it, it doesn't draw anything on the area where my hand is, but I still can draw with my finger on the rest of the StrokesView!
In addition to Dancreek's response, you should be setting buvard.userInteractionEnabled = YES; so that it captures interaction.
You should also set buvard.exclusiveTouch = YES; so that buvard is the only view which will receive touch events.
When you remove buvard you should set buvard.exclusiveTouch = NO; so that other views will regain their ability to receive touches.

How does UIBarButtonItem know which UIBarStyle the UIToolBar uses?

In Xcode ui builder when one set the UIBarStyle of the UIToolBar (such as BlackTranslucent, for example), the UIToolBarItem matches the background images to it. How does the UIToolBarItem know which style it should use?
I'm trying to do a put a custom colored image on top of the regular background tile (programatically merge a given image on top of the background image). I want to the code to be generalizable enough so that it is able to handle all UIBarStyles. That means I want to know when UIToolBarItem decides which background to use and intercept it so I can compose the button image on the fly.
Without being able to see apple's implementation of UIBarbuttonItem, I posit that they do not, in fact, know what the style of their UIToolbar is. If you look closely, they have the same alpha as their toolbar, and the same overlay (indicative of a subview). Therefore, any image that is below this highlighted layer, added as a subview, should conform to the UIToolbar's style. If you want to use multiple images though (one for each barStyle), you can determine it with self.myToolbar.barStyle and plan appropriately at -viewDidLoad time. As for true image drawing, subclass UIToolbar and override -drawRect: and use [UIImage drawInRect:rect];

Using a patternimage for a View inside an NSScrollView

I have a quite big problem, I am really not able to solve myself.
The result should look like this:
This image was made with photoshop and is part of the interface I try to build.
In the middle you see something, that should be a list of projects, you should be able to scroll, if it the list is bigger then the view.
So I am making a scrollview like this: (for some reason I cannot do this in the interface builder and want this to work programmatically)
NSScrollView *projectsListView = [[NSScrollView alloc] initWithFrame:NSMakeRect(15, 2, 801, 588)];
[projectsListView setHasVerticalScroller:YES];
Then I create the content view and set a pattern image as backgroundcolor:
NSClipView *contentView = [[NSClipView alloc] initWithFrame:NSMakeRect(0, 0,
[projectsListView frame].size.width, [projectsListView frame].size.height+(98*2))];
[contentView setBackgroundColor:[NSColor colorWithPatternImage:[NSImage imageNamed:#"BoxLineBackground"]]];
[contentView setDrawsBackground:YES];
Then set the view as document view:
[projectsListView setDocumentView:contentView];
Should work, right?
However the content view gets clipped and looks like this while scrolling:
I tried this to fix it, but it does nothing:
[[projectsListView documentView] setCopiesOnScroll:NO];
I also tried this, but it causes the contentview not to scroll at all.
The image stays the same, but I can move the scroller normally.
[[projectsListView contentView] setCopiesOnScroll:NO];
If I try to set the contentview with setContentView: instead of using setDocumentView:
it may work, but the scroller is gone, so it is also not working correctly.
I would really like to use the patternimage method, because I cannot tell how long the list will be. It depends on the user.
An additional problem then would be to get the whole thing rounded, but that does not matter that much. I tried to use a transparent border image and to overlay the NSScrollView with it using an NSImageView, but again this causes corruption, because it clips and moves the overlaying parts of the image view together with the content of the scrollview.
Anyone having an idea, how to achieve this?
Thanks
Rather than re-inventing the wheel, this interface should be implemented with a view-based NSTableView. The table cell UI could then be created in Interface Builder and you could control the background of the cells using the various NSTableView delegate methods. NSTableView will handle redraws upon scrolling correctly.
To handle the pattern color, just make the background of your cell a custom subclass of NSTableCellView and implement your pattern drawing code.
Regardless of all this, the problem you are having is due to an NSScrollView drawing optimisation. You can turn this off by calling [[yourScrollView contentView] setCopiesOnScroll:NO] on your NSScrollView instance. You can also set this in Interface Builder, just un-check the Copies on Scroll checkbox.
I fixed the problem by setting the Background Color on the NSScrollView instead on the NSClipView.
I though the background would be static in that case and I need to set it for the content view for that reason, but it works pretty well and does scroll together with the content view.
And thanks for Rob Keniger's answer. I will probably try this out.

How do I rotate the contents of a UIWebView?

I have made a very simple web browser app using a web view. Now I need to get the app so that when the iPhone is rotated, the text of the page is rotated as well.
How do I do this?
I am very confused by the auto-resize dialog, so it is possible I have done something wrong there.
Any help would be appreciated!
I think you sholud rotate UIWebView widget, not its contents. Contents should rotate as well. To support rotating add following code to your view controller:
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Rotated widget might look different then expected. Adjust struts and springs in Interface Builder.
I think you need to give us some sample code in order to determine what goes wrong. It is as Jacek says, the only think you should need to do is to support auto rotation on the UIWebView itself. The content should be rotated automatically.
I think you are confused by device orientation and view frame.
In most cases UIViews do change with respect to the orientation change. But to clarify - it is not because of the orientation change, but the layout change.
Only UIViewControllers need to consider device orientation - UIViews do NOT. When the device orientation changes, the UIViewController captures the event from its instance methods:
– willRotateToInterfaceOrientation:duration:
– willAnimateRotationToInterfaceOrientation:duration:
– didRotateFromInterfaceOrientation:
The UIViewController then re-layout the views - leading to reframing of the UIViews. In many cases, iOS can helps you in simplifying the relayout process by setting the UIViewAutoresizeMask. For example:
myWebview.autoresizeMask = UIVIewAutoresizeMaskFlexibleHeight | UIVIewAutoresizeMaskFlexibleHeight;
implies that when webview's superview changed its bounds, the webview will change accordingly.
As a summary, UIView only takes care of its frame / bounds etc.