How to deal with iMessage Navigation bar covering top of view bug

Leave a comment

iMessage has a bug where it doesn’t if you have something (like a search bar) pinned to the top of the view, it’s hides it when you transition from compact to expanded view.

imessage-navbar-bug.gif

The fix for now is to manually adjust the height on the top constraint so that when you are in expanded mode, you push it down beyond the navbar. Of course you will have to adjust this number slightly for older iPhones. But 88 seems standards for iPhone 6/7.

ViewController.m


@interface MessagesViewController ()
@property (nonatomic, strong) NSLayoutConstraint *topConstraint;
@end

-(void)willTransitionToPresentationStyle:(MSMessagesAppPresentationStyle)presentationStyle {
    // Called before the extension transitions to a new presentation style.
    
    // Use this method to prepare for the change in presentation style.

    switch (presentationStyle) {
        case MSMessagesAppPresentationStyleCompact: {
            self.topConstraint.constant = 0;
            [self.view setNeedsLayout];
            break;
        }
        case MSMessagesAppPresentationStyleExpanded: {
            self.topConstraint.constant = 88.0;
            [self.view setNeedsLayout];
            break;
        }

        default:
            break;
    }

}

How to set height programmatically autolayout

1 Comment

You can set the height and width visually like this.

    NSArray *foo1 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[clearSearchButton(==searchBar)]" options:0 metrics:nil views:views];
    NSArray *foo2 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[clearSearchButton(==searchBar)]" options:0 metrics:nil views:views];

You can set it programmatically with a constraint like this

 NSLayoutConstraint *foo = [NSLayoutConstraint constraintWithItem:self.clearSearchButton
                                                                   attribute:NSLayoutAttributeHeight
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self.searchBar
                                                                   attribute:NSLayoutAttributeHeight
                                                                  multiplier:1
                                                                    constant:0];

    [self.view addConstraint:foo];

Or You can set it to a specific height like this.

    [self.clearSearchButton addConstraint:[NSLayoutConstraint constraintWithItem:self.clearSearchButton
                                                     attribute:NSLayoutAttributeHeight
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:nil
                                                     attribute: NSLayoutAttributeNotAnAttribute
                                                    multiplier:1
                                                      constant:20]];

How to create a UITableViewCell and dequeue programatically

Leave a comment

If you ever need to create and dequeue a custom cell programatically (not use storyboards) do this

Screen Shot 2017-06-04 at 2.12.19 PM.png

Code

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"Cell";

    [tableView registerClass:[TrackCell class] forCellReuseIdentifier:cellIdentifier];
    TrackCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];


    Track *track = [self.tracks objectAtIndex:indexPath.row];

    cell.titleLabel.text = track.title;
    cell.artistLabel.text = track.artist;

    UIImage *albumImage = [UIImage imageNamed:track.albumImage];
    cell.imageView.image = albumImage;

    return cell;
}

How to UIStackView in UITableViewCell

Leave a comment

Create Single ViewController project. Add a UITableView.

Screen Shot 2017-06-04 at 8.31.52 AM.png

Pin it to the walls.

Screen Shot 2017-06-04 at 8.32.38 AM.png

Turn off the default separator.

Screen Shot 2017-06-04 at 8.33.14 AM.png

Drag out a UITableViewCell

Screen Shot 2017-06-04 at 8.34.10 AM.png

Add a UIImageView

Screen Shot 2017-06-04 at 8.35.22 AM.png

Set it’s height and width and position.

Screen Shot 2017-06-04 at 8.36.07 AM.png

Screen Shot 2017-06-04 at 8.36.20 AM.png

Now add x2 labels to the side.

Screen Shot 2017-06-04 at 8.37.08 AM.png

Now for the stackView. Select the two labels and then embed them in the stackView using the button at the bottom.

Screen Shot 2017-06-04 at 8.38.19 AM.png

Screen Shot 2017-06-04 at 8.38.36 AM.png

Now select the UIImageView and the new stackView and embed those in a stackview.

Screen Shot 2017-06-04 at 8.39.31 AM.png

Now here is the important bit. Right now you have constraint violations.

Screen Shot 2017-06-04 at 8.42.34 AM.png

