SVPullToRefresh custom view causes layoutIfNeeded go into infinite loop - ios

I tried using custom views for the SVPullToRefresh but I've stumbled upon weird issue. I've made the demo project to illustrate the issue: https://github.com/gaks/SVRefreshProblem
The project is simply one UITableViewController with a TableView and the xib file with custom refresh bar view. The SVPullToRefresh is added to the tableView via the IBOutlet in the viewDidLoad: https://github.com/gaks/SVRefreshProblem/blob/master/SVRefreshProblem/DemoViewController.m
There is also a code that loads the RefreshBarView from the xib file and sets it as a custom view for SVPullToRefresh (for 'loading' state only for illustration):
RefreshBarView* refreshBarView = [[[NSBundle mainBundle] loadNibNamed:#"RefreshBarView" owner:self options:nil] objectAtIndex:0];
refreshBarView.bounds = CGRectMake(0, 0, 320, 60);
[[tableView pullToRefreshView] setCustomView:refreshBarView forState:SVPullToRefreshStateLoading];
The issue is that when you pull the table view to trigger the refresh it goes into infinite loop and eat-all-available-memory state after calling [self layoutIfNeeded] in the - (void)setState:(SVPullToRefreshState)newState. As far as I was able to debug it keeps calling - (void)layoutSubviews over and over.
What's weird is that when you open the xib file: https://github.com/gaks/SVRefreshProblem/blob/master/SVRefreshProblem/SVPullToRefresh/RefreshBarView.xib
... and remove the label from the view - it works just fine (except you have an empty view).
What am I doing wrong?

Loading from nibs is for ViewControllers, not views proper. You can try to do this programmatically which will work :
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 60)];
[v setBackgroundColor:[UIColor grayColor]];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 60)];
[label setText:#"asdf"];
[v addSubview:label];
[[tableView pullToRefreshView] setCustomView:v forState:SVPullToRefreshStateLoading];

Try to turn off "Use Auto Layout" in your nib.

Related

How to place UILabel in the center of navigation bar

How to place UILabel in the center of navigation bar in XCode 6? Is it possible at all? I can place here, for example, UIButton, but unable to place UILabel. If no, what can I do then? Place a UIButton with the appropriate text and make it non-clickable?
Thanks in advance.
In Xcode 6 if you want to put a label inside the UINavigationBar firstly you have to put a UIView there then put the UILabel inside the UIView (this is from the Storyboard btw).
If you do not put the UIView first then the UILabel will never get put onto the UINavigationBar.
Create a UIView and add UILabel as it's subview and then set your NavigationItem's titleView as previously created UIView.
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
label.text = #"Hello";
label.textAlignment = NSTextAlignmentCenter;
[view addSubview:label];
self.navigationItem.titleView = view;
Note: Don't forget to set your own frame values to get better result.
Just make sure you try viewWillLayoutSubviews method instead of viewDidLoad that was what worked for me. Cheers!

iOS - Why setting and displaying subviews in initWithNibName doesn't work?

I have a simple xib file which its layout is:
Which the pale green UIView is referenced to an IBOutlet view_content in my UIViewController class. Then I did the following in initWithNibName:bundle: of my ViewController.m:
self = [super initWithNibName:nibNameOrNil bundle:nil];
if (self) {
self.view_a = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
self.view_a.backgroundColor = [UIColor purpleColor];
[self.view_content addSubview:self.view_a];
self.view_b = [[UIView alloc] initWithFrame:CGRectMake(150, 150, 100, 100)];
self.view_b.backgroundColor = [UIColor blueColor];
[self.view_content addSubview:self.view_b];
self.view_c = [[UIView alloc] initWithFrame:CGRectMake(200, 200, 100, 100)];
self.view_c.backgroundColor = [UIColor greenColor];
[self.view_content addSubview:self.view_c];
}
return self;
I expected there will be 3 small squares, each with different colors as declared in the code above, but they did not show up which the view is loaded and showed. But instead if I move the addSubView: calls into viewDidLoad, they are displayed as expected. I tried to test if view_content is nil in the if-segment and seems it is nil at that time. I don't understands why this is happening and how it works, isn't the view and its components are supposed to be loaded from the xib?
Thanks for any help!
At the point initWithNibName:... is called, the view itself is not yet loaded. This is an optimization (lazy loading) that defers loading the view until it is actually needed. The view is actually loaded when viewController.view is first-time accessed, and that's when viewDidLoad is called.
Some people force the view controler to load its view by calling [viewController view] (or [self view] if it's within the view controller's class).
The reason is simple. View is not loaded at that time when you are initializing the controller means initWithNibName. So best place is viewDidLoad where your all outlet has been assigned.

When placing a subclassed PFLogInViewController object in a UIView, why does it appear outside the frame?

For a project I’m working on, I need to heavily customise the Parse.com login screen.
I realise that I need to subclass the PFLogInViewController, as well as do most of the modifications within the viewDidLayoutSubviews method. Also, I know I will eventually need to place elements of the PFLogInViewController into a UIView (which I’ll then place in a UITableViewCell), however I’m running into a strange problem.
When I try to add the self.loginview.dismissButton as a subview of a UIView I’ve called testView, the dismissButton does not appear within testView’s frame, it appears well outside of it (I set the x and y values of the dismissButton both to 0). However when I set testView.hidden to YES both objects are hidden.
Does anyone have any idea what I am doing wrong? Or perhaps any suggestion to work around this? I’ve listed the relevant code below
Thanks in advance.
- (void)viewDidLoad {
[super viewDidLoad];
[self.logInView.dismissButton removeFromSuperview];
UIView *testView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
[testView setBackgroundColor:[UIColor yellowColor]];
[testView addSubview:self.logInView.dismissButton];
[self.logInView addSubview:testView];
}
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.logInView.dismissButton setFrame:CGRectMake(0, 0, self.logInView.dismissButton.frame.size.width, self.logInView.frame.size.height)];
}

Xibs and Scrollview

I'm still pretty new at this, so bear with me. I thought I would be able to load a Xib in a ScrollView, as I have seen apps that seem to do this, but we're are talking two different classes. But I'll ask anyway - Is there any practical way to have a scrollView with a static Xib over the top, where buttons defined in the UI don't move while a view underneath does. I'm sure it's easily doable in cocos2d, but for what I want to do, it's a bit overkill.
--- Edit ---
At the risk of embarrassing myself, I tried both possible solutions. Adding a button grammatically adds a button that moves when I scroll. Adding the nib seems to keep the scroll screen from scrolling. Here's the code, without trying to add any buttons everything works fine.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"View Loaded");
[mdm setMapSetupInfoWithRows:60 columns:90 cellSize:32];
[mdm initMapDataWithOriginsUsingCenter:TRUE];
NSLog(#"MapViewContoller.mapArrayCount = %d",[[mdm mapArray]count]);
// create the MapView with the screen size create by MapDataManager
mapView = [[MapView alloc] initWithFrame:[mdm mapRect]];
// Create the UIScrollView to have the size of the window, matching the window (screen) size
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:[mdm windowRect]];
[scrollView setBounds:[mdm windowRect]];
// Tell the scrollview how big it is and set other options
[scrollView setContentSize:[mdm mapRect].size];
[scrollView setBounces:NO];
[scrollView setMinimumZoomScale:.5];
[scrollView setMaximumZoomScale:10];
[scrollView setDelegate:self];
[scrollView setBackgroundColor:[UIColor darkGrayColor]];
//add the MapView as a subview of the scrollView
[scrollView addSubview:mapView];
//add the scrollView to the current one....
[[self view] addSubview:scrollView];
[[NSBundle mainBundle] loadNibNamed:#"MapViewController" owner:self options:nil];
[self generNewMap];
}
Anything else I'm trying to do wrong? after looking at this more it does seem doable.
You should set things with a hierarchy like this.
UIViewController
UIScrollView
Static Buttons etc
Then in interface builder, or code, just add the static buttons etc to the self.view.
I do everything in code so it would look something like
-(void)viewDidLoad {
//add scrollview
appScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
appScroll.pagingEnabled = YES;
[appScroll setCanCancelContentTouches:NO];
appScroll.bounds = CGRectMake(0, 0, 320, 480);
appScroll.contentSize = CGSizeMake(1600, 480);
[appScroll setScrollEnabled:YES];
appScroll.bounces = NO;
appScroll.showsHorizontalScrollIndicator = NO;
appScroll.showsVerticalScrollIndicator = NO;
appScroll.clipsToBounds = YES;
appScroll.delaysContentTouches = YES;
appScroll.center = (CGPoint){ 160, 240 };
[appScroll setBackgroundColor:[UIColor darkGrayColor]];
[self.view addSubview:appScroll];
//back
backBut = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"back.png"]];
backBut.center = (CGPoint){ 40, 430 };
backBut.transform = CGAffineTransformMakeScale(0.3,0.3);
[backBut setUserInteractionEnabled: YES];
[self.view addSubview: backBut];
}
The trick is to specify the owner when loading the XIB. For example:
Define an IBOutlet on your UIViewController
#property (nonatomic, strong) IBOutlet UIView* myScrollViewContent
Create a XIB, specify the owner as your UIViewController class
Wire the components defined in the XIB to the outlets defined in the UIViewController class
Then in code do this:
//Because the owner is 'self' the bundle loader will inject any properties defined . .
//. . . . and wired in the XIB to the owner's outlets
[[NSBundle mainBundle] loadNibNamed:#"MyXibName" owner:self options:nil];
//Now do something with self.myScrollViewContent - ie add it to the scroll view.
Custom Scroll-view sub-class
If you wanted should be able to use the same approach by creating a cusom scroll-view subclass and specifying an outlet there. . . The UIView would be loaded directly onto the sub-class, then. . . (you'd still have to add it as sub-view).
For more complex requirements, I personally like to build my views with pure code, but it is possible to arrange things neatly with XIBs.

Changing programatic uiscrollview to IB

got a bit of a small problem here. I've been following this tutorial which creates an automatic scrolling slideshow using uiscrollview. This piece of code is used in my viewdidload -
UIScrollView *scr=[[UIScrollView alloc] initWithFrame:CGRectMake(0, 120, 320, 180)];
scr.tag = 1;
scr.autoresizingMask=UIViewAutoresizingNone;
[self.view addSubview:scr];
[self setupScrollView:scr];
UIPageControl *pgCtr = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 280, 320, 60)];
[pgCtr setTag:12];
pgCtr.numberOfPages=10;
pgCtr.autoresizingMask=UIViewAutoresizingNone;
[self.view addSubview:pgCtr];
As you can see a small uiscrollview is created programatically which is 320x180. It works perfectly except for the fact that my UI has another uiscrollview which takes up the whole ui, which is around 320x700. I need to embed this programatically created scrollview into it, any ideas? Or alternatively I need to create my own scrollview using storyboards and link it across using code, but have no idea how I would go about this.
Any ideas would be much appreciated.
You have to embed the scroll view inside the scroll view not the main view
[self.scrollView addSubview:scr];

Resources