Objective C, rounded corner custom window? - objective-c

I have a subclass of NSWindow to customize one of my windows for my app.
I have everything set, but I am not sure how to make the corners round.
Currently, my window is a transparent rectangular window with some buttons, labels, and a textfield in it.
The class includes:
#import "TransparentRoundRectWindow.h"
#implementation TransparentRoundRectWindow
-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
if (self) {
[self setAlphaValue:0.75];
[self setOpaque:YES];
[self setHasShadow:YES];
[self setBackgroundColor:[NSColor clearColor]];
}
return self;
}
-(BOOL)canBecomeKeyWindow
{
return YES;
}
I just need to make the corners round now. I tried searching for similar situations and saw some of them explaining to override the drawRect method but I couldn't get them to work.
How could I do this?
(I'm using Mac OS X Lion)
Thanks in advance.

You need to set to Your window Opaque to NO. And subclass Your window's view.
Window subclass:
-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
if (self) {
[self setOpaque:NO];
[self setHasShadow:YES];
[self setBackgroundColor:[NSColor clearColor]];
}
return self;
}
-(BOOL)canBecomeKeyWindow
{
return YES;
}
Window's view subclass:
- (void)drawRect:(NSRect)rect
{
NSBezierPath * path;
path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:8 yRadius:8];
[[NSColor colorWithCalibratedRed:0 green:0 blue:0 alpha:0.75] set];
[path fill];
}
Result:
More explanation how to do this:
Create new NSView class and paste "Window's view subclass" code which I wrote in it. Then go to Your window's view.
Here is window's view click on it:
Go to the Identity inspector and set class to your created class:

Related

Why my NSBezierPath is not showing?

So i recieve a notification with the data i need to draw my path. This code is from my main app controller:
-(void) handleAdd:(NSNotification *)aNotification{
NSLog(#"x1:%f y1:%f x2:%f y2:%f ",[panelController x1],[panelController y1],[panelController x2],[panelController y2]);
myPath = [[NSBezierPath alloc]init];
[myPath setLineWidth:[panelController grosor]];
[myPath moveToPoint:NSMakePoint([panelController x1],[panelController y1])];
[myPath lineToPoint:NSMakePoint([panelController x2],[panelController y2])];
[[panelController trazado] setStroke];
[myPath stroke];
}
The NSLog is showing me the right data. I have a view created and in that white rectangle is where i want to draw.
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
NSRect bounds= [self bounds];
[[NSColor whiteColor] set];
[NSBezierPath fillRect:bounds];
}
If i draw in that class the stroke is showing, but how could i draw on that view from the controller? Or should i just receive the notification in the view and draw from that class?
You can't (easily) draw from the controller into the view.
Think of your views drawRect method as a complete set of instructions of what to draw at every refresh.
So right now all you are saying is "fill me with white"
You need to handle all the relevant drawing within the views drawRect: method.
Adjust your controller method to this.
-(void) handleAdd:(NSNotification *)aNotification{
[myViewInstance setNeedsDisplay:YES]; //also myViewInstance.needsDisplay = YES
}
And assuming the view has a reference to the panel controller…
#interface MyView: UIView
//weak as you don't want a reference cycle
#property (weak) MyPanelController *panelController;
#end
#implementation MyView
- (void)drawRect:(NSRect)dirtyRect
{
NSRect bounds= [self bounds];
[[NSColor whiteColor] set];
[NSBezierPath fillRect:bounds];
NSBezierPath *myPath = [[NSBezierPath alloc]init];
[myPath setLineWidth:[self.panelController grosor]];
[myPath moveToPoint:NSMakePoint([self.panelController x1],[self.panelController y1])];
[myPath lineToPoint:NSMakePoint([self.panelController x2],[self.panelController y2])];
[[self.panelController trazado] setStroke];
[myPath stroke];
}
#end
If you want explore your first technique you want to look at at NSView and the lockFocus/unlockFocus methods. The documentation explains why you probably don't want to do this.

UIImagePickerController how to hide the flip camera button?

is there a way to hide the flip camera button inside the UIImagePickerController?
thanks for reading
!^_^!
I ended up using a custom subclass of UIImagePickerController to fix this (and other) issues:
#import "SMImagePickerController.h"
#implementation SMImagePickerController
void hideFlipButtonInSubviews(UIView *view) {
if ([[[view class] description] isEqualToString:#"CAMFlipButton"]) {
[view setHidden:YES];
} else {
for (UIView *subview in [view subviews]) {
hideFlipButtonInSubviews(subview);
}
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
hideFlipButtonInSubviews(self.view);
}
#end
You should be able to create an empty button inside an overlayview that you float on top of the flip camera button. I hacked the code below to test and it seemed to work. Give it a try.
UIView *cameraOverlayView = [[UIView alloc] initWithFrame:CGRectMake(screenSize.width - 100.0f, 5.0f, 100.0f, 35.0f)];
[cameraOverlayView setBackgroundColor:[UIColor blackColor]];
UIButton *emptyBlackButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)];
[emptyBlackButton setBackgroundColor:[UIColor blackColor]];
[emptyBlackButton setEnabled:YES];
[cameraOverlayView addSubview:emptyBlackButton];
cameraUI.allowsEditing = YES;
cameraUI.showsCameraControls = YES;
cameraUI.delegate = self;
cameraUI.cameraOverlayView = cameraOverlayView;

