iOS Header StackView with correct alignment? - ios

I am trying to implement a UIView which will be a header. Note I am only focused on implementing the header (as shown below) in this question.
Here is how it is supposed to be look like (the HEADER is in yellow)
Basically, the header UIView should have a UIBUTTON all the way to the left and a UILabel exactly in the middle, nothing on the right
The problem I am having is how I will make the UIView for this.
My idea was have a main horizontal UIStackView, but if I put a UILabel and UIButton into it, how can I (in code) align it in the way I've described? I am unable to use the UI Builder for this, but have to lay it out in Objective C code.
#interface HeaderView : UIView
#implementation HeaderView {
UIStackView mainHorizontalStackView;
UIButton leftButton;
UILabel middleLabel;
}
-(instanceType) initializer(){
mainHorizontalStackView = ... //alloc
leftButton = ...
middleLabel = ...
// how do I set up the constraints to make it fit the desired setup?
}

This is a very basic example of creating your custom view:
HeaderView.h
//
// HeaderView.h
// Created by Don Mag on 4/7/20.
//
#import <UIKit/UIKit.h>
#interface HeaderView : UIView
#end
HeadView.m
//
// HeaderView.m
// Created by Don Mag on 4/7/20.
//
#import "HeaderView.h"
#interface HeaderView ()
#property (strong, nonatomic) UIButton *leftButton;
#property (strong, nonatomic) UILabel *centeredLabel;
#end
#implementation HeaderView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// default background color
self.backgroundColor = [UIColor colorWithRed:1.0 green:0.95 blue:0.8 alpha:1.0];
self.layer.borderColor = [UIColor brownColor].CGColor;
self.layer.borderWidth = 1.0;
self.layer.cornerRadius = 8.0;
_leftButton = [UIButton new];
[_leftButton setTitle:#"BUTTON" forState:UIControlStateNormal];
[_leftButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
_leftButton.translatesAutoresizingMaskIntoConstraints = NO;
_centeredLabel = [UILabel new];
_centeredLabel.text = #"LABEL";
_centeredLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_leftButton];
[self addSubview:_centeredLabel];
// adjust constant values if "padding" from edges desired
[NSLayoutConstraint activateConstraints:#[
// constrain button to left, top, bottom
[_leftButton.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:4.0],
[_leftButton.topAnchor constraintEqualToAnchor:self.topAnchor constant:8.0],
[_leftButton.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-8.0],
// constrain label centered horizontally in view, centered vertically to button
[_centeredLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
[_centeredLabel.centerYAnchor constraintEqualToAnchor:_leftButton.centerYAnchor],
]];
}
return self;
}
#end
TestViewController.h
//
// TestViewController.h
// Created by Don Mag on 4/7/20.
//
#import <UIKit/UIKit.h>
#interface TestViewController : UIViewController
#end
TestViewController.m
//
// TestViewController.m
// Created by Don Mag on 4/7/20.
//
#import "TestViewController.h"
#import "HeaderView.h"
#interface TestViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
HeaderView *v = [HeaderView new];
v.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:v];
// respect safe area
UILayoutGuide *g = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:#[
// constrain header view top / leading / trailing to self.view (safe area)
// adjust constant values if "padding" from edges desired
[v.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0],
[v.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:8.0],
[v.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-8.0],
]];
}
#end
Result:

Related

UIButton is not displaying below the TableView

I have a view-controller, to which I add a tableView, and a “Done” Button.
I’m able to add the tableview to my view controller successfully, but my “Done” button does not display.
The tableview is supposed to display at the top of the view, and the done button is supposed to display at the bottom, beneath the tableview.
Only the tableview displays and it takes up the whole screen.
Can you please advise what the issue is? Is there something wrong with my constraints?
Thanks!
#interface MyView : UIViewController<UITableViewDelegate, UITableViewDataSource>
#end
#interface MyView ()
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) UIButton *doneButton;
#end
#implementation MyView
- (void)viewDidLoad {
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:CGRectZero];
_tableView.delegate = self;
_tableView.dataSource = self;
self.view.backgroundColor = [UIColor yellowColor];
[_tableView registerClass:UITableViewCell.class forCellReuseIdentifier:#"cell"];
[self.view addSubview:_tableView];
[_tableView setTranslatesAutoresizingMaskIntoConstraints:NO];
[NSLayoutConstraint activateConstraints:#[
[_tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:10],
[_tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-10],
[_tableView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:20],
[_tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]];
self.view.largeContentTitle = #"Title";
self.title = #"Title";
_doneButton = [UIButton buttonWithType:UIButtonTypeSystem];
_doneButton.backgroundColor = [UIColor blueColor];
[self.view addSubview:_doneButton];
[_doneButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[NSLayoutConstraint activateConstraints:#[
[_doneButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[_doneButton.trailingAnchor constraintEqualToAnchor:_tableView.trailingAnchor],
[_doneButton.topAnchor constraintEqualToAnchor:_tableView.bottomAnchor],
[_doneButton.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]];
//[_tableView.bottomAnchor constraintEqualToAnchor:_doneButton.topAnchor].active = YES;
// Do any additional setup after loading the view.
}
Here's a screenshot, attached. The tableview appears in white and pink, while the view (which contains that tableview) is yellow. This yellow viewcontroller is presented on top of another view controller...
Attached screenshot, tableView contained inside a Yellow View - Done button is not displaying:

How to calculate UIViewController height before adding view to view tree?

I need to measure the height of a simple autolayout based VC for a given width. For example a simple UIViewController with only one label which is positioned using leading, trailing, top and bottom constraints to the VCs root view. The VC should not have a fixed size but automatically adapt to the label content.
This is only an example, of course the VC could have other content which is influences the size.
How can I calculate the VCs size for a given width and label content without adding it to the view hierarchy?
Background:
I am using a third party FormSheet control which allows to easily show any ViewController as form sheet with different styles, transitions, etc. The only downside is, that one has to specify a fixed sheet size before the VC is presented.
While this works great for VCs with "static" content / fixed sizes even a label with different texts for different languages might break the design.
Thus I am look for something like this:
ContentViewController *contentVC = [ContentViewController new];
CGRect contentBounds = [SomeClass calculateAutoLayoutHeightForView:contentVC.view withFixedWidth:500];
[ThirPartyFormSheetController presentController:contentVC withSize:contentBounds];
How can this be done?
Given a width, you can use systemLayoutSizeFittingSize:UILayoutFittingCompressedSize to determine what the height will be after auto-layout does its work.
Assuming constraints in the view-to-show are set up correctly:
CGFloat w = 500.0;
[loadedView.widthAnchor constraintEqualToConstant:w].active = YES;
// caluclate the size using FittingCompressedSize
CGSize contentBounds = [loadedView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
Here is a simple example (only need to assign the ViewController class to a view controller in Storyboard... no IBOutlets needed). Lots of comments in the code should make everything clear:
//
// ViewController.h
// Created by Don Mag on 4/8/19.
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
//
// ViewController.m
// Created by Don Mag on 4/8/19.
//
#import "ViewController.h"
#import "FormViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// add a button we'll use to show the form VC
UIButton *b = [UIButton new];
b.translatesAutoresizingMaskIntoConstraints = NO;
[b setTitle:#"Show Form" forState:UIControlStateNormal];
[b setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[b setBackgroundColor:[UIColor redColor]];
[self.view addSubview:b];
[NSLayoutConstraint activateConstraints:
#[
[b.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:20.0],
[b.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:0.75],
[b.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor]
]
];
[b addTarget:self action:#selector(loadAndShowForm:) forControlEvents:UIControlEventTouchUpInside];
}
- (void) loadAndShowForm:(id)sender {
// instantiate the form view controller
FormViewController *vc = [FormViewController new];
// get a reference to its view
UIView *v = vc.view;
// use auto-layout
v.translatesAutoresizingMaskIntoConstraints = NO;
// set the label text in the form view
vc.topLabel.text = #"This is a bunch of text for the TOP label in the Form VC";
vc.bottomLabel.text = #"This is a bunch of text for the BOTTOM label in the Form VC. It's enough text to cause a few lines of word-wrap, assuming we're running on an iPhone.";
// specify a width for the form view
// we'll use width of current view minus 60 (30-pts on each side)
CGFloat w = self.view.frame.size.width - 60.0;
[v.widthAnchor constraintEqualToConstant:w].active = YES;
// caluclate the size using FittingCompressedSize
CGSize contentBounds = [v systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
// because we set the width constraint, we now have the "compressed" height
//[ThirdPartyFormSheetController presentController:contentVC withSize:contentBounds];
// debugging from here down
NSLog(#"Auto-layout resulting size: %#", [NSValue valueWithCGSize:contentBounds]);
// set the height for the form view
[v.heightAnchor constraintEqualToConstant:contentBounds.height].active = YES;
// add it to the view, so we can confirm the height calculation
[self.view addSubview:v];
// center it on the view
[NSLayoutConstraint activateConstraints:
#[
[v.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
[v.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor]
]
];
}
#end
//
// FormViewController.h
// Created by Don Mag on 4/8/19.
//
#import <UIKit/UIKit.h>
#interface FormViewController : UIViewController
#property (strong, nonatomic) UILabel *topLabel;
#property (strong, nonatomic) UITextField *theTextField;
#property (strong, nonatomic) UILabel *bottomLabel;
#end
//
// FormViewController.m
// Created by Don Mag on 4/8/19.
//
#import "FormViewController.h"
#interface FormViewController ()
#end
#implementation FormViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
// create a multi-line "top label"
_topLabel = [UILabel new];
_topLabel.backgroundColor = [UIColor cyanColor];
_topLabel.text = #"Hello Top Label";
_topLabel.numberOfLines = 0;
// create a text field
_theTextField = [UITextField new];
_theTextField.backgroundColor = [UIColor greenColor]; // just to make it easy to see
_theTextField.borderStyle = UITextBorderStyleRoundedRect;
_theTextField.text = #"The Text Field";
// create a multi-line "bottom label"
_bottomLabel = [UILabel new];
_bottomLabel.backgroundColor = [UIColor cyanColor];
_bottomLabel.text = #"Hello Bottom Label";
_bottomLabel.numberOfLines = 0;
// we're using auto-layout and constraints
_topLabel.translatesAutoresizingMaskIntoConstraints = NO;
_theTextField.translatesAutoresizingMaskIntoConstraints = NO;
_bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
// add to view
[self.view addSubview:_topLabel];
[self.view addSubview:_theTextField];
[self.view addSubview:_bottomLabel];
// these elements and constraints will define the height of the content
[NSLayoutConstraint activateConstraints:
#[
// constrain top label leading, trailing and top to top of view, all at 20-pts
[_topLabel.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:20.0],
[_topLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0],
[_topLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0],
// constrain text field leading and trailing, and top to bottom of top label, all at 20-pts
[_theTextField.topAnchor constraintEqualToAnchor:_topLabel.bottomAnchor constant:20.0],
[_theTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0],
[_theTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0],
// constrain bottom label leading, trailing and top to bottom of text field, all at 20-pts
[_bottomLabel.topAnchor constraintEqualToAnchor:_theTextField.bottomAnchor constant:20.0],
[_bottomLabel.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-20.0],
[_bottomLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0],
// AND constrain bottom label to bottom of view at 20-pts
[_bottomLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0]
]
];
}
#end
The result (adding the loaded VC's view as a subview - see the comments in the code):
and with more text to show the automatic height calculation:
If you change the amount of text for the labels (set in ViewController.m), you will see that the height is calculated correctly.
Swift:
If all you need is to calculate height on the basis of label's text, you can use this solution
https://stackoverflow.com/a/25187891/7848711

Reuse xib in different screens

I have 4 screens that have one almost the same view:
And one screen have the same view but with slightly different UI:
So, my question: Can I use one xib and adapt states (active, inactive) and change ui for different screen? How I can do it?
Here is an example of this kind of class
In Your .m file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some screen like change labels and button text
}
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some another screen and change labels and button text
}
In Your .h file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
In your view controller where you want to display the custom UI
Create an instance of your xib or add through interfacebuilder
And On your instance of custom class call the method as required.
Below is a class I've used in one of my project to get a clear understanding.
#import <UIKit/UIKit.h>
#import "DYRateView.h"
#interface LevelAndRankDetails : UIView
#property (nonatomic, strong) IBOutlet UIView* contentView;
#property (nonatomic, strong) IBOutlet UIView* viewContainer;
#property (nonatomic, strong) IBOutlet UILabel* lblLevel;
#property (nonatomic, strong) IBOutlet UILabel* lblRanking;
#property (weak, nonatomic) IBOutlet DYRateView *viewRate;
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking;
- (void)setupUI;
#end
.m File
#import "LevelAndRankDetails.h"
#import "AppDelegate.h"
#import "Constants.h"
#implementation LevelAndRankDetails
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]){
[self commonSetup];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self commonSetup];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
}
- (void)viewFromNibForClass {
[[NSBundle mainBundle] loadNibNamed:[[self class] description] owner:self options:nil];
[self addSubview:self.contentView];
self.contentView.frame = self.bounds;
}
- (void)commonSetup {
[self viewFromNibForClass];
//For View's Corner Radius
self.contentView.layer.cornerRadius = 12;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = kDefaultBackgroundGreyColor;
self.viewContainer.backgroundColor = kDefaultBackgroundGreyColor;//[UIColor clearColor];
self.backgroundColor = kDefaultBackgroundGreyColor;
//self.viewContainer.backgroundColor = UIColorFromRGB(0xBB9657);//[kLearnFromLightColor colorWithAlphaComponent:0.5];
self.viewRate.rate = 0;
self.viewRate.editable = NO;
self.viewRate.delegate = nil;
self.viewRate.alignment = RateViewAlignmentCenter;
self.viewRate.backgroundColor = [UIColor clearColor];
[self.viewRate setEmptyStarImage:[UIImage imageNamed:#"StarEmpty"]];
UIImage* imageFullStar = [[UIImage imageNamed:#"StarFull"] imageTintedWithColor:kSliderDarkYellowColor];
[self.viewRate setFullStarImage:imageFullStar];
self.lblLevel.textColor = [UIColor whiteColor];
self.lblRanking.textColor = [UIColor whiteColor];
//For Teacher label
}
- (void)setupUI {
self.contentView.layer.cornerRadius = 0;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = [UIColor clearColor];
self.viewContainer.backgroundColor = [UIColor clearColor];//[UIColor clearColor];
self.backgroundColor = [UIColor clearColor];
}
- (void)setRanking:(CGFloat)ranking {
self.viewRate.rate = ranking;
}
- (void)setLevel:(NSNumber*)level {
self.lblLevel.text = [NSString stringWithFormat:#"Level : %#",level];
}
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking {
if (level.integerValue > 0) {
[self setLevel:level];
}
if (ranking.doubleValue > 0) {
CGFloat rankingConverted = ranking.floatValue;
[self setRanking:rankingConverted];
}
}
#end
And this is how you use it in your view controller
LevelAndRankDetails* toolTipCustomView = [[LevelAndRankDetails alloc] initWithFrame:CGRectMake(0, 0, 250, 66)];
toolTipCustomView.backgroundColor = [UIColor blackColor];
[toolTipCustomView setLevel:#(10) andRanking:#(3)];

iOS 7 zooming is not working in ScrollView with AutoLayout but working in iOS8/9

I have made a demo for zoom image using UIScrollView. My ViewController only contains one image.
The problem is the image cannot zoom in iO7 (I have tested on iPhone4S-iOS7) but work perfectly in iOS8/iOS9.
Any ideas on how to fix it?
Here is my code
#import "ViewController.h"
#interface ViewController ()<UIScrollViewDelegate>
#property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
#property (weak, nonatomic) IBOutlet UIView *contentview;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
float minimumScale = [_contentview frame].size.width /[_scrollview frame].size.width;
_scrollview.maximumZoomScale = 5; //Change as per you need
_scrollview.minimumZoomScale = minimumScale; //Change as you need
_scrollview.zoomScale = minimumScale;
_scrollview.delegate =self;
_scrollview.clipsToBounds = YES;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return self.contentview;
}
#end
Here is the layout structure
Screen.png constraint
ContentView constraint
ScrollView constraint
Here is my demo project
https://drive.google.com/file/d/0B679aXO0SBmMeUVHTUdOcmxJSXM/view
The height and width constraints are causing this in iOS 7. A workaround would be, removing those constraints for iOS 7 and calculate minimumScale manually. in IOS 8 and above, do not change anything.
- (void)viewDidLoad {
[super viewDidLoad];
float minimumScale = 1;
if (floor(NSFoundationVersionNumber) < NSFoundationVersionNumber_iOS_8_0) {
[self.view removeConstraints:self.heightWidthConstraints];
minimumScale = self.scrollview.frame.size.width / self.imageView.image.size.width;
}
_scrollview.maximumZoomScale = 5; //Change as per you need
_scrollview.minimumZoomScale = minimumScale; //Change as you need
//_scrollview.zoomScale = minimumScale;
_scrollview.delegate = self;
//_scrollview.clipsToBounds = YES;
[self.scrollview setZoomScale:minimumScale animated:YES];
}
Remove width and height contraint of contentView.
Add centralHorizontal constraint of contentView with scrollView
Let me know if it works.

Gracefully hiding and showing views when using autolayout

I thought there might be a way to easily hide and show a button in a row using auto layout so that views could be automatically arranged neatly depending on which are visible.
For example, say I have two buttons that I always want centered in a frame:
// pseudo visual format code:
|-----[star][download]-----|
When I press download I want now to see three buttons: (pause is the download button relabelled; cancel is a previously hidden button)
|--[star][cancel][pause ]--|
I thought I could perhaps have all three buttons always present but perhaps override the width to make the view gracefully animate between states? I thought there might be a more semantic way to achieve the adding and removing of views from the auto layout structure. Any thoughts?
I've put together a small sample showing how this could be done using a custom UIView subclass. In the example below, I've used the AutoLayout framework from this answer and I'd recommend you do the same; it keeps the constraint code clean and legible.
The general approach is that you have to keep pointers to the key constraints that bind the trailing edge of the left-hand buttons to the leading edge of those to the right and then use those pointers to dynamically add/remove constraints. Generally, you don't want to do too much of that because performance will suffer, but a small amount in response to a user action is OK.
My view is declared thus:
#protocol TSDownloadViewDelegate;
#interface TSDownloadView : UIView
#property (strong, nonatomic) id<TSDownloadViewDelegate> delegate;
#end
#protocol TSDownloadViewDelegate <NSObject>
- (void) downloadStartedInDownloadView:(TSDownloadView*)downloadView;
- (void) downloadPausedInDownloadView:(TSDownloadView *)downloadView;
- (void) downloadCancelledInDownloadView:(TSDownloadView*)downloadView;
#end
And implemented like this:
#import "UIView+AutoLayout.h"
#import "TSDownloadView.h"
static const CGFloat kMargin = 20.0;
#interface TSDownloadView ()
// Our buttons
#property (strong, nonatomic) UIButton * starButton;
#property (strong, nonatomic) UIButton * cancelButton;
#property (strong, nonatomic) UIButton * downloadButton;
// State tracking
#property (nonatomic) BOOL downloading;
#property (nonatomic) BOOL constraintsUpdated;
// The constraint governing what's tied to the right hand side of the starButton
#property (weak, nonatomic) NSLayoutConstraint *starRightConstraint;
// The constraint governing what's tied to the left hand side of the downloadButton
#property (weak, nonatomic) NSLayoutConstraint *downloadLeftConstraint;
#end
#implementation TSDownloadView
- (void) initializator
{
_starButton = [UIButton buttonWithType:UIButtonTypeSystem];
_cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
_downloadButton = [UIButton buttonWithType:UIButtonTypeSystem];
_starButton.translatesAutoresizingMaskIntoConstraints = NO;
_cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
_downloadButton.translatesAutoresizingMaskIntoConstraints = NO;
_starButton.titleLabel.textAlignment = NSTextAlignmentCenter;
_cancelButton.titleLabel.textAlignment = NSTextAlignmentCenter;
_downloadButton.titleLabel.textAlignment = NSTextAlignmentCenter;
[_starButton setTitle:#"Star" forState:UIControlStateNormal];
[_cancelButton setTitle:#"Cancel" forState:UIControlStateNormal];
[_downloadButton setTitle:#"Download" forState:UIControlStateNormal];
[_downloadButton addTarget:self action:#selector(downloadClicked:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_starButton];
[self addSubview:_cancelButton];
[self addSubview:_downloadButton];
_cancelButton.hidden = YES;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self initializator];
}
return self;
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if( self )
{
[self initializator];
}
return self;
}
- (void)downloadClicked:(id)sender
{
self.downloading = !self.downloading;
if( self.downloading )
{
[self.downloadButton setTitle:#"Pause" forState:UIControlStateNormal];
self.cancelButton.hidden = NO;
// Remove previous constraints
[self removeConstraint:self.starRightConstraint];
[self removeConstraint:self.downloadLeftConstraint];
// |--[star][cancel][pause ]--|
self.starRightConstraint = [self.starButton autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self.cancelButton withOffset:-kMargin];
self.downloadLeftConstraint = [self.downloadButton autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:self.cancelButton withOffset:kMargin];
// Tell delegate what's happened
if( self.delegate )
[self.delegate downloadStartedInDownloadView:self];
}
else
{
[self.downloadButton setTitle:#"Download" forState:UIControlStateNormal];
self.cancelButton.hidden = YES;
// Remove previous constraints
[self removeConstraint:self.starRightConstraint];
[self removeConstraint:self.downloadLeftConstraint];
// |-----[star][download]-----|
self.starRightConstraint = [self.starButton autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self.downloadButton withOffset:-kMargin];
self.downloadLeftConstraint = nil;
// Tell delegate what's happened
if( self.delegate )
[self.delegate downloadPausedInDownloadView:self];
}
}
- (void) updateConstraints
{
[super updateConstraints];
if( self.constraintsUpdated ) return;
self.constraintsUpdated = YES;
// Now put our constraints in place
// Make sure the button hugs the label and doesn't get stretched
// just because there's space available
[self.starButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
// Pin the starButton to the top, left and bottom edges of its superview
[self.starButton autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kMargin];
[self.starButton autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:kMargin];
[self.starButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kMargin];
// Repeat for the other buttons
[self.cancelButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[self.cancelButton autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kMargin];
[self.cancelButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kMargin];
[self.downloadButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[self.downloadButton autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kMargin];
[self.downloadButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kMargin];
[self.downloadButton autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:kMargin];
// These two are special. We keep a reference to them so we can replace
// them later. Note that since the cancelButton is hidden at the start,
// the initial value for downloadLeftConstraint is simply nil.
self.starRightConstraint = [self.starButton autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self.downloadButton withOffset:-kMargin];
self.downloadLeftConstraint = nil;
}
#end
There's a lot more work to do to make the view really functional, but hopefully you can see the general approach to take.
Design the (5) buttons one over the other using Autolayout.
//on ViewDidLoad: set cancel & pause button to hide
-(void) viewDidLoad
{
[_pauseBtn setHidden:YES];
[_cancelBtn setHidden:YES];
}
//on Downlaod action
-(IBAction) downloadClick (UIButton *) sender
{
[_pauseBtn setHidden:NO];
[_cancelBtn setHidden:NO];
[sender setHidden:YES];
}
this can only be achieve handling constraints from code:
http://www.techotopia.com/index.php/Implementing_iOS_6_Auto_Layout_Constraints_in_Code

Resources