This is what my view controller looks like with these two table views. As you can see, the left looks like the frame is in the intended place and the right does not. I've posted my code and the origin y is in the same place in both. What could be causing this?
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CGFloat halfLength = self.view.frame.size.width / 2;
CGRect ingredientsFrame = CGRectMake(0, 0, halfLength - 1, self.view.frame.size.height);
CGRect modsFrame = CGRectMake(halfLength + 1, 0, halfLength - 1, self.view.frame.size.height);
_ingredientsTableView = [[UITableView alloc] initWithFrame:ingredientsFrame style:UITableViewStyleGrouped];
_ingredientsTableView.delegate = self;
_ingredientsTableView.dataSource = self;
_ingredientsTableView.tag = 1;
[self.view addSubview:_ingredientsTableView];
_modsTableView = [[UITableView alloc] initWithFrame:modsFrame style:UITableViewStyleGrouped];
_modsTableView.delegate = self;
_modsTableView.dataSource = self;
_modsTableView.tag = 2;
[self.view addSubview:_modsTableView];
}
You need to set the second table view's contentInset and scrollIndicatorInsets to compensate for the fact that the top of the table view is up underneath the navigation bar.
The reason you don't see the same problem in the first table view is that this done for you automatically for the first scroll view in your interface.
Related
I'm dealing with a tricky bug on my app. I have a chat view controller where I deal with keyboard showing and hiding. But the weird part is when putting the app on background.
This is the view controller before going to background (tapping the home button)
And this is the app when returning from background
If I put the app on background using the home button, the black screen only appears for a second, but if I block the phone and then unlock, the black screen keeps there.
This is how I deal with the keyboard
- (void)keyboardWillShowWithRect:(CGRect)rect
{
//We adjust inverted insets because tableview will be inverted
CGFloat displacementDistance = rect.size.height - self.composeBarView.bounds.size.height;
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, displacementDistance, 0);
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - displacementDistance, self.view.frame.size.width, self.view.frame.size.height)];
}
- (void)keyboardWillDismissWithRect:(CGRect)rect
{
//We adjust inverted insets because tableview will be inverted
CGFloat displacementDistance = rect.size.height - self.composeBarView.bounds.size.height;
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, 0, 0);
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + displacementDistance, self.view.frame.size.width, self.view.frame.size.height)];
}
The tableView used to display the messages is inverted in order to display the first message at the bottom. Here's how I do it:
- (void)setupTableView
{
self.tableView.delegate = self;
self.tableView.dataSource = self;
//We adjust inverted insets because tableview will be inverted
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, 0, 0);
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 500.0;
self.tableView.sectionFooterHeight = 30.0;
self.tableView.showsVerticalScrollIndicator = NO;
[self.tableView registerNib:[UINib nibWithNibName:#"MessagesDateHeader" bundle:nil] forHeaderFooterViewReuseIdentifier:#"MessagesDateHeader"];
// Table View is inverted so we display last messages at the bottom instead of top
self.tableView.transform = CGAffineTransformMakeRotation(-M_PI);
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapOnTableView)];
tap.numberOfTapsRequired = 1;
[self.tableView addGestureRecognizer:tap];
}
Also, I have self.definesPresentationContext = YES; set on viewDidLoad
Anyone can give me a hint of what's happening?
Thanks
I used to have a similar problem. Issue was the resizing of the tableView when keyboard appears/disappears based on its frame.
What I did was set a constraint between the bottom of the tableView and the superView and then change its constant with the appearance/disappearance of the keyboard.
Instead of relying on keyboardWillShowWithRect: and keyboardWillDismissWithRect: you can use listen to UIKeyboardWillChangeFrameNotification and handle it like follows
- (void) keyboardWillChangeFrame:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd toView:nil];
[UIView animateWithDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]
delay:0.f
options:[userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue] << 16
animations:^{
self.bottomConstraint.constant = CGRectGetHeight(self.view.frame) - keyboardFrameEnd.origin.y;
[self.view layoutIfNeeded];
} completion:nil];
}
[self.view layoutIfNeeded] is used so that view shows the whole animation
Is it possible to use UIScrollViewController to scroll or "page" two or more views coming from UIViewControllers?
Example (in viewDidLoad)
self.a1 = [[CustomViewController1 alloc] init];
self.a2 = [[CustomViewController2 alloc] init];
//Scroller
self.scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,1000,400
400)];
[self.scroller addSubview:self.a1.view];
[self.scroller addSubview:self.a2.view];
[self.view addSubview:self.scroller];
But I can see in the scroller only the view of controller a2.
You need to set the frames of the views so they they sit one below another. Currently they are both there, just on top of one another.
Try putting in
self.a2.view.frame = CGRectMake(0, 480, 320, 480);
You have to modify the frames aswell. Now a1 and a2 have the same, and they are on top of eachother, so the a2 is visible, because you added the later.
Try
self.a2.view.frame = CGRectOffset(self.a2.view.frame, self.a1.view.frame.size.width, 0);
The solution is to set the frame coordinates of the subviews inside the scroller:
CGRect frame = CGRectMake(0, 0, 1000, 600);
self.a1 = [[CustomViewController1 alloc] init];
self.a1.view.frame = frame;
self.a2 = [[CustomViewController2 alloc] init];
frame.origin.x = frame.size.width +10;
self.a2.view.frame = frame;
[self.scroller addSubview:self.a1.view];
[self.scroller addSubview:self.a2.view];
[self.view addSubview:self.scroller];
You'll need to add the custom view controllers as child view controllers. See Apple's documentation for more information on doing that correctly.
I have a UIView which is located offscreen and I'm animating the frame so that the view slides in offscreen from the bottom and is visible. I'd like to simultaneously animate the alpha property of a UILabel on the view as well so it fades in. Unfortunately it appears I can't do the alpha animation because the view is offscreen and doesn't appear to take hold. It looks something like this:
nextCell.titleLabel.alpha = 0;
[UIView animateWithDuration:collapsedAnimationDuration animations:^{
CGRect newFrame = lastCell.frame;
newFrame.origin = CGPointMake(lastCell.frame.origin.x , lastCell.frame.origin.y + THREAD_CELL_HEIGHT);
nextCell.frame = newFrame;
nextCell.titleLabel.alpha = 1;
}];
Is it not possible to start animating the alpha of the subview because it's offscreen? If I position the view on screen and then try the animation it looks great but that's not the effect I'm going for. Thanks for your help.
Is this code executed in cellForRowAtIndexPath? If so, try moving it to tableView:willDisplayCell:forRowAtIndexPath:. The table view resets various properties of the cell before displaying it.
From the AppDelegate didFinishLaunching method:
self.myView = [[MyView alloc] initWithFrame:CGRectMake(320, 480, 400, 400)];
self.myView.titleLabel.text = #"test text";
self.myView.titleLabel.alpha = 0;
[UIView animateWithDuration:10.0 animations:^{
CGRect newFrame = self.myView.frame;
newFrame.origin = CGPointMake(0 , 0);
self.myView.frame = newFrame;
self.myView.titleLabel.alpha = 1;
}];
[self.viewController.view addSubview:self.myView];
MyView is just this:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self addSubview:self.titleLabel];
}
return self;
}
- (UILabel *)titleLabel
{
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
}
return _titleLabel;
}
I did no important changes to the code you presented and it worked fine. So assuming you're not doing what Tim mentioned (it won't work if you're doing it), we need more details to help you out.
Disclaimer: I'm something of an iOS n00b. I have a navigation-based app -- i.e., in my AppDelegate, I create the nav frame:
self.navigation_controller = [[UINavigationController alloc] initWithRootViewController:home_view_controller];
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
self.window.rootViewController = navigation_controller;
self.window.makeKeyAndVisible;
Inside the frame of my home view, I want a search bar, then the scrollable table view. So, I wrote this:
- viewDidLoad{
(HomeView*)home_view = [[HomeView alloc] init];
self.view = home_view
self.view.backgroundColor = [UIColor whiteColor]
(UITableView*)self.table_view = [UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.table_view.bounds.origin.y += 44;
self.table_view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.table_view.dataSource = self;
self.table_view.delegate = self;
[self.view addSubview:self.table_view];
search_frame = self.view.bounds;
search_frame.origin.y = 48.0;
search_frame.size.height = 48.0;
self.search_bar = [[UISearchBar alloc] initWithFrame:search_frame)];
[self.view addSubview:self.search_bar];
}
The table view displays fine, but occupies all the space below the navigation bar. I want to have the navigation bar, then immediately below it the search bar, followed by the table view. At the point of viewDidLoad, the UITableView does not yet have a non-zero bounding rect and I expect that's part of the problem. Additionally, I've specified UIViewAutoresizingFlexibleHeight in my autoresizingMask when I really want it glued against the search bar -- again, I believe this may be part of the problem.
What have I misunderstood here?
Thanks
Steve,
Try following changes:
1) Set tableview's frame using:
CGRect targetRect = CGRectMake(0, 48, self.view.frame.size.width, self.view.frame.size.heigth);
(UITableView*)self.table_view = [UITableView alloc] initWithFrame:targetRect style:UITableViewStylePlain];
2) Add following autosize mask also:
// This value will anchor your table view with top margin
UIViewAutoresizingFlexibleBottomMargin
3) Set searchbar's frame to following rect frame:
CGRecttMake(0, 0, self.view.frame.size.width, 48);
What I would do, is just add the UISearchBar as the first UITableView header.
(method: tableView:viewForHeaderInSection:)
Check this blog post:
http://jainmarket.blogspot.com/2009/08/add-searchbar-as-uitableviews-header.html
In my app, I have a split screen in which the detail view is a scrollview. I have 5 tables which are subviews of my scrollview in which 3 table views are side by side on top and 2 table views are side by side on bottom
I have already implemented a way in which when I click any of the rows of any of the table in the scrollview, that view disappears and another view zooms into its position.
I write the following code in the didSelectRowAtIndexPath in the middle table subview,
CGFloat xpos = self.view.frame.origin.x;
CGFloat ypos = self.view.frame.origin.y;
self.view.frame = CGRectMake(xpos+100,ypos+150,5,5);
[UIView beginAnimations:#"Zoom" context:NULL];
[UIView setAnimationDuration:2];
self.view.frame = CGRectMake(xpos,ypos,220,310);
[UIView commitAnimations];
[self.view addSubview:popContents.view];
popContents is the view I need to zoom into to the view previously occupied by that particular table view and that happens correctly.
However the problem that I am facing is that since there is another table subview in the side, if I increase the frame size to say 250 or so, the part of the zoomed in view gets hidden by the tableview on the side ( as its as if a part of the zoomed in view goes under the tableview on the side).
Is there anyway to correct this so that my zoomed in view would not get hidden by the tableviews on its sides?
I hope I have explained my problem correctly...
UPDATE:
Here is the code I am using for adding the subviews for the scrollview
// Scroll view
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 30, 1000, 740)];
scrollView.contentSize = CGSizeMake(1000, 700);
scrollView.delegate = self;
scrollView.scrollEnabled = YES;
scrollView.showsHorizontalScrollIndicator = YES;
scrollView.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
[self.view addSubview:scrollView];
aView = [[aViewController alloc] initWithNibName:#"aViewController" bundle:nil];
aView.view.frame = CGRectMake(10, 25, 220, 310);
[aView loadList:objPatients];
[scrollView addSubview:aView.view];
bView = [[bViewController alloc] initWithNibName:#"bViewController" bundle:nil];
bView.view.frame = CGRectMake(10, 350, 220, 310);
[bView loadList:objPatients];
[scrollView addSubview:bView.view];
cView = [[cViewController alloc] initWithNibName:#"cViewController" bundle:nil];
cView.view.frame = CGRectMake(240, 25, 220, 310);
[cView loadList:objPatients];
[scrollView addSubview:cView.view];
dView = [[dViewController alloc] initWithNibName:#"dViewController" bundle:nil];
enView.view.frame = CGRectMake(240, 350, 220, 310);
[enView loadList:objPatients];
[scrollView addSubview:dView.view];
eView = [[eViewController alloc] initWithNibName:#"eViewController" bundle:nil];
eView.view.frame = CGRectMake(470, 25, 220, 310);
[eView loadList:objPatients];
[scrollView addSubview:eView.view];
say for example, I add the code for didSelectRowAtIndexPath in cViewController subview...
This is a guess since I would need to know how your table views are added to the scroll view, but the middle table view was probably added before the one on the side. Views are "stacked" in the order they're added with the last one on top. You'll need to get the scroll view to move the middle view to the front with this method
- (void)bringSubviewToFront:(UIView *)view
The best way to do that would be to create a protocol for the table views and make the scroll view the delegate. The method would be something like this
- (void) moveAViewToFront: (MyTableView *) aTableView
{
[self.view bringSubviewToFront: aTableView.view];
}
You would then call the delegate method before setting up the animation.
Edited
After a little more thought I realized that the subviews have a reference to their superview so this bit of code should provide an idea on how to solve the problem. I created a test app which has a view controller which adds two sub views. The view controller header file is MoveSubviewViewController.h
#import <UIKit/UIKit.h>
#interface MoveSubviewViewController : UIViewController
{
}
#end
and it's implementation is
#import "MoveSubviewViewController.h"
#import "MoveableSubview.h"
#implementation MoveSubviewViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Create two overlapping subviews. The blue subview will start at the top of
// the frame and extend down two thirds of the frame.
CGRect superviewFrame = self.view.frame;
CGRect view1Frame = CGRectMake( superviewFrame.origin.x, superviewFrame.origin.y,
superviewFrame.size.width, superviewFrame.size.height * 2 / 3);
MoveableSubview *view1 = [[MoveableSubview alloc] initWithFrame: view1Frame];
view1.backgroundColor = [UIColor blueColor];
[self.view addSubview: view1];
[view1 release];
// The green subview will start one third of the way down the frame and
// extend all the to the bottom.
CGRect view2Frame = CGRectMake( superviewFrame.origin.x,
superviewFrame.origin.y + superviewFrame.size.height / 3,
superviewFrame.size.width, superviewFrame.size.height * 2 / 3);
MoveableSubview *view2 = [[MoveableSubview alloc] initWithFrame: view2Frame];
view2.backgroundColor = [UIColor greenColor];
[self.view addSubview: view2];
[view2 release];
}
#end
The subview class is MoveableSubview with another simple header
#import <UIKit/UIKit.h>
#interface MoveableSubview : UIView
{
}
#end
and implementation
#import "MoveableSubview.h"
#implementation MoveableSubview
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// Move this view to the front in the superview.
[self.superview bringSubviewToFront: self];
}
#end
The thing to do is to add the
[self.superview bringSubviewToFront: self];
line before setting up the animation.