Skip to content

Instantly share code, notes, and snippets.

@christianroman
Created February 6, 2014 16:18
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save christianroman/8847406 to your computer and use it in GitHub Desktop.
Save christianroman/8847406 to your computer and use it in GitHub Desktop.
Facebook Paper clone using Auto Layout and UIScrollView (First attempt)
//
// HomeViewController.m
// Stories
//
// Created by Christian Roman on 05/02/14.
// Copyright (c) 2014 Christian Roman. All rights reserved.
//
#import "HomeViewController.h"
#import "StoryView.h"
@interface HomeViewController () <UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) NSLayoutConstraint *constraintHeight;
@property (nonatomic, strong) NSMutableArray *contrainstArray;
@property (nonatomic, assign) BOOL pageOpened;
@end
@implementation HomeViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureScrollView];
[self adjustStories];
}
- (void)configureScrollView
{
_contrainstArray = [[NSMutableArray alloc] init];
_scrollView = [UIScrollView new];
[_scrollView setDelegate:self];
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_scrollView];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]];
_constraintHeight = [NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:253];
[self.view addConstraint:_constraintHeight];
}
- (void)adjustStories
{
StoryView *previousStory = nil;
for (NSInteger i = 0; i < 10; i++) {
StoryView *story = [StoryView new];
[story setTag:i];
CGFloat hue = ( arc4random() % 256 / 256.0 );
CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5;
CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5;
UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1];
[story setBackgroundColor:color];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapFrom:)];
[story addGestureRecognizer:tapGestureRecognizer];
story.translatesAutoresizingMaskIntoConstraints = NO;
[_scrollView addSubview:story];
// Default constraints
[_scrollView addConstraint:[NSLayoutConstraint constraintWithItem:story
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_scrollView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0]];
[_scrollView addConstraint:[NSLayoutConstraint constraintWithItem:story
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_scrollView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]];
NSLayoutConstraint *storyWidthConstraint = [NSLayoutConstraint constraintWithItem:story
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:143];
[_scrollView addConstraint:storyWidthConstraint];
[_contrainstArray addObject:storyWidthConstraint];
[_scrollView addConstraint:[NSLayoutConstraint constraintWithItem:story
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_scrollView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0]];
if (!previousStory) {
[_scrollView addConstraint:[NSLayoutConstraint constraintWithItem:story
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:_scrollView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0]];
} else {
[_scrollView addConstraint:[NSLayoutConstraint constraintWithItem:story
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:previousStory
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0]];
}
previousStory = story;
}
[_scrollView addConstraint:[NSLayoutConstraint constraintWithItem:previousStory
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:_scrollView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0]];
}
- (void)handleTapFrom:(UITapGestureRecognizer *)sender
{
NSInteger element = sender.view.tag;
CGRect frame = _scrollView.frame;
frame.origin.x = _pageOpened ? 0 : 320 * element;
[_scrollView scrollRectToVisible:frame animated:YES];
//[_scrollView setContentOffset:CGPointMake(-320 * element, 0) animated:YES];
if (!_pageOpened) {
[self.view removeConstraint:_constraintHeight];
_constraintHeight = [NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0];
[self.view addConstraint:_constraintHeight];
[self increaseStoriesSize];
} else {
[self.view removeConstraint:_constraintHeight];
_constraintHeight = [NSLayoutConstraint constraintWithItem:_scrollView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:253];
[self.view addConstraint:_constraintHeight];
[self decreaseStoriesSize];
}
[_scrollView setPagingEnabled:!_pageOpened];
[self.view setNeedsUpdateConstraints];
[_scrollView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
[_scrollView layoutIfNeeded];
} completion:^(BOOL finished) {
_pageOpened = !_pageOpened;
}];
}
- (void)increaseStoriesSize
{
for (NSLayoutConstraint *constraint in _contrainstArray) {
[constraint setConstant:320];
}
}
- (void)decreaseStoriesSize
{
for (NSLayoutConstraint *constraint in _contrainstArray) {
[constraint setConstant:143];
}
}
@end
//
// StoryView.m
// Stories
//
// Created by Christian Roman on 05/02/14.
// Copyright (c) 2014 Christian Roman. All rights reserved.
//
#import "StoryView.h"
@import QuartzCore;
@implementation StoryView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor whiteColor]];
[self.layer setCornerRadius:4.0];
[self.layer setBorderColor:[UIColor blackColor].CGColor];
[self.layer setBorderWidth:0.5];
}
return self;
}
@christianroman
Copy link
Author

@vic
Copy link

vic commented Feb 6, 2014

you are a crack

@dschesus
Copy link

dschesus commented Feb 7, 2014

Amazing!

@bohanxyz
Copy link

Tried with something similar ended up with updating frames with animations. You solution seems to be better. Like this!

@biyu
Copy link

biyu commented Feb 26, 2014

Very good practice of creating layout constraint programatically. Thumb up !

@Arrnas
Copy link

Arrnas commented Apr 5, 2014

are you able to expand views that are further away ( elements 4,5...) with the same animation? i've tried using your code at it seems that this only works when the scrollview doesn't need to scroll to a point thats more than 320 points away from the start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment