Programatically adding views to the view controller's view using AutoLayout - ios

I have a view controller which I have created using code (no interface builder or storyboard). I am trying to programatically add few views (buttons and image views) and I am using Masonry for AutoLayout.
I have the following code
- (instancetype)init {
self = [super init];
if (self) {
self.view.backgroundColor = UIColor.whiteColor;
self.progress = 0.f;
self.shouldRecord = YES;
[self createMainUI];
[self addActions];
}
return self;
}
- (void)createMainUI {
self.backButton = [self.view createAndAddSubView:UIButton.class];
[self.backButton setImage:[TeamieUIGlobals defaultPicForPurpose:#"close" withSize:25.f] forState:UIControlStateNormal];
[self.backButton addTarget:self action:#selector(dismissViewController) forControlEvents:UIControlEventTouchUpInside];
self.micNormalImageView = [self.view createAndAddSubView:UIImageView.class];
self.dynamicProgress = [self.view createAndAddSubView:TMEProgressImageView.class];
self.dynamicProgress.image = IMAGE_MIC_WAVE;
self.dynamicProgress.progress = 0;
self.dynamicProgress.hasGrayscaleBackground = NO;
self.dynamicProgress.verticalProgress = YES;
self.recordButton = [self.view createAndAddSubView:UIButton.class];
self.recordButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.recordButton.backgroundColor = UIColor.redColor;
self.recordButton.layer.cornerRadius = 50.f;
self.recordButton.titleLabel.font = [TeamieGlobals appFontFor:#"regularFontWithSize13"];
[self.recordButton setTitle:#"Record" forState:UIControlStateNormal];
[self.recordButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[self.backButton mas_makeConstraints:^(MASConstraintMaker *make){
make.width.height.equalTo(#25);
make.left.top.equalTo(#10);
}];
[self.micNormalImageView mas_makeConstraints:^(MASConstraintMaker *make){
make.width.equalTo(#204);
make.height.equalTo(#295);
make.center.equalTo(self.view);
}];
[self.dynamicProgress mas_makeConstraints:^(MASConstraintMaker *make){
make.width.equalTo(#204);
make.height.equalTo(#295);
make.center.equalTo(self.view);
}];
[self.recordButton mas_makeConstraints:^(MASConstraintMaker *make){
make.width.height.equalTo(#100);
make.centerX.equalTo(self.view);
make.bottom.equalTo(self.view.mas_bottom).with.offset(15.f);
}];
}
This is what createAndAddSubView does
- (id)createAndAddSubView:(Class)modelClass {
id temporaryView = [modelClass new];
[self insertSubview:(UIView *)temporaryView atIndex:0];
return temporaryView;
}
The only view which appears on the view in the simulator is the backButton and no other view appears.
Also, the last 2 constraints added to the recordButton crashes the app and the error is "couldn't find a common superview for <UIButton: 0x7ff2eb15f110; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x7ff2eb118c60>> and <UIView: 0x7ff2e8f4bf20; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff2e8fdf220>>"
but when I pin the button, there is no error but still it is not visible on the view. Any idea why the views aren't appearing, something wrong with the code?

- (id)createAndAddSubView:(Class)modelClass {
id temporaryView = [modelClass new];
[self insertSubview:(UIView *)temporaryView atIndex:self.subviews.count];
return temporaryView;
}
Problem is with the atIndex:0 it should be self.subviews.count

I think the problem could be the index at which you are inserting the subviews on parent view. Substitute [[self subviews] count] in place of index '0' as-
- (id)createAndAddSubView:(Class)modelClass {
id temporaryView = [modelClass new];
[self insertSubview:(UIView *)temporaryView atIndex:[[self subviews] count]];
return temporaryView;
}

There are several concerns about the code presented above:
1. Apologise if missed this, however I dont see a code to set the frames of each sub view.
2. This is incorrect.
self.recordButton = [self.view createAndAddSubView:UIButton.class];
self.recordButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
3. You are adding each sub view on top of previously added subviews.
Please check all these aspects and I think your code should work.

Related

Scrollview should start from where I left it last time

I have a scrollview(timesScrollView) which is added as a subview on a view(dropDownView).The view is hidden until a particular button is pressed, when that button is pressed view will appear.
(IBAction)how_many_times_btn_click:(id)sender{
if(howMany==false){
for(UIView *view in dropDownView.subviews)
{
[view removeFromSuperview];
}
howMany=true;
duration=false;
how_many_times_btn.backgroundColor=[UIColor colorWithRed:130/255.0f green:189/255.0f blue:31/255.0f alpha:1.0f];
durationBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
startBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
dropDownView.hidden=NO;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,70);
dropDownView.backgroundColor=[UIColor colorWithRed:37/255.0f green:42/255.0f blue:54/255.0f alpha:1.0f];
//dropDownView.backgroundColor=[UIColor whiteColor];
targetLbl=[[UILabel alloc]init];
targetLbl.frame=CGRectMake(0, 30, dropDownView.frame.size.width,30);
targetLbl.text=#"TARGET";
targetLbl.textColor=[UIColor whiteColor];
targetLbl.font=[UIFont boldSystemFontOfSize:22];
targetLbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl=[[UILabel alloc]init];
how_many_Lbl.frame=CGRectMake(0, targetLbl.frame.origin.y+targetLbl.frame.size.height, dropDownView.frame.size.width, 20);
how_many_Lbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl.text=#"HOW MANY TIMES WILL YOU DO IT?";
how_many_Lbl.textColor=[UIColor colorWithRed:65/255.0f green:71/255.0f blue:80/255.0f alpha:1.0f];
how_many_Lbl.font=[UIFont systemFontOfSize:10.0f];
hideViewBtn=[UIButton buttonWithType:UIButtonTypeCustom];
hideViewBtn.frame=CGRectMake(dropDownView.frame.size.width-30,20,20,20);
[hideViewBtn setImage:[UIImage imageNamed:#"Close Icon [ x ]"] forState:UIControlStateNormal];
[hideViewBtn addTarget:self action:#selector(hideView) forControlEvents:UIControlEventTouchUpInside];
//hideViewBtn.backgroundColor=[UIColor whiteColor];
self.timesScroll=[[LTInfiniteScrollView alloc] initWithFrame:CGRectMake(0, how_many_Lbl.frame.origin.y+how_many_Lbl.frame.size.height+16, dropDownView.frame.size.width, 102)];
//self.timesScroll.backgroundColor=[UIColor whiteColor];
self.timesScroll.verticalScroll=NO;
self.timesScroll.dataSource=self;
self.timesScroll.maxScrollDistance=5;
self.timesScroll.contentInset=UIEdgeInsetsMake(0, self.timesScroll.frame.size.width/2-31, 0,self.timesScroll.frame.size.width/2-31 );
self.timesScroll.userInteractionEnabled=YES;
self.timesScroll.exclusiveTouch=YES;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,_timesScroll.frame.origin.y+_timesScroll.frame.size.height+20);
[self viewWillAppear:YES];
[dropDownView addSubview:targetLbl];
[dropDownView addSubview:how_many_Lbl];
[dropDownView addSubview:hideViewBtn];
[dropDownView addSubview:_timesScroll];
}
else
{
[self hideView];
}
}
The method above is what I am using to create view.
Now my problem is that when that particular button(how_many_times_btn) is pressed again all views are first removed then added as you can see and scrollview starts from initial position but I want it show from where I left it last time how_many_times_btn was clicked.
Hope you can understand What I am trying to say....if not I am happy to elaborate furthur.
you can get the last position by delegate methods
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
nslog(#"%f %f",scrollView.contentOffset.x,scrollView.contentOffset.y);
}
and store the x and y value and set
scrollView.contentOffset = CGPointMake(x,y);
You can save contentOffsetto one variable of CGPoint. And use this variable 's value later to scroll the UIScrollview.
Something like below line of code :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
contentOffset = scrollView.contentOffset;
}
When button pressed write below line of code:
self.timesScroll .contentOffset = contentOffset;
I'm using LTInfiniteScrollview in which there is a method 'reloadDataWithInitialIndex'
-(void)reloadDataWithInitialIndex:(NSInteger)initialIndex
{
for (UIView *view in self.scrollView.subviews) {
[view removeFromSuperview];
}
self.views = [NSMutableDictionary dictionary];
self.visibleViewCount = [self.dataSource numberOfVisibleViews];
self.totalViewCount = [self.dataSource numberOfViews];
[self updateSize];
_currentIndex = initialIndex;
self.scrollView.contentOffset = [self contentOffsetForIndex:_currentIndex];
[self reArrangeViews];
[self updateProgress];}
This method is called in 'viewWillAppear'
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.viewSize = CGRectGetWidth(self.view.frame) / Number_of_visibleViews;
self.timesScroll.delegate=self;
[self.timesScroll reloadDataWithInitialIndex:howIndex];}
I just passed previous index value here.

When UIButton is toggled Map View isn't filing the whole screen iOS

I am new to using MapView in iOS, here's my situation:
When I toggle the nearby button it will redirect me to map view:
Then when I toggle the List View button, it will display a UItableView with a Map Button. Then finally, when I toggle the map button it will display the Map View.
My problem is, when in list view then I scrolled down then toggle the map view button the map view doesn't fill the whole screen (please see image for reference):
Here's what i have so far:
This is how i initiate the Map:
- (void)viewDidLoad {
jobsMapView = [[MTJobsMapView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)];
jobsMapView.showsUserLocation = YES;
jobsMapView.zoomEnabled = YES;
jobsMapView.rotateEnabled = NO;
jobsMapView.parentViewController = self;
jobsMapView.delegate = jobsMapView;
// Set up buttons but hide them
showListViewButton = [UIButton buttonWithType:UIButtonTypeCustom];
showListViewButton.frame = CGRectMake(self.view.frame.size.width-58, self.view.frame.size.height-159, 50.0, 36.0);
[showListViewButton addTarget:self action:#selector(toggleNearbyView:) forControlEvents:UIControlEventTouchUpInside];
[showListViewButton setImage:[UIImage imageNamed:#"list.png"] forState:UIControlStateNormal];
[self.view addSubview:showListViewButton];
showMapViewButton = [UIButton buttonWithType:UIButtonTypeCustom];
showMapViewButton.frame = CGRectMake(self.view.frame.size.width-58, self.view.frame.size.height-159, 50.0, 36.0);
[showMapViewButton addTarget:self action:#selector(toggleNearbyView:) forControlEvents:UIControlEventTouchUpInside];
[showMapViewButton setImage:[UIImage imageNamed:#"icon_map.png"] forState:UIControlStateNormal];
[self.view addSubview:showMapViewButton];
// Default mapView is shown in Nearby View
showListViewButton.hidden = YES;
showListViewButton.enabled = NO;
showMapViewButton.hidden = YES;
showMapViewButton.enabled = NO;
self.listViewSelected = NO;
}
- (IBAction)toggleNearbyView:(UIButton *)sender {
self.listViewSelected = !self.listViewSelected;
if (self.listViewSelected) {
self.title=[NSString stringWithFormat:#"Nearby Jobs (%d)",[[self.jobsDictionary objectForKey:#"sub_slots"] count]];
// TableView is shown, so showMapViewButton for user to select MapView
showMapViewButton.hidden = NO;
showMapViewButton.enabled = YES;
showListViewButton.hidden = YES;
showListViewButton.enabled = NO;
[jobsMapView removeFromSuperview];
} else {
showListViewButton.hidden = NO;
showListViewButton.enabled = YES;
showMapViewButton.hidden = YES;
showMapViewButton.enabled = NO;
self.title=[NSString stringWithFormat:#"Nearby Jobs (%d)",[[self.FilterDictionary objectForKey:#"sub_slots"] count]];
[jobsMapView mapViewWithJobsDisplayed:self.FilterDictionary andUserLocation:xapp.self.userLocation andUserCoordinates:xapp.self.userLocationCoordinates];
[self.jobsTableView addSubview:jobsMapView];
}
}
what am doing wrong here?
Any help will be appreciated..
thanks...
Comment This line.
self.listViewSelected = !self.listViewSelected;
in toggleNearbyView method

ios : UIScrollView scrolling reset controls position to initials

I am creating a Register screen where if user want to change PIN he should tap on change PIN label and it will add two UITextField Controls (New PIN and Confirm New PIN) after PIN UITextField and push the below fields 100 pixels below.
The problem is when I try to scroll the view to see the below controls it resets the controls (which I moved down) to the initial positions.
ViewDidLoad
[NSTimer scheduledTimerWithTimeInterval:0.1
target:self selector:#selector(forScrollView)userInfo:nil repeats:NO];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(ShowChangePINFields:)];
singleTap.numberOfTapsRequired = 1;
_lblChangePIN.userInteractionEnabled = YES;
[_lblChangePIN addGestureRecognizer:singleTap];
- (void) forScrollView {
NSLog(#"setScrollEnabled");
[self.scrollview setScrollEnabled:YES];
[self.scrollview setContentSize:CGSizeMake(320, 900)]; // must be greater then the size in Storyboard
}// Dispose of any resources that can be recreated.
BOOL isNewPINShow = NO;
-(void)ShowChangePINFields:(UITapGestureRecognizer *)gestureRecognizer{
NSLog(#"setScrollEnabled");
isNewPINShow = NO;
if(!isNewPINShow)
{
// [[self scrollview] setContentOffset:self.scrollview.contentOffset animated:NO];
_tfNewPIN.hidden = NO;
_tfConfirmNewPIN.hidden = NO;
isNewPINShow = YES;
[UIView animateWithDuration:0.5 animations:^{
_tfConfirmNewPIN.frame = CGRectMake(306, 197, 292, 30);
_tfNewPIN.frame = CGRectMake(306, 245, 292, 30);
CGRect tempFrame = [_tfEmail frame];
tempFrame.origin.y = tempFrame.origin.y + 100;
_tfEmail.frame = tempFrame;
tempFrame = [_tfLanguage frame];
tempFrame.origin.y = tempFrame.origin.y + 100;
_tfLanguage.frame = tempFrame;
tempFrame = [_tfSecretQuestion frame];
tempFrame.origin.y = tempFrame.origin.y + 100;
_tfSecretQuestion.frame = tempFrame;
tempFrame = [_tfSecretAnswer frame];
tempFrame.origin.y = tempFrame.origin.y + 100;
_tfSecretAnswer.frame = tempFrame;
}];
}
}
Simply disable "Use Autolayout" in the File Inspector in your storyboard.
you need to move from
Scroll View > All Objects
to
Scroll View > View > All Objects
Below is a sample image

How to properly implement multiple subview operations in IPAD

I am creating an iPAD app. I have got a MAIN VIEW controller which covers the whole screen. And I have another class DROP-DOWN Class which i will be using to mimic the functionality of a drop-down as in Windows OS components. For that I am using a simple button, a scroll view and a few labels. I instantiate an object of that class and use it in my MAIN VIEW controller. To create the effect of a drop down, I alter the instance's views frame on the touch up of the button in toggle mode.(Click once, frame increased, click again frame decreased).
The creation part was fine, and the function to toggle to worked fine when implemented on a single instance of the DROP DOWN object.
But the problem comes when I instantiate these objects thru a for loop. The views seem to just vanish on button click.
Here is the code within the dropdowns.
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(10,54,100,50)];
scrollView.contentSize = CGSizeMake(50, 100);
for (int i = 0; i< 10; i++)
{
UILabel *newLable = [[UILabel alloc]initWithFrame:CGRectMake(0, 10*i, 100, 10)];
[newLable setFont:[UIFont boldSystemFontOfSize:10]];
newLable.text = [NSString stringWithFormat:#"Testing %i",i];
[scrollView addSubview:newLable];
}
scrollView.backgroundColor = [UIColor greenColor];
[self.view addSubview:scrollView];
}
-(IBAction)btnClicked:(id)sender
{
if (!isOpen) {
oldRect = self.view.frame;
CGRect newFrame = self.view.frame;
newFrame.size = CGSizeMake(190, 200);
NSLog(#"New Frame - %f,%f,%f,%f",self.view.frame.origin.x,self.view.frame.origin.y,self.view.frame.size.height,self.view.frame.size.width);
self.view.frame = newFrame;
}
else {
self.view.frame = oldRect;
NSLog(#"Old Frame - %f,%f,%f,%f",self.view.frame.origin.x,self.view.frame.origin.y,self.view.frame.size.height,self.view.frame.size.width);
}
isOpen = !isOpen;
}
And here is how this is called from the main view.
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:#selector(drawTheFilters)];
}
-(void)drawTheFilters
{
for (int i = 0; i<5 ; i++) {
DropDownView *dropView = [[DropDownView alloc]initWithNibName:#"DropDownView" bundle:[NSBundle mainBundle]];
CGRect newFrame = dropView.view.frame;
newFrame.origin = CGPointMake(200*i, 200);
dropView.view.frame = newFrame;
[self.view addSubview:dropView.view];
NSLog(#"Frame %i, %f,%f,%f,%f",i,dropView.view.frame.origin.x,dropView.view.frame.origin.y,dropView.view.frame.size.height,dropView.view.frame.size.width);
}
}

UIButton addTarget does not in invoke selector

Let me first state, that this is not a matter of getting my selector name right, nor setting up the button target in loadView, nor any other suggestion I've seen in the last 4 hours of browsing. I should also explain I am not using nibs, nor IB.
These buttons have been working for the bulk of development.
Then poof! It's not just the buttons. My table views do not scroll. Pressing the cells in the table views do not invoke the actions that I had setup.
It seems I've broken the responder chain entirely; or something to that effect.
To try and narrow down the source of the problem a created a window-based project; stripped out everything that xCode generates; deleted the nib; and copied in several methods from my original app delegate and my rootViewController.
It's the RVT that contains the subView that contains the buttons. Fairly straight forward. Same effect. I've literally stripped out all functional code but the following source in appDelegate.m:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setDelegate:self];
if(window == nil)
window = [[UIWindow alloc] init];
window.autoresizesSubviews = YES;
if(controller == nil)
controller = [[Controller alloc] init];
window.rootViewController = controller;
[window makeKeyAndVisible];
return YES;
}
-(void)dealloc {
[window release];
[controller release];
[super dealloc];
}
And in Controller:
- (void)buttonResponse {
NSLog(#"Button touched up inside!!!!!");
}
- (void)loadView {
[super loadView];
//test
button = [UIButton buttonWithType:UIButtonTypeCustom];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Button" ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
CGSize imageSize = [image size];
CGRect buttonFrame = CGRectMake(0,0,imageSize.width + 100, BUTTONBAR_H + 100);
button.frame = buttonFrame;
[button setImage:image forState:UIControlStateNormal];
button.backgroundColor = [UIColor blueColor];
[button setTitle:#"" forState:UIControlStateNormal];
button.userInteractionEnabled = YES;
[button addTarget:self action:#selector(buttonResponse) forControlEvents: UIControlEventTouchUpInside];
UIView *view = self.view;
CGRect viewFrame = view.frame; //self.view is valid and takes up available screen
[self.view addSubview:button];
[self.view bringSubviewToFront:button];
//end test
[self.view setNeedsDisplay];
}
- (void)dealloc {
[button release];
[super dealloc];
}
I know it's gotta be something really simple. But I can't see it. I would prefer to leave my hair in place. I'm wondering if that's going to happen as I continue to learn the quirks.
Does loadView ever get called? Put a NSLog (or a breakpoint) in loadView just as a sanity check.
Also, from UIViewController Documentation:
If you override this method (loadView) in order to create your views manually,
you should do so and assign the root view of your hierarchy to the
view property. (The views you create should be unique
instances and should not be shared with any other view controller
object.) Your custom implementation of this method should not call super.
If you want to perform any additional initialization of your views, do
so in the viewDidLoad method. In iOS 3.0 and later, you
should also override the viewDidUnload method to release any
references to the view or its contents.
Try putting all the button code in viewDidLoad:
- (void)buttonResponse:(id)sender {
NSLog(#"Button touched up inside!!!!!");
}
- (void)loadView {
// Dont call super (according to the UIViewController docs)
// [super loadView];
// self.view = ... however your setting up self.view
// self.view.frame = CGRectMake....
// self.view.etc...
[self.view setNeedsDisplay];
}
- (void)viewDidLoad {
[super viewDidLoad];
button = [UIButton buttonWithType:UIButtonTypeCustom];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Button" ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
CGSize imageSize = [image size];
CGRect buttonFrame = CGRectMake(0,0,imageSize.width + 100, BUTTONBAR_H + 100);
button.frame = buttonFrame;
[button setImage:image forState:UIControlStateNormal];
button.backgroundColor = [UIColor blueColor];
[button setTitle:#"" forState:UIControlStateNormal];
button.userInteractionEnabled = YES;
[button addTarget:self action:#selector(buttonResponse:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
[self.view bringSubviewToFront:button];
}
- (void)dealloc {
[button release];
[super dealloc];
}

Resources