-1

I have problem with setting constraints to custom UIView and pushing new ViewController by delegate when I tap the view. I tried to find solution for these problems but couldn't find one that answers to these questions.

Autolayout problem

I have custom xib-file which has been set Size: Freeform, Width: 600 and Height: 25, it also includes one label and one button with constraints in this view. I have added this view successfully below navigation bar where I want it. Problem is, that it don't make anything to fit it's width equally with navigation bar / window size (I have tried multiple choices eg. making new frame for view that is width of window / navigation bar). It only appears to have static 600 width all the time whatever I try.

First two constraints are working, it appears 25 points below navigation bar and it centers it. But last one won't make anything.

How should I do this properly? So far have this:

[self.subView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:self.subView];

[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.subView
                              attribute:NSLayoutAttributeBottom
                              relatedBy:NSLayoutRelationEqual
                              toItem:self.navBar
                              attribute:NSLayoutAttributeBottom
                              multiplier:1
                              constant:25.0]];

[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.subView
                              attribute:NSLayoutAttributeCenterX
                              relatedBy:NSLayoutRelationEqual
                                 toItem:self.view
                              attribute:NSLayoutAttributeCenterX
                             multiplier:1.0
                               constant:0.0]];

[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.subView
                              attribute:NSLayoutAttributeWidth
                              relatedBy:NSLayoutRelationEqual
                                 toItem:self.view
                              attribute:NSLayoutAttributeWidth
                             multiplier:1
                               constant:0]];

Should I do something more with xib-file that it will make this width to fit it's parent view? I have also implemented initWithFrame, initWithCoder and intrinsicContentSize to my custom view.


Solution

I ended up to make containerView for my subView and center it vertically and horizontally and found right constraint for width. I also forgot to update my subView's view frames to match navigation bar width. Here is what I ended up to (if there is better way to do this, I take critic with pleasure):

self.containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 62, self.navBar.frame.size.width, 25)];
[self.view addSubview:self.containerView];

self.subView = [[SubView alloc]init];
[self.subView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.containerView addSubview:self.subView];

self.subView.view.frame = CGRectMake(0, 0, self.containerView.frame.size.width, self.containerView.frame.size.height);

[self.containerView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.subView
                              attribute:NSLayoutAttributeCenterY
                              relatedBy:NSLayoutRelationEqual
                                 toItem:self.containerView
                              attribute:NSLayoutAttributeCenterY
                             multiplier:1.0
                               constant:0.0]];

[self.containerView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.subView
                              attribute:NSLayoutAttributeCenterX
                              relatedBy:NSLayoutRelationEqual
                                 toItem:self.containerView
                              attribute:NSLayoutAttributeCenterX
                             multiplier:1.0
                               constant:0.0]];

[self.containerView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.subView
                              attribute:NSLayoutAttributeWidth
                              relatedBy:NSLayoutRelationEqual
                                 toItem:self.containerView
                              attribute:NSLayoutAttributeWidth
                             multiplier:1.0f
                               constant:0]];

Delegate problem (solved)

For answer to this problem: check MisterGreen's answer below.

Another problem occured when I made UITapGestureRecognizer with delegate in my custom view. What I want is when I tap the view, it opens another ViewController. The delegate function is like this where I implement my custom view:

-(void)pushViewControllerUsingDelegate
{
    NSLog(@"DELEGATE WAS : %@", self.subView.delegate);
    [self pushViewController:self.anotherViewController animated:YES];
}

Now it gives exception when I tap the view:

DELEGATE WAS : <MasterViewController: 0x7fc96132e7d0> <-- Delegate is OK
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AnotherViewController 0x7fc961248230> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key subViewButton.'

What this actually means? I have this subViewButton IBOutlet with weak property, does it have something to do with this? Or is there another way to make this happen?

Tutorial which I followed: https://www.youtube.com/watch?v=TfKv1MYxnA4

Cœur
  • 37,241
  • 25
  • 195
  • 267
