I'm trying to make a animation that is done in Skype iOS application. The animation can be seen in this link Animation Section 3:Add a Contact
I tried with UIBezierPath but I can't do it. Any ideas?
Thanks!
My code
#implementation CustomView
#pragma mark - Lifecycle and initialize components
- (instancetype) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if ( self ) {
self.alpha = 0;
[self configureCancelButton];
[self configureCollectionView];
[self addSubview:self.cancelButton];
[self addSubview:self.collectionView];
}
return self;
}
- (void) configureCancelButton {
self.cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.cancelButton setTitle:#"Cancel" forState:UIControlStateNormal];
self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:20];
[self.cancelButton addTarget:self action:#selector (cancelView) forControlEvents:UIControlEventTouchUpInside];
self.cancelButton.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.8];
self.cancelButton.layer.cornerRadius = 7.f;
self.frameForCancelButton = CGRectMake (self.bounds.origin.x+5, self.bounds.size.height - kCancelButtonHeight - 5, self.bounds.size.width-10, kCancelButtonHeight);
self.cancelButton.frame = CGRectMake (self.frameForCancelButton.origin.x, self.frameForCancelButton.origin.y + kAnimationOffset, self.frameForCancelButton.size.width, self.frameForCancelButton.size.height);
}
- (void) configureCollectionView {
UICollectionViewFlowLayout *layout= [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(kItemSize, kItemSize);
layout.minimumInteritemSpacing = 3.0;
layout.sectionInset = UIEdgeInsetsMake(0, 7, 7, 10);
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.frameForCollectionView = CGRectMake(self.cancelButton.frame.origin.x, self.frame.size.height - (self.cancelButton.frame.size.height + 10 + kCollectionHeight), self.cancelButton.bounds.size.width, kCollectionHeight);
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake (self.frameForCollectionView.origin.x, self.frameForCollectionView.origin.y + kAnimationOffset, self.frameForCollectionView.size.width, self.frameForCollectionView.size.height)
collectionViewLayout:layout];
self.collectionView.backgroundColor = [UIColor colorWithWhite:1 alpha:.8];
[self.collectionView registerClass:[RAShareCell class] forCellWithReuseIdentifier:#"Cell"];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.layer.cornerRadius = 7.f;
}
#pragma mark - Public Methods
- (void) present {
[UIView animateWithDuration:0.35 animations:^{
self.alpha = 1;
self.darkView.alpha = .5;
}];
[UIView animateWithDuration:1.0 delay:0.45 options:(UIViewAnimationOptions) UIViewAnimationCurveEaseInOut animations:^{
[self setupAnimation];
} completion:nil];
}
- (void) cancelView {
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
self.cancelButton.frame = CGRectMake (self.frameForCancelButton.origin.x, self.frameForCancelButton.origin.y + kAnimationOffset, self.frameForCancelButton.size.width, self.frameForCancelButton.size.height);
self.collectionView.frame= CGRectMake(self.frameForCollectionView.origin.x, self.frameForCollectionView.origin.y + kAnimationOffset, self.frameForCollectionView.size.width, self.frameForCollectionView.size.height);
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
;
}
- (void) setupAnimation {
self.cancelButton.alpha = 1;
self.collectionView.alpha = 1;
self.cancelButton.frame = self.frameForCancelButton;
self.collectionView.frame = self.frameForCollectionView;
[self addShapeLayer];
}
- (void)addShapeLayer
{
self.shapeLayer = [CAShapeLayer layer];
self.shapeLayer.path = [[self pathAtInterval:0.0] CGPath];
self.shapeLayer.fillColor = [[UIColor redColor] CGColor];
self.shapeLayer.lineWidth = 3.0;
self.shapeLayer.strokeColor = [[UIColor redColor] CGColor];
[self.collectionView.layer insertSublayer:self.shapeLayer atIndex:0];
}
- (UIBezierPath *) pathAtInterval:(NSTimeInterval) interval {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(self.collectionView.frame.origin.x,self.collectionView.frame.origin.y)];
[path addQuadCurveToPoint:CGPointMake(self.collectionView.frame.size.width, self.collectionView.frame.origin.y) controlPoint:CGPointMake(self.collectionView.frame.size.width/2, self.collectionView.frame.origin.y-30)];
return path;
}
Your animation block does not contain any animations. You should move your setup outside of the animation block and then animate within it.
[self setupAnimation];
[UIView animateWithDuration:1.0 delay:0.45 options:(UIViewAnimationOptions) UIViewAnimationCurveEaseInOut animations:^{
// animate something
} completion:nil];
In addition to this, your intended animation does not have a linear progression, meaning that you'l want to use animateKeyframesWithDuration instead.
[UIView animateKeyframesWithDuration:1.0 delay:0.45 options:UIViewAnimationCurveEaseInOut animations:^{
for (NSInteger i = 0; i < 10; i++) {
[UIView addKeyframeWithRelativeStartTime:i/10.0
relativeDuration:1.0/10.0
animations:^{
self.shapeLayer = [self pathAtInterval:i/10.0];
}];
}
} completion:nil];
1, add the path you created to CAShaperLayer object;
2, see the "strokeStart" and "strokeEnd" properties in CAShapeLayer class;
3, add a animation which called "CABasicAnimation" to your Layer obj.
Related
Hi i am beginner in ios and in my project i am adding UIImage on UIScrollview and i have added tap gesture on UIImage
When we double click on UIImage then image should be zooming full screen size on view controller
After the full screen size image we can zoom it like any way what we want(i mean using like pinch zoom effect)here my requirement is when we double click on image then image need to set it's original position i have tried my level best but i did not get result please help me
my code is below:
#import "ViewController2.h"
#interface ViewController2 ()
{
UIScrollView * myScroll;
UITapGestureRecognizer *tap;
BOOL isFullScreen;
CGRect prevFrame;
UIImageView * _imageView;
}
#end
#implementation ViewController2
- (void)viewDidLoad
{
[super viewDidLoad];
isFullScreen = FALSE;
myScroll = [[UIScrollView alloc] init];
myScroll.frame = self.view.bounds;
myScroll.contentSize = CGSizeMake(_imageView.frame.size.width, _imageView.frame.size.height);
myScroll.maximumZoomScale = 4.0;
myScroll.minimumZoomScale = 1.0;
myScroll.clipsToBounds = YES;
myScroll.delegate = self;
myScroll.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:myScroll];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 300, 200)];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[_imageView setClipsToBounds:YES];
_imageView.userInteractionEnabled = YES;
_imageView.image = [UIImage imageNamed:#"ram.jpeg"];
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen:)];
tapper.numberOfTapsRequired = 1;
[_imageView addGestureRecognizer:tapper];
[myScroll addSubview:_imageView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageView;
}
-(void)imgToFullScreen:(UITapGestureRecognizer*)sender {
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
prevFrame = _imageView.frame;
[_imageView setFrame:[[UIScreen mainScreen] bounds]];
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[_imageView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = FALSE;
}];
return;
}
}
#end
I did some modifications in your code as like below try it .Check it give your wanted output or not.
#interface ScrollViewController ()<UIScrollViewDelegate>{
UIScrollView * myScroll;
UITapGestureRecognizer *tap;
BOOL isFullScreen;
CGRect prevFrame;
UIImageView * _imageView;
CGAffineTransform trans;
}
#end
#implementation ScrollViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
isFullScreen = FALSE;
myScroll = [[UIScrollView alloc] init];
myScroll.frame = [UIScreen mainScreen].bounds;
myScroll.contentSize = CGSizeMake(prevFrame.size.width, prevFrame.size.height);
myScroll.maximumZoomScale = 4.0;
myScroll.minimumZoomScale = 1.0;
myScroll.clipsToBounds = YES;
myScroll.delegate = self;
myScroll.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:myScroll];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 300, 200)];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[_imageView setClipsToBounds:YES];
_imageView.userInteractionEnabled = YES;
_imageView.image = [UIImage imageNamed:#"img.png"];
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen:)];
tapper.numberOfTapsRequired = 2;
[_imageView addGestureRecognizer:tapper];
[myScroll addSubview:_imageView];
prevFrame = _imageView.frame;
trans = _imageView.transform;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageView;
}
-(void)imgToFullScreen:(UITapGestureRecognizer*)sender {
if (!isFullScreen) {
myScroll.contentSize = prevFrame.size;
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
_imageView.frame = [UIScreen mainScreen].bounds;
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
myScroll.contentSize = CGSizeMake(prevFrame.size.width, prevFrame.size.height);
_imageView.transform = trans;
_imageView.frame = prevFrame;
NSLog(#"%# %#",NSStringFromCGSize(myScroll.contentSize),NSStringFromCGRect(prevFrame));
}completion:^(BOOL finished){
isFullScreen = FALSE;
}];
return;
}
}
I'm new to iOS development, and now working on an iOS app mainly using UINavigationController and UITableViewController.
The problem I try to solve is the UITableView (Custom tableView cell) layout broken bug on the root viewController. This happens when I back from a child viewController to the root viewController.(Left: Original, Right: Wrong Layout) It looks like UITableView position is moved for some reason, but I'm not sure why.
In MainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
viewFrame = self.view.bounds;
[self loadHeader];
[self loadTable];
self.view.backgroundColor = [UIColor whiteColor];
numberOfCellRow = 20;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)loadView {
[super loadView];
}
- (void)loadHeader {
CGRect headerFrame = viewFrame;
headerFrame.size.width = self.view.frame.size.width;
headerFrame.size.height = 200;
self.headerView = [[HeaderView alloc] initWithFrame:CGRectIntegral(headerFrame)];
[self.view addSubview:self.headerView];
NSLog(#"header loaded");
}
- (void)loadTable {
CGRect tableFrame = CGRectMake(viewFrame.origin.x, viewFrame.origin.y + 150,
viewFrame.size.width, viewFrame.size.height-150);
self.customTableView = [[UITableView alloc] initWithFrame:CGRectIntegral(tableFrame)];
self.customTableView.backgroundColor = [UIColor clearColor];
//set delegates
self.customTableView.delegate = self;
self.customTableView.dataSource = self;
//set custom cell
UINib *nib = [UINib nibWithNibName:#"CardViewCell" bundle:nil];
[self.customTableView registerNib:nib forCellReuseIdentifier:#"Cell"];
self.customTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:self.customTableView];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cell loaded");
dispatch_async(dispatch_get_main_queue(), ^{
[self loadData:indexPath];
});
}
- (void)loadData: (NSIndexPath *)indexPath {
_tableCell.titleLabel.text = [[_articles objectAtIndex:indexPath.row] title];
NSLog(#"%#", [[_articles objectAtIndex:indexPath.row] title]);
[_tableCell setNeedsLayout];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
_tableCell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
_tableCell.backgroundColor = [UIColor clearColor];
[_tableCell.contentView setUserInteractionEnabled: NO];
// add touch events
[_tableCell.button addTarget:self
action:#selector(cellPressed:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
NSLog(#"%#", NSStringFromCGRect(tableView.frame));
return _tableCell;
}
In CardViewCell.m
- (void)drawRect:(CGRect)rect {
//self.backgroundColor = [UIColor colorWithRed:228/255.0f green:228/255.0f blue:228/255.0f alpha:1.0f];
NSLog(#"%f", rect.origin.x);
self.backgroundColor = [UIColor clearColor];
[self drawCardView];
[self drawCardImage];
[self drawButton];
[self drawLabels];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.selectionStyle = UITableViewCellSelectionStyleNone;
}
- (void)drawCardImage {
_cardViewBounds = _cardView.bounds;
CGRect imageFrame = _cardViewBounds;
imageFrame.size.height = _cardViewBounds.size.height/2+40;
_cardImage = [[UIImageView alloc] initWithFrame:CGRectIntegral(imageFrame)];
_cardImage.image = [UIImage imageNamed:#"sampleImage"];
_cardImage.backgroundColor = [UIColor grayColor];
_cardImage.clipsToBounds = YES;
_cardImage.contentMode = UIViewContentModeScaleAspectFill;
_cardImage.userInteractionEnabled = YES;
_cardImage.tag = 100;
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:self.cardView.bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight)
cornerRadii:CGSizeMake(3.0, 3.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.cardView.bounds;
maskLayer.path = maskPath.CGPath;
_cardImage.layer.mask = maskLayer;
[self.cardView addSubview:_cardImage];
}
- (void)drawCardView {
CGRect screen = [[UIScreen mainScreen] bounds];
CGRect frame = CGRectMake(15, 25, (int)screen.size.width-30, 200);
_cardView.layer.cornerRadius = 3;
_cardView.backgroundColor = [UIColor greenColor];
_cardImage.userInteractionEnabled = YES;
_cardImage.tag = 101;
_cardView.frame = CGRectIntegral(frame);
CALayer *caLayer = _cardView.layer;
caLayer.frame = _cardView.frame;
caLayer.shadowRadius = 3.0f;
caLayer.shadowOpacity = 0.4f;
caLayer.shadowOffset = CGSizeMake(0.0f, 3.0f);
caLayer.shouldRasterize = YES;
// retina screen resolution
[caLayer setRasterizationScale:[[UIScreen mainScreen] scale]];
[caLayer setShouldRasterize:YES];
[self addSubview:_cardView];
}
- (void)drawButton {
CGRect buttonSize = CGRectMake(_cardViewBounds.size.width-100, _cardViewBounds.size.height/2+10, 50, 50);
_button = [[UIButton alloc] initWithFrame:CGRectIntegral(buttonSize)];
_button.layer.cornerRadius = 25;
_button.backgroundColor = [UIColor colorWithRed:0 green:169.0f/255.0f blue:244.0f/255.0f alpha:1.0f];
_button.userInteractionEnabled = YES;
_button.tag = 102;
//_button.titleLabel.text = #"+";
[_button setTitle:#"+" forState:UIControlStateNormal];
[_button.titleLabel setFont:[UIFont fontWithName:#"Helvetica" size:30.0]];
CALayer *caButtonLayer = _button.layer;
caButtonLayer.frame = _button.frame;
caButtonLayer.shadowRadius = 3.0f;
caButtonLayer.shadowOpacity = 0.2f;
caButtonLayer.shadowOffset = CGSizeMake(0.0f, 3.0f);
caButtonLayer.shouldRasterize = YES;
// retina screen resolution
[caButtonLayer setRasterizationScale:[[UIScreen mainScreen] scale]];
[caButtonLayer setShouldRasterize:YES];
[self.cardView addSubview:_button];
}
- (void)drawLabels {
CGRect titleLabelSize = CGRectMake( 10, _cardViewBounds.size.height-50, _cardViewBounds.size.width-20, 40);
_titleLabel = [[UILabel alloc] initWithFrame:CGRectIntegral(titleLabelSize)];
_titleLabel.backgroundColor = [UIColor clearColor];
_titleLabel.numberOfLines = 2;
_titleLabel.userInteractionEnabled = YES;
_titleLabel.tag = 103;
[_titleLabel setFont:[UIFont fontWithName:#"Helvetica" size:15.0]];
[_cardView addSubview:_titleLabel];
[_cardView sendSubviewToBack:_titleLabel];
}
- (void)prepareForReuse {
[super prepareForReuse];
for (UIView *subView in [self.contentView subviews]) {
[subView removeFromSuperview];
}
}
The code of this app is on this link.
Any ideas to solve this?
Your thoughts and help will be hugely appreciated.
the reason the view misplace is due to the _cardView.frame is CGRectZero when disappear, and I didn't find the solve yet.
you can add those to see the change.
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
NSLog(#"viewWillLayoutSubviews cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
NSLog(#"viewDidLayoutSubviews cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
NSLog(#"viewWillDisappear cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
NSLog(#"viewDidDisappear cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
I think you can learn more about life-cycle about viewController and Cell.
LifeCycle
by the way, when I watching your code, I don't know if you want to use xib or only code to programming. Like the code below, this is init from code but you try to get from xib.
just my opinion.
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
// make self from nib file
UINib *nib = [UINib nibWithNibName:#"HeaderView" bundle:nil];
self = [nib instantiateWithOwner:nil options:nil][0];
self.backgroundColor = [UIColor colorWithRed:0 green:169.0f/255.0f blue:244.0f/255.0f alpha:1.0f];
CGRect frame = CGRectZero;
frame.size.width = [[UIScreen mainScreen] bounds].size.width;
frame.size.height = 200;
[self setFrame:frame];
}
return self;
}
Alright, I'm almost positive I'm just doing something stupid, but I'm new to this, so please excuse my incompetence. I have a nested animation block, and it changes the view controller once it's finished - one problem. It fires prematurely. I don't know if it's me incorrectly changing the view controller, or the block is incorrect. Any help would be great. Thanks in advance.
SplashViewController.m
#import "SplashViewController.h"
#import "MenuViewController.h"
#interface SplashViewController ()
#end
#implementation SplashViewController
-(void) drawColoredBars
{
UIView *greenBar = [[UIView alloc] initWithFrame:CGRectMake(75.0, -self.view.bounds.size.height, 3.0, self.view.bounds.size.height)];
UIView *orangeBar = [[UIView alloc] initWithFrame:CGRectMake(87.5, -self.view.bounds.size.height - 25, 3.0, self.view.bounds.size.height)];
UIView *yellowBar = [[UIView alloc] initWithFrame:CGRectMake(100.0, -self.view.bounds.size.height - 50, 3.0, self.view.bounds.size.height)];
UIColor *green = [UIColor colorWithRed:142.0/255.0f green:149.0/255.0f blue:31.0/255.0f alpha:0.6f];
UIColor *orange = [UIColor colorWithRed:204.0/255.0f green:82.0/255.0f blue:29.0/255.0f alpha:0.6f];
UIColor *yellow = [UIColor colorWithRed:254.0/255.0f green:190.0/255.0f blue:16.0/255.0f alpha:0.6f];
greenBar.backgroundColor = green;
orangeBar.backgroundColor = orange;
yellowBar.backgroundColor = yellow;
greenBar.tag = 1;
orangeBar.tag = 2;
yellowBar.tag = 3;
[self.view addSubview:greenBar];
[self.view addSubview:orangeBar];
[self.view addSubview:yellowBar];
}
-(void) animate
{
MenuViewController *menu = [[MenuViewController alloc] init];
double delay = 0.0;
double x = 75.0;
for (int i = 1; i < 4; i++) {
CGRect frame = CGRectMake(x, 0.0, 3.0, self.view.bounds.size.height);
[UIView animateWithDuration: 2.5
delay: delay
options: UIViewAnimationOptionCurveEaseIn
animations:^{
[self.view viewWithTag:i].frame = frame;
}
completion:^(BOOL finished){
[UIView animateWithDuration: 2.5
delay: 2.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
self.view.alpha = 0.0;
}
completion:^(BOOL finished){
[self presentViewController:menu animated:NO completion:nil];
}];
}];
delay = delay + 0.5;
x = x + 12.5;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
CAGradientLayer *layer = [GradientBackground drawGradient];
layer.frame = self.view.bounds;
[self.view.layer insertSublayer:layer atIndex:0];
[self drawColoredBars];
[self animate];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Once again, thanks!
The viewDidLoad method is too early to set up animations. Try putting [self animate] in viewDidAppear: instead.
Also, make sure [self.view viewWithTag:i] doesn't return nil. If it returns nil, the outer animation block doesn't have anything to animate and will fire its completion block immediately.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have written a basic app in Objective-C which displays a users contacts with pictures. The issue is, there is no compartmentalization and I feel I am violating certain standards.
Everything is handled through one main ViewController, which begins the work mainly after a user taps a button (through an outlet to IB).
//
// ViewController.m
// Future Take 4
//
// Created by Rooz Mahdavian on 5/31/13.
// Copyright (c) 2013 Rooz Mahdavian. All rights reserved.
//
#import "ViewController.h"
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
#import <QuartzCore/QuartzCore.h>
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userAllowedForAccess)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[[self.view viewWithTag:300] addGestureRecognizer:singleTap];
[[self.view viewWithTag:300] setUserInteractionEnabled:YES];
CGRect tempButton = [self.view viewWithTag:300].frame;
tempButton.origin.y = self.view.frame.size.height/2 - 56;
[self.view viewWithTag:300].frame = tempButton;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: .4];
[UIView setAnimationDelay: 0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
CGRect tempButton2 = [self.view viewWithTag:300].frame;
tempButton2.origin.y += 90;
[self.view viewWithTag:300].frame = tempButton2;
[self.view viewWithTag:100].alpha = 1;
[UIView commitAnimations];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)userAllowedForAccess {
NSLog(#"User Has Verified Contacts");
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0,0, 320, 55)];
header.backgroundColor = [UIColor colorWithRed:34/255.0 green:34/255.0 blue:34/255.0 alpha:1];
[header.layer setShadowColor:[UIColor colorWithRed:14/255.0 green:14/255.0 blue:14/255.0 alpha:.5].CGColor];
[header.layer setShadowOpacity:0];
[header.layer setShadowRadius:3.0];
[header.layer setShadowOffset:CGSizeMake(2.0, 2.0)];
[self.view addSubview:header];
[self.view bringSubviewToFront:[self.view viewWithTag:100]];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: .7];
[UIView setAnimationDelay: 0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
CGRect tempLogo = [self.view viewWithTag:100].frame;
tempLogo.origin.y = -14;
tempLogo.size.height = tempLogo.size.height/2.5;
tempLogo.size.width = tempLogo.size.width/2.5;
tempLogo.origin.x = 160 - tempLogo.size.width/2;
[self.view viewWithTag:100].frame = tempLogo;
CGRect tempButton = [self.view viewWithTag:300].frame;
tempButton.size.width = tempButton.size.width * 2.5;
tempButton.size.height = tempButton.size.height * 2.5;
tempButton.origin.x = -((tempButton.size.width/2)-((tempButton.size.width * 2.5))/2);
[self.view viewWithTag:300].frame = tempButton;
[self.view viewWithTag:300].alpha = 0;
[self.view viewWithTag:200].alpha = 0;
[header.layer setShadowOpacity:1];
[UIView commitAnimations];
ABAddressBookRef addressBook = ABAddressBookCreate();
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height)];
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
int peopleInARow = 0;
int maxPeopleInARow = 3;
int positionFromTop = 20;
int IMAGE_SIZE = 70;
float animationOffset = .5;
float animationOffsetChange = .3;
float animationDuration = .5;
int scaleOffset = 40;
int screenWidth = 320;
int startingPositionFromLeft = 26;
int positionFromLeft = startingPositionFromLeft;
int topOffset = 40;
int leftOffset = 26;
int numberOfRows = 0;
UIView *contactContainer;
UIImage* image;
CALayer * l;
NSString* name;
NSString* lastName;
NSString* firstName;
UIImageView *newimageview;
UILabel *label;
UIView *contactImageContainer;
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
firstName = (__bridge_transfer NSString*)ABRecordCopyValue(person,
kABPersonFirstNameProperty);
lastName = (__bridge_transfer NSString*)ABRecordCopyValue(person,
kABPersonLastNameProperty);
name = [NSString stringWithFormat:#"%# %#", firstName, lastName];
if(ABPersonHasImageData(person)){
//NSLog(#"%#", name);
image = [UIImage imageWithData:(__bridge NSData *)ABPersonCopyImageData(person)];
//NSLog(#"Position %i", positionFromLeft);
newimageview = [[UIImageView alloc] initWithFrame:CGRectMake(-scaleOffset/2, -scaleOffset/2, IMAGE_SIZE+scaleOffset, IMAGE_SIZE+scaleOffset)];
newimageview.contentMode = UIViewContentModeScaleAspectFit;
[newimageview setImage: image];
contactContainer = [[UIView alloc] initWithFrame:CGRectMake(positionFromLeft, positionFromTop + 20, IMAGE_SIZE, 200)];
contactImageContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, IMAGE_SIZE, IMAGE_SIZE)];
contactImageContainer.clipsToBounds = YES;
l = [contactImageContainer layer];
[l setMasksToBounds:YES];
[l setCornerRadius:IMAGE_SIZE/2];
// You can even add a border
[l setBorderWidth:0.0];
[l setBorderColor:[[UIColor colorWithRed:234.0/255.0 green:234.0/255.0 blue:234.0/255.0 alpha:.6] CGColor]];
[contactImageContainer addSubview:newimageview];
[contactContainer addSubview:contactImageContainer];
label = [[UILabel alloc] initWithFrame: CGRectMake(0, IMAGE_SIZE + 10, IMAGE_SIZE, 20)];
label.text = firstName;
label.backgroundColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0];
label.textColor = [UIColor whiteColor];
[label setTextAlignment:NSTextAlignmentCenter];
[label setFont:[UIFont fontWithName:#"Arial-BoldMT" size:14]];
[contactContainer addSubview:label];
contactContainer.alpha = 0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationDelay:animationOffset];
animationOffset+= animationOffsetChange;
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
contactContainer.alpha = 1;
CGRect temp = contactContainer.frame;
temp.origin.y = positionFromTop;
contactContainer.frame = temp;
[UIView commitAnimations];
if(peopleInARow >= 2){
positionFromTop += IMAGE_SIZE + topOffset;
peopleInARow = 0;
positionFromLeft = startingPositionFromLeft;
numberOfRows++;
} else {
peopleInARow += 1;
positionFromLeft += IMAGE_SIZE + leftOffset;
}
[scroll addSubview:contactContainer];
[scroll bringSubviewToFront:contactContainer];
}
}
NSLog(#"%i", numberOfRows);
scroll.contentSize = CGSizeMake(screenWidth, 150 * numberOfRows);
scroll.pagingEnabled = NO;
[self.view addSubview:scroll];
[self.view bringSubviewToFront:scroll];
}
- (IBAction)userDeniedAccess:(id)sender {
NSLog(#"Denied");
}
#end
Can anyone tell me the best way to rewrite this and what standard/conventions (probably in MVC) I am doing wrong?
You're not violating MVC at any thing. The view controller loads some contacts and displays them in the view. The model, represented by the contact, and the views have no coupling at all. That's correct from MVC's point of view.
As you said, this is a simple app. You may need to add some design to your code if the applications gets bigger and more complicated. But this design is good for such level of complexity. For example, if this class get bigger and more complex, you may separate the contacts loading part into a new class.
However, there's a very bad thing about your code. The method userAllowedForAccess contains more than 100 lines of code. Modularity must be maintained in the level of classes as well as methods and functions. Separate the code to many methods, depending on the function it performs. For example:
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0,0, 320, 55)];
header.backgroundColor = [UIColor colorWithRed:34/255.0 green:34/255.0 blue:34/255.0 alpha:1];
[header.layer setShadowColor:[UIColor colorWithRed:14/255.0 green:14/255.0 blue:14/255.0 alpha:.5].CGColor];
[header.layer setShadowOpacity:0];
[header.layer setShadowRadius:3.0];
[header.layer setShadowOffset:CGSizeMake(2.0, 2.0)];
[self.view addSubview:header];
[self.view bringSubviewToFront:[self.view viewWithTag:100]];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: .7];
[UIView setAnimationDelay: 0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
Can be extracted in a method called - (void) setupHeaderView and you can make another method to load the contacts - (NSArray *) getContacts or just - (NSArray *) contacts to match Objective-C's style for getters definition.
I would start refactoring your
- (IBAction)userAllowedForAccess
method in smaller and atomic methods. It's usually a bad idea to have one method that does basically everything.
I have a parent view that allows you to see post in a UITableView. In its Navigation Bar I have a post button that when pressed presents a UIView subclass and shows it on the top of the screen. I have an image on that UIView that when tapped I want to present the UIImagePickerController to allow users to pick an image to post to the service. How can I do this since my subview is not a view controller it cannot present the UIImagePickerController.
Below is my subview code.
#import "PostView.h"
#implementation PostView
#synthesize attachedLabel;
#synthesize postButton;
#synthesize textView;
#synthesize characterLimit;
#synthesize attachImage;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
originalFrame = frame;
NSArray *xib = [[NSBundle mainBundle] loadNibNamed:#"PostView" owner:self options:nil];
PostView *view = [xib objectAtIndex:0];
[view setBackgroundColor:[UIColor whiteColor]];
[view setAlpha:0.7f];
attachedLabel = [[UILabel alloc] initWithFrame:CGRectMake(204, 212, 56, 21)];
attachedLabel.textColor = [UIColor blackColor];
[attachedLabel setText:#"Attached"];
attachedLabel.backgroundColor = [UIColor clearColor];
attachedLabel.font = [UIFont fontWithName:text_font_name size:12.0];
characterLimit = [[UILabel alloc] initWithFrame:CGRectMake(246, 13, 50, 21)];
[characterLimit setTextAlignment:NSTextAlignmentRight];
characterLimit.textColor = [UIColor blackColor];
characterLimit.backgroundColor = [UIColor clearColor];
characterLimit.font = [UIFont fontWithName:text_font_name size:12.0];
attachImage = [[UIImageView alloc] initWithFrame:CGRectMake(270, 208, 30, 30)];
[attachImage setImage:[UIImage imageNamed:#"attachphoto30x30.png"]];
[self.textView setDelegate:self];
[self.textView setAlpha:0.7f];
[self.textView setTextColor:[UIColor whiteColor]];
[self.textView setBackgroundColor:[UIColor clearColor]];
self.layer.cornerRadius = 10.0f;
self.layer.masksToBounds = YES;
[self addSubview:view];
[self addSubview:characterLimit];
[self addSubview:attachedLabel];
[self addSubview:attachImage];
}
return self;
}
- (IBAction)openCamera:(id)sender
{
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
controller.delegate = self;
//[self presentViewController:controller animated:YES completion:nil];
NSLog(#"%#", #"Image Tapped");
}
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
/*[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *image = [info objectForKey: UIImagePickerControllerOriginalImage];
UIImage *scale = [image scaleToSize:CGSizeMake(320.0f, 548.0f)];
imageData = UIImageJPEGRepresentation(scale, 1);
encodedImage = [self Base64Encode:imageData];
[attachedLabel setHidden:NO];
*/
}
#pragma mark Custom alert methods
- (IBAction)postAction:(id)sender
{
[self hide];
}
- (void)show
{
//prepare attachImage
attachImage.userInteractionEnabled = YES;
UITapGestureRecognizer *tapAttach = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(openCamera:)];
tapAttach.numberOfTapsRequired = 1;
[self.attachImage addGestureRecognizer:tapAttach];
isShown = YES;
self.transform = CGAffineTransformMakeScale(0.1, 0.1);
self.alpha = 0;
[UIView beginAnimations:#"showAlert" context:nil];
[self setBackgroundColor:[UIColor clearColor]];
[UIView setAnimationDelegate:self];
self.transform = CGAffineTransformMakeScale(1.1, 1.1);
self.alpha = 1;
[UIView commitAnimations];
}
- (void)hide
{
isShown = NO;
[UIView beginAnimations:#"hideAlert" context:nil];
[UIView setAnimationDelegate:self];
[[NSNotificationCenter defaultCenter] postNotificationName:#"hidePostView_Notification" object:nil];
self.transform = CGAffineTransformMakeScale(0.1, 0.1);
self.alpha = 0;
[UIView commitAnimations];
}
- (void)toggle
{
if (isShown)
{
[self hide];
} else
{
[self show];
}
}
#pragma mark Animation delegate
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
if ([animationID isEqualToString:#"showAlert"])
{
if (finished)
{
[UIView beginAnimations:nil context:nil];
self.transform = CGAffineTransformMakeScale(1.0, 1.0);
[UIView commitAnimations];
}
} else if ([animationID isEqualToString:#"hideAlert"])
{
if (finished)
{
self.transform = CGAffineTransformMakeScale(1.0, 1.0);
self.frame = originalFrame;
}
}
}
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return YES;
}
- (BOOL)textView:(UITextView *)textViewer shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string
{
if ([string isEqualToString:#"\n"])
{
[textViewer resignFirstResponder];
}
return [self isAcceptableTextLength:textViewer.text.length + string.length - range.length];
}
-(IBAction)checkIfCorrectLength:(id)sender
{
if (![self isAcceptableTextLength:self.textView.text.length])
{
// do something to make text shorter
}
}
- (BOOL)isAcceptableTextLength:(NSUInteger)length
{
return length <= 160;
}
- (void)textViewDidChange:(UITextView *)textViewer
{
NSString *characters = [[NSString stringWithFormat:#"%d", textViewer.text.length] stringByAppendingString:#"/160"];
NSLog(#"%#", characters);
[self updateDisplay:characters];
}
-(void) updateDisplay : (NSString *)str
{
[self.characterLimit performSelectorOnMainThread : # selector(setText : ) withObject:str waitUntilDone:YES];
}
#end
Yes, you can not present a viewcontroller from a UIView subclass.
To solve this problem, you can use your subview's superview's viewcontroller class. calling [self.superview nextResponder] in your subview will return you the superview's viewcontroller. Using that you can present your UIImagePicker view controller. To use the presentViewController method, you should cast [self.superview nextResponder] to your parentviewcontroller's class type. Also make sure you import parentview controller.h inside subview.m file
[(YourParentViewController *)[self.superview nextResponder] presentViewController:controller animated:YES completion:nil];
You should present a UIViewController subclass rather than a UIView subclass.
I would also say that UIViewController should be responsible for handling data and operational logic for its views. Check out some of the docs:
View Controller Basics:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/AboutViewControllers/AboutViewControllers.html
UIViewController Class Reference:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/AboutViewControllers/AboutViewControllers.html