The way to fix these is to pin the outermost UIStackView to the x4 edges.

Screen Shot 2017-06-04 at 8.43.25 AM.png

Screen Shot 2017-06-04 at 8.43.49 AM.png

This will line everything up nicely.

Now there is still a constraint violation. But it has nothing to do with stackview. It’s a hugging issue.

Screen Shot 2017-06-04 at 8.44.51 AM.png

Here it doesn’t know what priority to give vertical hugging for the x2 labels. Which one should expand to fill the height of the cell. They are both the same.

The way to resolve this is to change the hugging priority of one of the labels. Make the bottom one hug more than the top.

Select artist and set it’s vertical hug to 252.

Screen Shot 2017-06-04 at 8.49.10 AM.png

And voila! A stackview in a tableviewcell.

Screen Shot 2017-06-04 at 8.49.40 AM.png

Also you can give your view a 1:1 aspect ratio if you like.

Screen Shot 2017-06-04 at 8.56.06 AM.png

Links that help
https://developer.apple.com/videos/play/wwdc2015/407/
the 5min marks show you how to do this

How to UICollectionView

Leave a comment

Drag out Single View Controller. Add a CollectionView.

Screen Shot 2017-06-04 at 6.03.52 AM.png

Pin it to the walls.

Screen Shot 2017-06-04 at 6.04.36 AM.png

Implement the interfaces

Screen Shot 2017-06-04 at 6.05.36 AM.png

The create an data struct and fill it with data.

Screen Shot 2017-06-04 at 6.08.33 AM.png

Create a UICollectionViewCell.

Screen Shot 2017-06-04 at 6.10.25 AM.png

Add a label to the cell in the story board.

Screen Shot 2017-06-04 at 6.11.52 AM.png

Connect the cell in the storyboard to the UICollectionViewCell we just created.

Screen Shot 2017-06-04 at 6.14.36 AM.png

Give it an id.

Screen Shot 2017-06-04 at 6.14.50 AM.png

Hook it up to an IBOutlet.

Screen Shot 2017-06-04 at 6.15.47 AM.png

Instantiate and populate the cell in the delegate methods.

Screen Shot 2017-06-04 at 6.20.11 AM.png

Add the CollectionView as a property.

Screen Shot 2017-06-04 at 6.23.15 AM.png

Make yourself the delegate.

Screen Shot 2017-06-04 at 6.24.53 AM.png

Set yourself as the DataSource by control dragging from CollectionView to yellow ViewController in storyboard.

Screen Shot 2017-06-04 at 6.28.49 AM.png

Should now run and populate.

Screen Shot 2017-06-04 at 6.29.53 AM.png

To make the flow horizontal change the flow.

Screen Shot 2017-06-04 at 6.30.40 AM.png

And to make rows selectable implement.

Screen Shot 2017-06-04 at 6.34.40 AM.png

Which will print out.

Screen Shot 2017-06-04 at 6.32.43 AM.png

Optionally you can also implement these following methods for more layout control.

Screen Shot 2017-06-04 at 6.33.27 AM.png

Code

TrackCell.h

#import

@interface TrackCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UILabel *name;
@end

TrackCell.m

#import "TrackCell.h"
@implementation TrackCell
@end

ViewController.m

#import "ViewController.h"
#import "TrackCell.h"

@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (nonatomic, strong) NSArray *tracks;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tracks = [NSArray arrayWithObjects:@"Egg Benedict", @"Mushroom Risotto", @"Full Breakfast", nil];

    self.collectionView.delegate = self;
}

#pragma mark - UICollectionViewDataSource

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.tracks.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"TrackCell";

    TrackCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
    cell.name.text = (NSString *)self.tracks[indexPath.row];
    return cell;
}

#pragma mark - UICollectionViewDelegate

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%@", self.tracks[indexPath.row]);
}

@end

How to adjust layout for UISearchBar keyboard

Leave a comment

See previous post for how to add and hook up a search bar. Setup something like this.

Screen Shot 2017-06-03 at 3.55.19 PM.png

Center the label.

Screen Shot 2017-06-03 at 3.57.02 PM.png

But also give it a custom height.

