I am working on a menubar app, that uses NSPopover. I am using the following code to present popover.
[self.mainPopover showRelativeToRect:[testView bounds] ofView:testView preferredEdge:NSMinYEdge];
Issue is this is being present too close to status bar as shown below.
Even if i change the rect it does not have any effect and rightly so, as the documentation states
The rectangle within positioningView relative to which the popover should be positioned. Normally set to the bounds of positioningView. May be an empty rectangle, which will default to the bounds of positioningView.
Following is the screenshot from dropbox app, was just wondering how can i add some spacing in my app like dropbox.
To achieve this i added a padding view and attach set NSStatusItem View to that container view. Code from the solution used is as follow for anybody looking to implement it.
_paddingView = [NSView new];
[_containerView addSubview:_paddingView];
[_containerView addSubview:_dragView];
[_dragView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_paddingView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_dragView(22)][_paddingView(5)]|" options:0
metrics:nil views:views]];
[_containerView addConstraint:[NSLayoutConstraint constraintWithItem:_dragView
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
toItem:_paddingView attribute:NSLayoutAttributeLeft
multiplier:1. constant:0]];
[_containerView addConstraint:[NSLayoutConstraint constraintWithItem:_dragView
attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
toItem:_paddingView attribute:NSLayoutAttributeRight
multiplier:1. constant:0]];
self.mainPopover = [[NSPopover alloc] init];
self.mainPopover.delegate = self;
self.mainPopover.backgroundColor = [NSColor greenColor];
[self.mainPopover setAnimates:NO];
[self.mainPopover setBehavior:NSPopoverBehaviorTransient];
[self.mainPopover setContentViewController:viewController];
[_containerView layoutSubtreeIfNeeded];
[_statusItem setView:_containerView];
You could inset the test view bounds to add some margin between de view and popover:
NSPopover *mainPopover = [self mainPopover];
NSRect bounds = CGRectInset([testView bounds], -50.0, -50.0);
[mainPopover showRelativeToRect:bounds ofView:testView preferredEdge:NSMinYEdge];
Related
I am trying to add a button to a UIstackview, programmatically. All this is in fitxero XIB.
The button is created correctly, but when adding the constraints I get the following error:
2020-05-21 17:51:08.328369+0200 eWAS[3391:567586] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view?
That's illegal. constraint: < NSLayoutConstraint:0x282362b70 V:|-(0)-[UIButton:0x11c225a60'button'] (active, names: '|':UIStackView:0x11bfc13f0 ) > view:< UIButton: 0x11c225a60; frame = (0 0; 30 150); opaque = NO; layer = < CALayer: 0x2802e4220 > >'
-(void) configureTabsWithTexts: (NSArray *) tabs{
NSInteger tag = 0;
UIButton *currentButton = [UIButton buttonWithType:UIButtonTypeSystem];
[currentButton setTitle:#"Button1" forState:UIControlStateNormal];
[currentButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[currentButton setTag:tag];
[currentButton.titleLabel setFont:[UIFont systemFontOfSize:20]];
[currentButton.titleLabel setTextColor:[UIColor whiteColor]];
[currentButton setFrame:CGRectMake(0, 0, 30, 150)];
currentButton.backgroundColor = [UIColor blackColor];
[self.stackViewForButtons addSubview:currentButton];
[currentButton setTranslatesAutoresizingMaskIntoConstraints:NO];
NSMutableArray <NSLayoutConstraint *> *arrayConstraints = [[NSMutableArray alloc] init];
currentButton.translatesAutoresizingMaskIntoConstraints = false;
[currentButton addSubview:self.stackViewForButtons];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.stackViewForButtons
attribute:NSLayoutAttributeTop
multiplier:1
constant:0]];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:currentButton.superview
attribute:NSLayoutAttributeBottom
multiplier:1
constant:0]];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:50]];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:currentButton.superview
attribute:NSLayoutAttributeLeading
multiplier:1
constant:0]];
}
You have this line:
[self.stackViewForButtons addSubview:currentButton];
which seems fine, but then later you are doing:
[currentButton addSubview:self.stackViewForButtons];
which seems backwards and is probably the source of your problem. Try removing that latter line and see if it works. I doubt you want a UIButton to have a stack view as a subview. With both lines in place, there is a circular reference, which UIView probably figures out and removes the original superview of the UIButton, meaning that is nil when you are creating the later constraints (or maybe it removes the superview/subview relationship altogether).
As an aside, if you are using an actual UIStackView which it looks like you are, you shouldn't need any of these constraints done by hand. The entire point of UIStackView is to generate all those constraints for you. In that case, simply call:
[self.stackViewForButtons addArrangedSubview:currentButton];
[currentButton setTranslatesAutoresizingMaskIntoConstraints:NO];
and you should be done, provided you have configured the stack view correctly. Maybe you need the width constraint on each one, not sure. While you can add non-arranged subviews to a UIStackView, that should be rare. And even if that is intended in this case, you may be better off adding another UIStackView as a subview, then adding the buttons to that.
I have a UIView that contains subviews that looks like this:
This view was originally designed with 320 width in mind. iPhone 5s and lower. However I am now adapting it to work with iPhone 6+
The issue I am facing is getting the subviews width to grow to accommodate the extra space on the left and right of their super view. I can only seem to get the centre views width to grow, however not the out views. What constraints would I need to apply or change in order to get all views to grow a little to accommodate the extra space on the sides?
Hi!
If you design your view in interface builder, you may try this:
1- set all views to specific width and height
2- the view at the corner add pin to the edge with static value.
3- the view in the middle add pin to top or bottom, and add align constraint to horizontal centre of superview
Not sure if this help, Just try to answer!
Here is a complete example of how to achieve this programmatically (with dummy views):
// Simple example demonstrating the below screenshots
// Create containers to hold each row of subviews
UIView *container1 = [UIView new];
container1.translatesAutoresizingMaskIntoConstraints = NO;
container1.backgroundColor = [UIColor redColor];
UIView *container2 = [UIView new];
container2.translatesAutoresizingMaskIntoConstraints = NO;
container2.backgroundColor = [UIColor orangeColor];
// Create the subviews
UIView *v1 = [UIView new];
v1.translatesAutoresizingMaskIntoConstraints = NO;
v1.backgroundColor = [UIColor grayColor];
UIView *v2 = [UIView new];
v2.translatesAutoresizingMaskIntoConstraints = NO;
v2.backgroundColor = [UIColor blackColor];
UIView *v3 = [UIView new];
v3.translatesAutoresizingMaskIntoConstraints = NO;
v3.backgroundColor = [UIColor greenColor];
UIView *v4 = [UIView new];
v4.translatesAutoresizingMaskIntoConstraints = NO;
v4.backgroundColor = [UIColor purpleColor];
UIView *v5 = [UIView new];
v5.translatesAutoresizingMaskIntoConstraints = NO;
v5.backgroundColor = [UIColor blueColor];
UIView *v6 = [UIView new];
v6.translatesAutoresizingMaskIntoConstraints = NO;
v6.backgroundColor = [UIColor yellowColor];
// add the subviews
[container1 addSubview:v1];
[container1 addSubview:v2];
[container1 addSubview:v3];
[container2 addSubview:v4];
[container2 addSubview:v5];
[container2 addSubview:v6];
// Add the containers to the root view (in this case self.view)
[self.view addSubview:container1];
[self.view addSubview:container2];
// Add constraints for the containers
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[container1]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container1)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[container2]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container2)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-64.0-[container1(==100)]-[container2(==container1)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container1, container2)]];
// Add constraints in both VFL and regular NSConstraints to the subviews of container 1
[container1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v1]-[v2(==v1)]-[v3(==v1)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v1,v2,v3)]];
[container1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v1]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v1)]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v1 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container1 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v1 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container1 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
// Add constraints in both VFL and regular NSConstraints to the subviews of container 2
[container2 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v4]-[v5(==v4)]-[v6(==v4)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v4,v5,v6)]];
[container2 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v4]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v4)]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v5 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v4 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v5 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v6 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v4 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v6 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
Attached are screenshots on iPhone 5s, iPhone 6 and iPhone 6 Plus respectively:
iPhone 5s
iPhone 6
iPhone 6 Plus
I hope this at least point you in the right direction =)
disable autolayout and use autoresizing masks in the interface builderHandling Layout Changes Automatically Using Autoresizing Rules
I'm trying to fill a UIView with a UIImageView using auto layout. I've tried several thing, but the most obvious, equalSize with parent view only works when I set the correct size in "Simulated metric". If I let Freeform (the point of autolayout isn't it ?) I get messed up.
I'm testing on an iPhone 4S and a 6 plus.
Thanks for any leading tracks.
EDIT FOR #mittens
I've seen your edit. I still can get it working. As you see I have 4 margin constraints, the same as in your code (I did not need the rest because I only use the main UIView).
Anyway, when I change the size on xcode, the layout is perfect, when I send it to my 4S, I only get Top and left margins.
I'd double check the constraints on the UIView you're trying to fill with the UIImageView to make sure it is filling up its parent view as it should be when the storyboard/xib is set to freeform. Also if you're adding/creating the views programmatically double check that the views 'translatesAutoresizingMaskIntoConstraintsis set toNO`. That always trips me up.
I made a super quick view and added some constraints to both a view inside the View Controllers view and an Image view to show one way to do it -- hopefully it helps at least a little
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.backdropView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
self.backdropView.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.5];
self.backdropView.translatesAutoresizingMaskIntoConstraints = NO; // Make sure this is set to NO if the view is being added programmatically
[self.view addSubview:self.backdropView]; // Always add the view into the hierarchy _before_ constraints are added (again, if creating & adding programmatically)
NSLayoutConstraint *backdropViewWidth = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0];
NSLayoutConstraint *backdropViewHeight = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeHeight multiplier:0.5 constant:0];
NSLayoutConstraint *backdropViewCenterX = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
NSLayoutConstraint *backdropViewCenterY = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
[self.backdropView.superview addConstraints:#[backdropViewWidth, backdropViewHeight, backdropViewCenterY, backdropViewCenterX]];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
self.imageView.translatesAutoresizingMaskIntoConstraints = NO;
self.imageView.backgroundColor = [UIColor colorWithRed:1 green:0 blue:1 alpha:0.5];
[self.backdropView addSubview:self.imageView];
NSLayoutConstraint *imageViewTop = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeTop multiplier:1 constant:8];
NSLayoutConstraint *imageViewLeft = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeLeft multiplier:1 constant:8];
NSLayoutConstraint *imageViewRight = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeRight multiplier:1 constant:-8];
NSLayoutConstraint *imageViewBottom = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeBottom multiplier:1 constant:-8];
[self.imageView.superview addConstraints:#[imageViewTop, imageViewLeft, imageViewRight, imageViewBottom]];
[self.view layoutIfNeeded];
}
That produces and
Again, hopefully this helps.
EDIT: how to add them in storyboard
Note on photo 3, I select the view I want to constrain and then shift select the view I want to constraint it to. So I selected the inside UIView (because it width/height will be constrained to the parent view) then shift selected its parent view (the view it is nested inside of) to enable those options of Equal Width & Equal Height
Add constraints to UIImageView nested inside the UIView
Center UIView inside its parent view
Add width/height constraints equal to parent -- Note: I select the view I want to constrain and then shift select the view I want to constraint it to. So I selected the inside UIView (because it width/height will be constrained to the parent view) then shift selected its parent view (the view it is nested inside of) to enable those options of Equal Width & Equal Height
Change multiplier in constraint to be whatever you want, 0.5 in this case
Celebrate
i'm not sure but try this in your imageview.
[imgView clipToBounds:YES];
I hope it's work for you
When my table view is empty, I want to add a simple label into the tableview footer to display a "no content" message. It was working fine when I was setting the frames of the UILabel and the UIView that I used for footerView, but now I'm trying to convert to using auto-layout, and I can't get it to work.
Here's what I'm doing:
// Create the footer
UIView *tempFooter = [[UIView alloc] init];
UILabel *atext = [[UILabel alloc] init];
tempFooter.translatesAutoresizingMaskIntoConstraints = NO;
atext.translatesAutoresizingMaskIntoConstraints = NO;
atext.numberOfLines = 0;
[atext setText:#"Add Some Text"];
atext.textAlignment = NSTextAlignmentCenter;
atext.font = [UIFont italicSystemFontOfSize:14];
atext.textColor = [UIColor grayColor];
atext.backgroundColor = [UIColor clearColor];
atext.lineBreakMode = NSLineBreakByWordWrapping;
// add label to footer view, and add constraints
[tempFooter addSubview:atext];
NSLayoutConstraint *tvatt1 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:atext attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:10.0];
NSLayoutConstraint *tvatt2 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:atext
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:10.0];
NSLayoutConstraint *tvatt3 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:atext
attribute:NSLayoutAttributeTop
multiplier:5.0
constant:0];
NSLayoutConstraint *tvatt4 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:atext
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant: 0];
[tempFooter addConstraints: #[tvatt1, tvatt2, tvatt3, tvatt4]];
// set the footerview
self.tview.tableFooterView = tempFooter;
When I run this, I get a crash:
2014-09-08 19:57:16.594 SimpleList[49442:60b] * Assertion failure in
-[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794 2014-09-08
19:57:21.073 SimpleList[49442:60b] * Terminating app due to uncaught
exception 'NSInternalInconsistencyException', reason: 'Auto Layout
still required after executing -layoutSubviews. UITableView's
implementation of -layoutSubviews needs to call super
I'm not sure what I'm doing wrong. I've also tried setting constraints for the self.tview.tableFooterView wrt the tempFooter (pinning against all 4 sides) but that doesn't change the crash. I also call:
[self.tview.tableFooterView layoutSubviews];
but that doesn't help either.
Any ideas what I'm doing wrong?
You shouldn't set translatesAutoresizingMaskIntoConstraints to NO for table views, their cells, or table header and footer views (or for your controller's self.view for that matter). It's ok to use constraints for views inside those views (the content view of cells or the header and footer views). I added a simplified version of your code to viewDidLoad, and it worked as expected. Note that you need to give the footer view a height and an x position (the y position and the width are ignored),
UIView *tempFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 50)];
UILabel *atext = [[UILabel alloc] init];
atext.translatesAutoresizingMaskIntoConstraints = NO;
atext.numberOfLines = 0;
[atext setText:#"Add Some Text"];
atext.textAlignment = NSTextAlignmentCenter;
atext.font = [UIFont italicSystemFontOfSize:14];
atext.textColor = [UIColor grayColor];
atext.backgroundColor = [UIColor clearColor];
atext.lineBreakMode = NSLineBreakByWordWrapping;
[tempFooter addSubview:atext];
NSDictionary *dict = NSDictionaryOfVariableBindings(atext);
[tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|-10-[atext]-10-|" options:0 metrics:nil views:dict]];
[tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[atext]|" options:0 metrics:nil views:dict]];
self.tableView.tableFooterView = tempFooter;
I'm not sure what you were trying to accomplish with your constraint, tvatt3. The multiplier (you have 5) doesn't do anything with a top or left constraint since the value of those attributes is 0. I used the visual constraints, rather than the method you used, but when I used your code to add the constraints, it worked also .
Interestingly, changing the Autoresizing mask in the xib solved my problem.
Constraints not working:
Working:
I was able to make dynamically auto layout table footer width and height by implementing #rdelmar solution for constraints and adding these lines below. Same solution applies to table header view.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let tableFooter = tableView.tableFooterView {
let maxSize = CGSize(width: self.tableView.bounds.size.width,
height: CGFloat.greatestFiniteMagnitude)
let size = tableFooter.systemLayoutSizeFitting(maxSize)
let height = size.height
var headerFrame = tableFooter.frame
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if height != headerFrame.size.height {
headerFrame.size.height = height
tableFooter.frame = headerFrame
tableView.tableFooterView = tableFooter
}
}
}
P. S. I prefer Interface Builder for constraints setup
hope this will help you
I am not sure of this but it help me in my project, first add every thing in contentView (all the subview and the constraint)
[self.contentView addSubview:atext]
and then comes to code part
NSLayoutConstraint *tvatt1 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:atext attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:10.0];
code saying for left attribute
temfooter(must be equal) = 1.0*atext +10.0
i.e
temfooter must be equal to the modified atext , so need to make sure that your constraints are not wrong.
In my main view, I do some gesture action causing some new view to be shown. At this time I want to dim the entire background (except this new view) as a good UI practice. In HTML, Javascript it looks like so - How do I get this same effect in iOS ?
Lay a UIView over the background, set its background to [UIColor blackColor] and set its opacity to like 0.6. Then add that UIView to the parent view.
This'll dim out the background AND intercept any taps to background controls.
While Dan's suggestion is on target, you cannot use a modal view controller in this case because a typical modal covers the entire screen, blocking the parent view controller, even if you have the background of your view as transparent (you'll see whatever you have in the application's UIWindow).
If you are doing this on the iPad there are 2 modal presentation styles (UIViewModalPresentationStylePageSheet and UIViewModalPresentationStyleFormSheet) that can do something similar, but those will not work on an iPhone or iPod Touch.
Add the "shadow" view, with the dark background and partial opacity and whatever view you want to be in the foreground, to the view controller's view directly. You can animate them in using standard UIView animation blocks, or CoreAnimation.
Another note, if you want to intercept touches to that shadow view you can either make it a giant button, subclass UIView to override one of the touch methods like touchesEnded: or change it to a UIControl which can receive touch events like a UIButton, but without the extra options for text, shadows, states etc.
The above two answers work if the new view has it's own 'background', i.e. has no transparency. The problem that led me here cannot be solved that way though, what I was trying to do is this: I'm running an AVCaptureSession on my screen with the usual AVCaptureVideoPreviewLayer to display video in real time. I want to select a part of the screen (to later do something with only this part), and when this part is selected want to dim the rest of the video preview. This is what it looks like:
This is how I solved this: A new view is created depending on where the screen is touched and added as a subview of the video preview view. Then, I create 4 additional, non-overlapping rectangular subviews with the before-mentioned background color and opacity to cover the rest of the screen. I explicitly need all these views not to be subviews of the main view, because I need the ability to touch the screen somewhere else and change the selected area.
I'm sure there are more elegant ways to solve this, so if someone knows how please comment...
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UIGestureRecognizerDelegate>
{
UIView *mainView;
UIView *dimBackgroundUIView;
UIView *customView;
UIButton *btn;
}
#end
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
mainView = [[UIView alloc] init];
mainView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:mainView];
[self addConstraintsForMainView];
btn = [[UIButton alloc] initWithFrame:CGRectMake(200, 200, 100, 30)];
[btn setTitle:#"Button" forState:UIControlStateNormal];
[btn setBackgroundColor:[UIColor blueColor]];
[btn addTarget:self action:#selector(showCustomView_Action:) forControlEvents:UIControlEventTouchUpInside];
[mainView addSubview:btn];
dimBackgroundUIView = [[UIView alloc] init];
dimBackgroundUIView.backgroundColor = [UIColor blackColor];
dimBackgroundUIView.alpha = 0.2;
}
-(void)removeCustomViewsFromSuperView {
if(dimBackgroundUIView)
[dimBackgroundUIView removeFromSuperview];
if(customView)
[customView removeFromSuperview];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)showCustomView_Action:(id)sender {
customView = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 80, 80)];
customView.backgroundColor = [UIColor redColor];
[self.view addSubview:dimBackgroundUIView];
[self addConstraintsForDimView];
[self.view addSubview:customView];
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(removeCustomViewsFromSuperView)];
tapped.delegate=self;
tapped.numberOfTapsRequired = 1;
[customView addGestureRecognizer:tapped];
}
-(void) addConstraintsForDimView {
[dimBackgroundUIView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:dimBackgroundUIView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:dimBackgroundUIView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:dimBackgroundUIView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:dimBackgroundUIView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
}
-(void) addConstraintsForMainView {
[mainView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:mainView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:mainView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:mainView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:mainView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
}
#end
note: you can optimise the code by using graphical interface on Xcode but i had to write code programmatically to be able to test it
so the idea is to:
create UIView name it what you want (dimBackgroundUIView) than set
the backgroundcolor as Black and set alfa to 0.1 or 0.2 or....
add this 2 line of code when you need to dim the background:[self.view addSubview:dimBackgroundUIView];
[self addConstraintsForDimView];
and add this 2 line of code when you want to remove the dimming
background: if(dimBackgroundUIView) [dimBackgroundUIView removeFromSuperview];