UIScrollView Custom ViewController - ios

I have an odd situation. I want user to choose a category by clicking an button inside UIScrollView. Here's the relevant code of page view controller (the one containing UIScrollView made with IB):
- (void)viewDidLoad
{
[super viewDidLoad];
uiScroll.contentSize = CGSizeMake([[SawData shared].categories count]*320,480);
int i = 0;
for (NSString* key in [SawData shared].categories) {
Baton *b = [[Baton alloc] initWithNibName:#"Baton" bundle:nil];
b.view.frame = CGRectMake(i++*320, 0, 320, 480);
[uiScroll addSubview:b.view];
[b release];
}
}
Baton is new UIViewController subclass containing only one button with touchUp action that prints some log info using NSLog. With this code I get the Batons properly arranged side by side. Problem is that clicking the button gives EXC_BAD_ACCESS as Batons view controller is released.
If i remove the [b release]; line I have Batons overlayed one over other as i++ * 320 is giving same result (which i checked and its correct). In this case click on button is working.
Thank you for help!
iOS SDK 4.3
EDIT 1:
After much trial and error, I have managed to find out whats happening. Its 320px width of controls. If i changed them to 321 or 319 all works as it should. I dont need to release the controller to image fill the UIScrollView content AND clicking the button works. What the hell is this?

This might be the reason.
Baton *b = [[Baton alloc] initWithNibName:#"Baton" bundle:nil] autorelease];
You should also make sure that the UIButton is initialized before you click on it. You can do this easily with the debugger.
Take a look here
Does UIView's addSubview really retain the view?

Related

Tableview frame issue when put in a scrollview

I wanted to post a gif but apparently I don't have enough reputation. Oh well, whatever; I was using UIPageViewController, but for some reason I decided to go with a more manual solution by using UIScrollView and adding the views of UITableViewControlllers to the corresponding offsets (pages). I have 4 UItableViewControllers on each page (the views of table view controllers) and all of these are added to the container view controller (which has the UIScrollView) as child view controllers.
The actual problem is when I made the switch, table views began refusing to go all the way down and part of the final table view cell stays trimmed by the end of the screen when the scrolling ends.
So, wanted to ask if anyone came across something like this before of know how to get rid of this. I know I could always use a library, but I want to learn. Here is some code:
_containerScrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
_containerScrollView.contentSize = CGSizeMake(_containerScrollView.frame.size.width * 4, 0.0f);
_containerScrollView.pagingEnabled = YES;
[self.view addSubview:_containerScrollView];
UITableViewController *vc1 = [[UIViewController alloc] init];
UITableViewController *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:#"trendingViewController"];
UITableViewController *vc3 = [self.storyboard instantiateViewControllerWithIdentifier:#"placesViewController"];
UITableViewController *vc4 = [self.storyboard instantiateViewControllerWithIdentifier:#"favoritesViewController"];
self.rallyViewControllers = [NSArray vc1, vc2, vc3, vc4, nil];
[self addViewControllers];
Other methods;
- (void)addViewControllers{
if (self.rallyViewControllers == nil) {
return;
}
for (int i = 0; i < [self.rallyViewControllers count]; i++) {
UIViewController* viewController = [self.rallyViewControllers objectAtIndex:i];
[self addChildViewController:viewController];
[viewController didMoveToParentViewController:self];
[_containerScrollView addSubview:viewController.view];
}
}
This is called in viewDidLayoutSubviews
- (void)configureFrames{
if (self.rallyViewControllers == nil) {
return;
}
CGFloat width = _containerScrollView.frame.size.width;
CGFloat height = _containerScrollView.frame.size.height;
for (int i = 0; i < [self.rallyViewControllers count]; i++) {
UIViewController *viewController = [self.rallyViewControllers objectAtIndex:i];
viewController.view.frame = CGRectMake(i * width, 0.0f, width, height);
}
}
I should state upfront that I didnt completely understand your description of
"table views began refusing to go all the way down and part of the
final table view cell stays trimmed by the end of the screen when the
scrolling ends."
My answer is based on an issue I faced before. My setup is a uitableview in the storyboard container view ( without any parent scrollview)
I faced this issue where part of the tableview was cut off and I could not see about 5 bottom rows.
Turns out I did not have any constraints setup between the parent container view and the tableview.
To determine if your tableviews are rendering fine, get your project running in XCode and then press on the below button
This button will then pause your app and give you a visual stack of the the different views that are currently rendered in your app. You can then see if any of the children ( in your case tableviews) are rendered outside the frame of the parent view in which case that portion will not be visible. This indicates that you either dont have constraints (or) the current constraints you have are incorrect.
I got it. The problem was when I added the view controllers views to the scroll view, they returned dimensions as if there was no navigation bar. But they were still positioned under the navigation bar, which caused total view to have 64 pt more height than the screen could show. when I manually subtracted 64 pt from views, and it was fixed. But since that is a very crude way of doing this, I then tried to fix it by fiddling with auto-layout, which ended up fine.

How to reset or restart root view of UIViewController to its original state?

I am new to iOS Development. I have a very simple UIViewController, with two button in the view. I am allowing users to edit UI components or drag and drop from one place to another. Now I want to implement reset functionality allowing users to reset UI to its original stage discarding all the changes.
As mentioned in several post tried setNeedsDisplay but looks like its not right way to achieve this. What are the my options ?
e.g. In Android world, you can finish current Activity (Equivalent of UIViewController) and relaunch self to achieve original state. Is it possible to do something like it in iOS.
- (IBAction)resetButtonClicked:(id)sender {
// Now I want discard all the changes on the screen
// On some button click or specific action from user.
// Tried calling setNeedsDisplay as pointed in few others answers but somehow
// setNeedsDisplay does not reload my ViewController.
// [self.view setNeedsDisplay];
}
I have done something similar. What I did was:
1) create local CGRect variables for each frame ui control i.e. CGRect originalFrame1;
2) get the original frame position for each ui control and store them on viewDidLoad i.e. originalFrame1 = _frame1.frame;
3) on the resetButtonClicked set it back to is original position _frame1.frame = originalFrame1;
I can think of two options:
1- Save the positions of your initial state, and when the user clicks the reset button, just put those buttons on their initial states.
2- OR (strange way of doing it), you can initialise the same controller you are in and just present it from itself, that should be somehow close to your android approach. You'll get the same controller on its initial state (If you didn't didn't dismiss the first one, you should)
Hope that helps :)
u can save the positions for all subviews(buttons,label,...) in the main view.
self.view.subview it will return array contain all elements u have it :)
and when u wanna rest your view just get the old position for each subview from the array.
NSArray *arrayOfView = [view subviews];
//also:
NSMutableArray *mutableArrayOfView = [[view subviews] mutableCopy];
for (UIImageView *imageView in imageViewArray) //uiimageview or whatever your subview //is you can check by using isKindofClass. `if ([view isKindOfClass:[UIImageView class]])`
{
//let's set frame for image view before adding to
[myimageView setFrame:imageview.frame];//or something like that
}
EVery app will have a keyWindow object for which you should assign some viewController to display.
window.rootViewController = [[UIViewController alloc] init];
Lets say your controller's class is CustomViewController
So, in your app delegate,didFinishLaunchingWithOptions, you will write
self.window.rootViewController = [[CustomViewController alloc] init];
And the function invoked when you click reset button be as below,
-(void)reset{
// reset the view with default
self.view.window.rootViewController = [[CustomViewController alloc] init];
}
If you follow above code, it won't have any memory leaks because ,when you set rootViewController again ,the old one will be lost and removed from memory.

Add clickable and fixed subview to UITableViewController?

I'd like to place an ADBannerView object onto my UITableView screen statically, what means that I want it to always stay above my toolbar (self.navigationController.toolbar), even when the user is scrolling the tableview. I've solved this by adding by ADBannerView as a subview to my toolbar and given it negative values for the frames origin:
[self setBannerViewSize];
[self.navigationController.toolbar addSubview:bannerView];
The only problem is: I can't click and open the iAd this way - I can see the banner but nothing happens when I tap on it.
Since I'm also using a refreshControl, the option to use a UIViewController instead of UITableViewController and add a tableView manually wouldn't work for me. Is there any other way I can get my ADBannerView statically showing in my table view controller AND still being tappable?
Thank you in advice!
Yay!! After all I succeeded in solving this (really annoying) problem by myself (and a lot of reading around)!
First, I found this really world-changing post. Basically this post handles with the topic that a UITableViewController uses self.view for its tableView property, so overriding the tableView property (or synthesizing it manually) plus giving self.view a new view (from application) and adding tableView as its subview would make it possible to reach the real superview of tableView.
But this still didn't solve my problem, although I was sure it would, because it all made sense. My bannerView appeared in the right place (and was fixed) but it still didn't do anything when clicked. But there was a second minor thing I didn't know about:
As I read in this post the superview of a subview doesn't only have to be userInteractionEnabled but also have a non-transparent backgroundColor. Because my superviews background color was set to [UIColor clearColor] it all didn't work - but setting its backGroundColor to e.g. blackColor solved the whole problem: the bannerView got finally tappable! :)
So, my code is now looking like this:
#synthesize tableView;
- (void)viewDidLoad
{
[super viewDidLoad];
if (!tableView && [self.view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)self.view;
}
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
self.tableView.frame = self.view.bounds;
[self.view addSubview:self.tableView];
[self resizeTableToFitBanner];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:bannerView];
// some other code
}
BannerViewController in Apple's iAdSuite sample code solves this problem very elegantly:
https://developer.apple.com/library/ios/samplecode/iAdSuite/Introduction/Intro.html
I think you should use a container view, and set things up in IB. You can add a tool bar and ADBannerView to the bottom of the view of your navigation controller's root view controller. Fill the rest of the space with a container view - this will give you an embedded view controller automatically. You should delete this one and then drag in a tableViewController and control drag from the container view to the tableViewController to hook up the embed segue.

Push view controller after setting view

Suppose i have a uiview in 1 screen and i want to view the same view in fullscreen mode on click of a button.
On click of a button the following function is called.
-(IBAction)fullScreen
{
FullScreenViewController *mv = [[FullScreenViewController alloc] init];
mv.fullview = minimizedView;
//minimizedView is a UIView already created with a specified frame
// fullview is a UIView decalred in FullScreenViewController
[[self navigationController] pushViewController:mv animated:YES];
}
In the FullScreenViewController.m the viewDidLoad function is as follows :
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:fullview];
}
On click of the fullscreen button, the view appears but on click of back button, the minimized view in the previous page dissapears.
Is it wrong to do this?
You dont need to use two views to implement this. In your code, your are navigating from one view to another view. You dont need to do that. Your minimizeView itself having a property "setFrame:" to increase and decrease its frame to resize of that subview in your current view itself. Learn how to resize the UIView.

iPad presentModalViewController appears in wrong position

First of, I get the feeling apple really doesnt like us optimizing apps for landscape view.
After struggling with my app for 2 days I finally convince it to always and only show in Landscape mode. I even convinced the UIViewController that I present with presentModalViewController to appear in landscape as well. So far so good...
The position of the UIViewController that I present with UIModalPresentationFormSheet is all the way to the bottom right (with the ipad in Landscape positition). I cannot get it to move to the center like it should. Does anyone have any ideas why and or how this works and how I can make it apear in the right position?
EDIT: Added code, this code is called from a UIViewController when a button is pushed.
- (void) buttonPushed
{
pickerViewController = [[UIViewController alloc] init];
[pickerViewController.view setBackgroundColor:[UIColor whiteColor]];
_pickerCustomers = [[UIPickerView alloc] initWithFrame:CGRectMake(22,20,380,216)];
_pickerCustomers.delegate = self;
_pickerCustomers.dataSource = self;
[_pickerCustomers setShowsSelectionIndicator:YES];
[pickerViewController.view addSubview:_pickerCustomers];
_btnPickerDone = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_btnPickerDone setFrame: CGRectMake(300,250,98,45)];
[_btnPickerDone setTitle:#"Select" forState:UIControlStateNormal];
[pickerViewController.view addSubview:_btnPickerDone];
pickerViewController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:pickerViewController animated:YES];
}
Have you tried playing with the little "autoposition springs" on the layout IB? Probably you have it attached to the bottom and right, simply remove those attachments.
Here's a link for you: http://disanji.net/iOS_Doc/#documentation/DeveloperTools/Conceptual/IB_UserGuide/Layout/Layout.html
Can also be done in code if you like.

Resources