NSScrollview with NSGradient

I have a nsscroll view in my application and i made a subclass of nsscrollview to add a nsgradient but it doesn't work this is my code in my implementation file:
#import "scrollview.h"
#implementation scrollview
#synthesize startingColor;
#synthesize endingColor;
#synthesize angle;
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
[self setStartingColor:[NSColor colorWithCalibratedRed:0.941 green:0.941 blue:0.941 alpha:1]];
[self setEndingColor:[NSColor colorWithCalibratedRed:0.6588 green:0.6588 blue:0.6588 alpha:1]];
[self setAngle:90];
}
return self;
}
- (void)drawRect:(NSRect)rect {
NSBezierPath* roundRectPath = [NSBezierPath bezierPathWithRoundedRect: [self bounds] xRadius:10 yRadius:10];
[roundRectPath addClip];
if (endingColor == nil || [startingColor isEqual:endingColor]) {
// Fill view with a standard background color
[startingColor set];
NSRectFill(rect);
}
else {
// Fill view with a top-down gradient
// from startingColor to endingColor
NSGradient* aGradient = [[NSGradient alloc]
initWithStartingColor:startingColor
endingColor:endingColor];
[aGradient drawInRect:[self bounds] angle:angle];
}
}
The first step is to create a custom NSView subclass that draws a gradient:
GradientBackgroundView.h:
#interface GradientBackgroundView : NSView
{}
#end
GradientBackgroundView.m:
#import "GradientBackgroundView.h"
#implementation GradientBackgroundView
- (void) drawRect:(NSRect)dirtyRect
{
NSGradient *gradient = [[[NSGradient alloc] initWithStartingColor:[NSColor redColor] endingColor:[NSColor greenColor]] autorelease];
[gradient drawInRect:[self bounds] angle:90];
}
#end
The next step is to make the scroll view's document view an instance of this class (instead of plain NSView).
In IB, double-click your scroll view, and in the Identity pane set the Class to GradientBackgroundView.
From this point on, things are handled pretty much in the standard way. You can add subviews to the document view, resize it, etc. Here's a screenshot:

Cocoa App Enter Full Screen

I am developing a simple application which make use of full screen window.
Window contains view that contains button, image etc etc... , but when I enter in full screen with the follow lines:
NSWindow* tmp = [self window];
[tmp setStyleMask:NSBorderlessWindowMask];
[tmp setFrame:[tmp frameRectForContentRect:[[tmp screen] frame]]display:YES animate:NO];
[tmp setBackingType:NSBackingStoreBuffered];
screenRect = [[NSScreen mainScreen] frame];
int windowLevel = CGShieldingWindowLevel();
[self.window setLevel:windowLevel];
The view I put in the window doesn't resized automatically, I could make some operation for resize correctly that work, but there are a way to do that automatically?
I post all my AppController here:
-(id)init {
self = [super initWithWindowNibName:#"MainWindow"];
NSWindow* tmp = [self window];
[tmp setStyleMask:NSBorderlessWindowMask];
[tmp setFrame:[tmp frameRectForContentRect:[[tmp screen] frame]]display:YES animate:NO];
[tmp setBackingType:NSBackingStoreBuffered];
screenRect = [[NSScreen mainScreen] frame];
/**
// [[tmp standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
// [[tmp standardWindowButton:NSWindowZoomButton] setHidden:YES];
self.window = [[NSWindow alloc] initWithContentRect:screenRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO screen:[NSScreen mainScreen]];
**/
int windowLevel = CGShieldingWindowLevel();
[self.window setLevel:windowLevel];
return self;
}
// We need to be layer-backed to have subview transitions.
-(void)awakeFromNib {
[[self window] setContentSize:[topMenu frame].size];
[[[self window] contentView] addSubview:topMenu];
[topMenu enterFullScreenMode:[NSScreen mainScreen] withOptions:nil];
[[[self window] contentView] setWantsLayer:YES];
}
- (void)dealloc
{
[super dealloc];
}
- (void)windowDidLoad
{
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
[topMenu_controller performAnimation];
return;
}
You can use the springs and struts of Interface Builder to set a view's autosizing behavior:
http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/IB_UserGuide/Layout/Layout.html

Couldn't UIToolBar be transparent?

I try the following code, but it doesn't work.
[helloToolbar setBackgroundColor:[UIColor clearColor]];
To make a completely transparent toolbar, use the method described here. In a nutshell, create a new TransparentToolbar class that inherits from UIToolbar, and use that in place of UIToolbar.
TransarentToolbar.h
#interface TransparentToolbar : UIToolbar
#end
TransarentToolbar.m
#implementation TransparentToolbar
// Override draw rect to avoid
// background coloring
- (void)drawRect:(CGRect)rect {
// do nothing in here
}
// Set properties to make background
// translucent.
- (void) applyTranslucentBackground
{
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.translucent = YES;
}
// Override init.
- (id) init
{
self = [super init];
[self applyTranslucentBackground];
return self;
}
// Override initWithFrame.
- (id) initWithFrame:(CGRect) frame
{
self = [super initWithFrame:frame];
[self applyTranslucentBackground];
return self;
}
#end
(code from the blog post linked above)
In iOS 5, simply call setBackgroundImage and pass a transparent image.
Here's how I do it (I dynamically generate transparent image):
CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextFillRect(context, rect);
UIImage *transparentImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[toolbar setBackgroundImage:transparentImage forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
The best you can do is using
[helloToolbar setBarStyle:UIBarStyleBlack];
[helloToolbar setTranslucent:YES];
This will get you a black but translucent toolbar.
Transparent (iOS 5.0):
[toolbar setBackgroundImage:[[UIImage alloc] init] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
Translucent:
[toolbar setBarStyle:UIBarStyleBlack];
[toolbar setTranslucent:YES];
A cumulative solution for all devices, from oldest iOS 3.0 (iPhone 1) to newest iOS 6.1 (iPad mini).
#implementation UIToolbar (Extension)
- (void)drawRect:(CGRect)rect
{
if (CGColorGetAlpha(self.backgroundColor.CGColor) > 0.f)
{
[super drawRect:rect];
}
}
- (void)setTransparent
{
//iOS3+
self.backgroundColor = [UIColor clearColor];
//iOS5+
if ([self respondsToSelector:#selector(setBackgroundImage:forToolbarPosition:barMetrics:)])
{
[self setBackgroundImage:[[UIImage new] autorelease] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
}
//iOS6+
if ([self respondsToSelector:#selector(setShadowImage:forToolbarPosition:)])
{
[self setShadowImage:[[UIImage new] autorelease] forToolbarPosition:UIToolbarPositionAny];
}
}
#end
When you want a transparent toolbar, call setTransparent on it.
When you want a non-transparent toolbar, set a backgroundColor of your choice or add an imageView by yourself.
Another solution would be to define a category for UIToolbar:
#implementation UIToolbar(Transparent)
-(void)drawRect:(CGRect)rect {
// do nothing in here
}
#end
In the IB set the toolbar as Black Translucent and non opaque.
We've just noticed that overriding drawRect doesn't work anymore with iOS 4.3. It's not called anymore (edit: seems to be only in Simulator). Instead drawLayer:inContext: is called.
A great solution was posted here
Now you can set each UIToolbar object transparent, by setting its tintColor to [UIColor clearColor] :)
With iOS 5 the following works:
UIToolbar *bar = [[UIToolbar alloc] initWithFrame:CGRectZero];
if (bar.subviews.count > 0)
[[[bar subviews] objectAtIndex:0] removeFromSuperview];
This is because the background is now a subview. This code is safe even with new iterations of iOS, but it may stop working. This is not private API usage, your app is safe to submit to the store.
Make sure you remove the backgroundView before adding any UIBarButtonItems to the bar. Or my code will not work.
I just tested the following with iOS 4.3 on simulator and phone, seems to work fine. Subclass UIToolbar, provide one method:
- (void)drawRect:(CGRect)rect
{
[[UIColor colorWithWhite:0 alpha:0.6f] set]; // or clearColor etc
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
}
toolbar.barStyle = UIBarStyleBlackTranslucent;
This works in iOS5.1 with pretty minimal effort. I am matching up the size, as only the background will have the same frame size as the toolbar itself. You could use other criteria, of course.
Enjoy.
Create a subclass of UIToolbar as follows:
.h:
#import <UIKit/UIKit.h>
#interface UIClearToolbar : UIToolbar
#end
.m:
#import "UIClearToolbar.h"
#implementation UIClearToolbar
- (void)layoutSubviews {
// super has already laid out the subviews before this call is made.
[self.subviews enumerateObjectsUsingBlock:^(UIView* obj, NSUInteger idx, BOOL *stop) {
if (CGSizeEqualToSize(self.frame.size, obj.frame.size) ||
self.frame.size.width <= obj.frame.size.width) { // on device, the background is BIGGER than the toolbar.) {
[obj removeFromSuperview];
*stop = YES;
}
}];
}
#end
Thanks #morais for your solution - here's the code translated to MonoTouch:
public class TransparentToolbar : UIToolbar
{
public TransparentToolbar()
{
init();
}
public TransparentToolbar(RectangleF frame) : base(frame)
{
init();
}
void init()
{
BackgroundColor=UIColor.Clear;
Opaque=false;
Translucent=true;
}
public override void Draw(RectangleF rect)
{
}
}