JHT
  • 1
  • 4
  • When do you set your constraints ? I don't see any constraints about the height of your subView – GaétanZ Aug 27 '15 at 09:20
  • I set constraints to my subView in viewDidLoad, after I have set subView to self.view. If I have set height on xib-file that is 25 and I don't want to change it, do I still have to make constraint for it?Only thing I want to change is that this subView will take dynamic width of screen/window/navigation bar for all devices (now its always 600 which I have set in xib) and fit it's content by that. – JHT Aug 27 '15 at 09:33
  • That's the purpose of constraints, being dynamic. What do you mean by "I have set height", using a constraint ? – GaétanZ Aug 27 '15 at 09:38
  • Yes, I know. I have set width: 600 and height: 25 from IB Size Inspector for my subView. I'm just wondering why this NSLayoutAttributeWidth won't take effect when I set it to my view. It won't change my subView width, it only throws it left side of the screen. Am I missing some other constraints I need to set for it to make it screen wide? – JHT Aug 27 '15 at 09:49
  • You should read this http://www.apeth.com/iOSBook/ch14.html#_autolayout – GaétanZ Aug 27 '15 at 09:54
  • Thank you for you reply, I will check that one out. – JHT Aug 27 '15 at 11:52

1 Answers1

0

Because there is not enough data to be exactly sure what is the problem you encountered, i have just created a code snippet that is working and doing exactly what you are trying to get.

About the constraints i think the problem is the hight constraint that is missing(unless you determined it elsewhere), try to remember that when you add constraints provide enough data to the compiler to understand how to resize and position your subview according to it's superview, in your case it didn't know what is the hight cause you didn't supply nor bottom or hight constraint to determine it.

About the delegate method you didn't supply enough data to exactly determine what is the problem, so i've written something that i think is doing what you are trying to get.

This code snippet is tested and working:

The subview: View.h

@protocol viewManager <NSObject>
@optional
- (void)subviewWasTapped;
@end
@interface View : UIView
@property (nonatomic, strong) id<viewManager>delegate;
@end

View.m

@implementation View

- (void)awakeFromNib{
    [super awakeFromNib];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(viewWasTapped:)];
    [self addGestureRecognizer:tap];
}

- (void)viewWasTapped:(NSNotification *)notification
{
    [self sendViewWasTappedToDelegate];
}

- (void)sendViewWasTappedToDelegate
{
    @synchronized(_delegate)
    {
        if([_delegate respondsToSelector:@selector(subviewWasTapped)])
        {
            [_delegate subviewWasTapped];
        }
    }
}

@end

FirstViewController:

@interface ViewController () <viewManager>
@property (nonatomic, strong) View *subview;

@end

@implementation ViewController
@synthesize subview;
- (void)viewDidLoad {
    [super viewDidLoad];

    NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"View" owner:self options:nil];
    subview = [subviewArray objectAtIndex:0];
    [subview setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:subview];

    [self.view addConstraint:
     [NSLayoutConstraint constraintWithItem:subview
                                  attribute:NSLayoutAttributeTop
                                  relatedBy:NSLayoutRelationEqual
                                     toItem:self.topLayoutGuide
                                  attribute:NSLayoutAttributeBottom
                                 multiplier:1.0
                                   constant:0.0]];


     [self.view addConstraint:
      [NSLayoutConstraint constraintWithItem:subview
                                  attribute:NSLayoutAttributeCenterX
                                  relatedBy:NSLayoutRelationEqual
                                     toItem:self.view
                                  attribute:NSLayoutAttributeCenterX
                                 multiplier:1.0
                                   constant:0.0]];

     [self.view addConstraint:
      [NSLayoutConstraint constraintWithItem:subview
                                  attribute:NSLayoutAttributeWidth
                                  relatedBy:NSLayoutRelationEqual
                                     toItem:self.view
                                  attribute:NSLayoutAttributeWidth
                                 multiplier:1
                                   constant:0.0]];

    // Height constraint to determine the
    [self.view addConstraint:
     [NSLayoutConstraint constraintWithItem:subview
                                  attribute:NSLayoutAttributeHeight
                                  relatedBy:NSLayoutRelationEqual
                                     toItem:nil
                                  attribute:NSLayoutAttributeNotAnAttribute
                                 multiplier:1
                                   constant:25.0]];

    [self.view layoutIfNeeded];

    [subview setDelegate:self];
}

#pragma mark - viewManager delegate method 

- (void)subviewWasTapped{
    SecondeViewController *secondeVC = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondeViewController"];
    [self.navigationController pushViewController:secondeVC animated:YES];
}
MisterGreen
  • 156
  • 9