Screen Shot 2017-06-03 at 3.57.29 PM.png

We are going to calculate the value and turn that constraint ON/OFF depending on whether the keyboard is displayed or not.

Drag out the two constraints from the storyboard.

Screen Shot 2017-06-03 at 3.58.30 PM.png

Calculate the keyboard height

Register yourself for the keyboard, calculate the height, and then set the calculated constraint value while turning the appropriate constraint on/off.

Screen Shot 2017-06-03 at 3.59.40 PM.png

Screen Shot 2017-06-03 at 3.59.40 PM.png

That’s it!

Jun-03-2017 16-03-36.gif

Code

ViewController.h

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
@property (weak, nonatomic) IBOutlet UILabel *label;

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelYCustomHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelYCenterContraint;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.searchBar.delegate = self;

    [self setupKeyboardNotification];
}

// return NO to not become first responder
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    return YES;
}

// called when text starts editing
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    // adjust layout for keyboard display
}

// return NO to not resign first responder
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
    // adjust layout for no keyboar

    return YES;
}

// called when text ends editing
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
    // turn off adjusted height
    self.labelYCustomHeightConstraint.active = NO;

    // turn on center Y
    self.labelYCenterContraint.active = YES;
}

// called when text changes (including clear)
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    self.label.text = searchText;
}

// called when keyboard search button pressed
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    self.label.text = @"searchButton clicked";
}

// called when cancel button pressed
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
    self.label.text = @"cancelButton clicked";

}

- (IBAction)onPressed:(UIButton *)sender
{
    // turn on adjusted height
    self.labelYCustomHeightConstraint.active = YES;

    // turn off center Y
    self.labelYCenterContraint.active = NO;
}

- (IBAction)offPressed:(UIButton *)sender
{
    // turn off adjusted height
    self.labelYCustomHeightConstraint.active = NO;

    // turn on center Y
    self.labelYCenterContraint.active = YES;
}

- (IBAction)dismissPressed:(UIButton *)sender
{
    [self.searchBar resignFirstResponder];
}

#pragma mark - Keyboard notification

- (void)setupKeyboardNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowNotification:) name:UIKeyboardWillShowNotification object:nil];
}

- (void)keyboardWillShowNotification:(NSNotification *)notification
{
    [self updateViewConstraintsForKeyboardNotification:notification];
}

- (void)updateViewConstraintsForKeyboardNotification:(NSNotification *)notification
{
    CGFloat keyboardHeight = [self keyboardHeightForNotification:notification];
    CGFloat viewHeight = self.view.bounds.size.height;
    CGFloat midPointY = (viewHeight - keyboardHeight) / 2;

    // turn on adjusted height
    self.labelYCustomHeightConstraint.constant = midPointY;
    self.labelYCustomHeightConstraint.active = YES;

    // turn off center Y
    self.labelYCenterContraint.active = NO;
}

- (CGFloat)keyboardHeightForNotification:(NSNotification *)notification
{
    NSDictionary *userInfo = [notification userInfo];
    NSValue *keyboardFrameBegin = [userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
    CGFloat keyboardHeight = keyboardFrameBeginRect.size.height;
    return keyboardHeight;
}


@end

How to UISearchBar

1 Comment

Drag out a UISearchBar and label

Screen Shot 2017-06-03 at 2.27.29 PM.png

Hook up the outlets

Screen Shot 2017-06-03 at 2.28.00 PM.png

Implement the interface

Screen Shot 2017-06-03 at 2.28.15 PM.png

Then do this

Screen Shot 2017-06-03 at 2.28.37 PM.png

Code

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UISearchBarDelegate>


@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.searchBar.delegate = self;
}

// return NO to not become first responder
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    return YES;
}

// called when text starts editing
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    // adjust layout for keyboard display
}

// return NO to not resign first responder
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
    // adjust layout for no keyboar

    return YES;
}

// called when text ends editing
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{

}

// called when text changes (including clear)
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    self.label.text = searchText;
}

// called when keyboard search button pressed
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    self.label.text = @"searchButton clicked";
}

// called when cancel button pressed
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
    self.label.text = @"cancelButton clicked";

}

@end

Older Entries Newer Entries

%d bloggers like this: