Is it possible to disable the scrolling of tableHeaderView (Not to be confused with section header).Right now whenever I scroll the table, view in the tableHeaderView also gets scrolled.
What i am doing:
I have a class subclassed from UITableViewController.
In storyboard, I am using the static table view.
Table style is Grouped and I have added 8 sections having a row each.
On the top of 1st section, added a view which is the tableHeaderView.
I want to disable the scrolling of view with title "Profile" when I scroll the table.
PS:
I know this is achievable if I subclassed my class from UIViewController instead of UITableViewController.
But I don't want to UIViewController because I am using storyboard for designing static cell and If I use UIViewController instead of UITableViewController then compiler throws a warning "Static table views are only valid when embedded in UITableViewController instances"
Please let me know which is the best approach to achieve this.Is it possible to disable the scrolling of tableHeader using my current approach or do I need to use UIViewController instead.
Just use an embed segue with a parent UIViewController consisting of a header view and a container view. Embed your UITableViewController in the container view. More specific steps in this answer.
If you want everything in UITableViewController, you can insert your own subview doing something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.header = [[UIView alloc] init];
self.header.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, 44);
self.header.backgroundColor = [UIColor greenColor];
[self.tableView addSubview:self.header];
self.tableView.contentInset = UIEdgeInsetsMake(44, 0, 0, 0);
}
and then manipulate the position of the view in scrollViewDidScroll and friends:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
self.header.transform = CGAffineTransformMakeTranslation(0, self.tableView.contentOffset.y);
}
I say "and friends" because you'd need to take care of the corner cases like scrollViewDidScrollToTop:. scrollViewDidScroll gets called in every display cycle during scrolling, so doing it this way looks flawless.
Timothy Moose was spot on. Here are the necessary changes for iOS8.
MonoTouch (C#)
// create the fixed header view
headerView = new UIView() {
Frame = new RectangleF(0,0,this.View.Frame.Width,44),
AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
BackgroundColor = UIColor.DarkGray
};
// make it the top most layer
headerView.Layer.ZPosition = 1.0f;
// add directly to tableview, do not use TableViewHeader
TableView.AddSubview(headerView);
// TableView will start at the bottom of the nav bar
this.EdgesForExtendedLayout = UIRectEdge.None;
// move the content down the size of the header view
TableView.ContentInset = new UIEdgeInsets(headerView.Bounds.Height,0,0,0);
.....
[Export("scrollViewDidScroll:")]
public virtual void Scrolled(UIScrollView scrollView)
{
// Keeps header fixed, this is called in the displayLink layer so it wont skip.
if(headerView!=null) headerView.Transform = CGAffineTransform.MakeTranslation(0, TableView.ContentOffset.Y);
}
[Export ("scrollViewDidScrollToTop:")]
public virtual void ScrolledToTop (UIScrollView scrollView)
{
// Keeps header fixed, this is called in the displayLink layer so it wont skip.
if(headerView!=null) headerView.Transform = CGAffineTransform.MakeTranslation(0, TableView.ContentOffset.Y);
}
Related
I am new to iPad developer,
I made one Registration form in my application, when i see my application in Portrait mode,
i am able to see whole form with no scrolling, but when i see same form in Landscape mode, i am not able to see part which is at bottom of page, for that a scrolling should be there to see bottom part.
:
In my .h file when i replace
#interface ReminderPage : UIViewController{
...
...
}
:UIViewController with :UIScrollView
and then when i add label in my .m file like this,
UILabel *Lastpaidlbl = [[[UILabel alloc] initWithFrame:CGRectMake(70 ,400, 130, 50)]autorelease];
Lastpaidlbl.backgroundColor = [UIColor greenColor];
Lastpaidlbl.font=[UIFont systemFontOfSize:20];
Lastpaidlbl.text = #"Lastpaid on :";
[self.view addSubview:Lastpaidlbl];
I am getting error on last line Property view not found on object of type classname.
i am unable to add label in my view.
Any help will be appreciated.
The question appears to be really asking how can all the components on the screen be placed inside a UIScrollView, rather than a UIView. Using Xcode 4.6.3, I found I could achieve this by simply:
In Interface Builder, select all the sub-views inside the main UIView.
Choose Xcode menu item "Editor | Embed In | Scroll View".
The end result was a new scroll view embedded in the existing main UIView, will all the former sub-views of the UIView now as sub-views of the UIScrollView, with the same positioning.
If you want to replace your UIViewController with a UIScrollView, you will have to go a bit of refactoring to your code. The error you get is just an example of that:
the syntax:
[self.view addSubview:Lastpaidlbl];
is correct if self is a UIViewController; since you changed it to be UIScrollView, you should now do:
[self addSubview:Lastpaidlbl];
You will have quite a few changes like this one to make to your code and will face some issues.
Another approach would be this:
instantiate a UIScrollView (not derive from it);
add your UIView (such as you have defined it) to the scroll view;
define the contentSize of the scroll view so to include the whole UIView you have.
The scroll view acts as a container for your existing view (you add your controls to the scroll view, then add the scroll view to self.view); this way, you could integrate it within your existing controller:
1. UIScrollView* scrollView = <alloc/init>
2. [self.view addSubview:scrollView]; (in your controller)
3. [scrollView addSubview:<label>]; (for all of your labels and fields).
4. scrollView.contentSize = xxx;
I think the latter approach will be much easier.
Please put all of your UIComponents to the UIScrollview and then it will start scrolling.
please look in to content size. please change it according to the orientation of device.
You're subclassing UIScrollView, so there is no self.view because already self is the view (of the scrollview). You dont need to subclass the scrollview, you can just embed your components in a ivar scrollview and set its contentSize (in your case, you have to enable the scrolling just when the device is in landscape mode). In interface builder you can embed the selected elements in one click, Editor-> Embed in-> scrollview.
First create scrollview
UIScrollView * scr=[[UIScrollView alloc] initWithFrame:CGRectMake(10, 70, 756, 1000)];
scr.backgroundColor=[UIColor clearColor];
[ self.view addSubview:scr];
second
change [self.view addSubview:Lastpaidlbl];
to
[scr addSubview:Lastpaidlbl];
third
set height depends on content
UIView *view = nil;
NSArray *subviews = [scr subviews];
CGFloat curXLoc = 0;
for (view in subviews)
{
CGRect frame = view.frame;
curXLoc += (frame.size.height);
}
// set the content size so it can be scrollable
[scr setContentSize:CGSizeMake(756, curXLoc)];
Finally
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
if (interfaceOrientation==UIInterfaceOrientationLandscapeLeft || interfaceOrientation==UIInterfaceOrientationLandscapeRight) {
self.scr.frame = CGRectMake(0, 0, 703,768);
} else {
self.scr.frame = CGRectMake(0, 0, 768, 1024);
}
return YES;
}
I'm about to add a UIScrollView to my iPhone project and before I implement this functionality I wanted to check if my approach is the right one or if I could be violating some best practice I'm not aware of.
The tutorials I've seen generally involve adding a UIScrollView to an existing UIView and they work from there. However, I was wondering if I could spare the UIView altogether and just add the UIScrollView as the only top-level object in my nib file.
My sample project uses Xcode's View-based Application template:
Project navigator http://img542.imageshack.us/img542/5364/projectnavigator.png
I deleted the UIView top-level object from the original MySampleViewController.xib file and replaced it by adding a UIScrollView object:
Nib placeholders http://img526.imageshack.us/img526/7709/placeholderobjects.png
Now my nib file only shows this object in the canvas:
Canvas http://img233.imageshack.us/img233/4063/scrollview.png
Then I created the link from the UIViewController's view outlet to the UIScrollView.
Now, if I wanted to programmatically manipulate the contents of the UIScrollView I can use this code:
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
// Solution B: With the following line we avoid creating an extra outlet linking to the UIScrollView top-level object in the nib file
UIScrollView *scrollView = (UIScrollView *)self.view;
for (int i = 0; i < colors.count; i++) {
CGRect frame;
//frame.origin.x = self.scroller.frame.size.width * i; // Solution A: scroller is an IBOutlet UIScrollView *scroller;
frame.origin.x = scrollView.frame.size.width * i; // Solution B
frame.origin.y = 0;
//frame.size = self.scroller.frame.size; // Solution A
frame.size = scrollView.frame.size; // Solution B
UIView *subView = [[UIView alloc] initWithFrame:frame];
subView.backgroundColor = [colors objectAtIndex:i];
//[self.scroller addSubview:subView]; // Solution A
[self.view addSubview:subView]; // Solution B
[subView release];
}
//self.scroller.contentSize = CGSizeMake(self.scroller.frame.size.width * colors.count, self.scroller.frame.size.height); // Solution A
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * colors.count, scrollView.frame.size.height); // Solution B
}
In order to implement Solution A the scroller outlet must be linked to the nib's UIScrollView as well, and the Connections Inspector looks like this:
Connections Inspector http://img228.imageshack.us/img228/8397/connectionsj.png
Solution A requires an outlet and this means having two connections to the UIScrollView: the UIViewController's own view outlet and MySampleViewController's scroller outlet. Is it legal and/or recommended to have two outlets pointing to the same view?
Solution B only involves UIViewController's view outlet linking to the view, and using this line:
UIScrollView *scrollView = (UIScrollView *)self.view;
My questions:
Do I incur in some sort of violation of Apple's design guidelines by using one of these two solutions?
Should I stick to the UIScrollView within a UIView solution?
Is there any other way to implement this?
Thanks!
P.S. Sorry for the syntax highlight, SO didn't recognize the use of the 'objective-c' tag
No I think you are fine either way.
I would, I don't think a UIView has any significant cost, plus what if you want to add a page control? and you don't have to cast the controller's view to a UIScrollView every time you need it.
Looks like you have it under control to me.
Solution A requires an outlet and this means having two connections to the UIScrollView: the UIViewController's own view outlet and MySampleViewController's scroller outlet. Is it legal and/or recommended to have two outlets pointing to the same view?
It standard to have IBOutlets to any view defined in your .nib that you want to access directly from your view controller.
If you don't want two outlets you could give the scroll view a tag then find it like so:
UIScrollView *myScrollView = (UIScrollView *)[self.view viewWithTag:1]
Then you only have the view as an outlet, but I would just add the extra outlet. Just make sure you set them to nil in your viewDidUnload.
Also you don't have to retain the scroll view (if you are even still using retain/release). Since the scroll view is inside your view controller's view it keeps a reference so you can have your scrollview's property by assign or week if your using ARC.
Hope that helps.
I'm using a UISegmentedControl as the headerview of a tableview. Now I want to add loading view (a view defined by myself) only covering the table cells but not my headerview. How do I achieve this?
You can add this view to the cell you want:
UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPathOfCell];
[cell addSubview:view];
The simplest way to add the loading view would be like this
// get the frame of your table header view
CGRect headerFrame = headerView.frame;
// construct a frame that is the screen minus the space for your header
CGRect loadingFrame = [[UIScreen mainScreen] applicationFrame];
loadingFrame.origin.y += headerFrame.size.height;
loadingFrame.size.height -= headerFrame.size.height;
// use that frame to create your loading view
MyLoadingView *loadingView = [[MyLoadingView alloc] initWithFrame:loadingFrame];
// add your view to the window *
[[headerView window] addSubview:loadingView];
* Adding the view to the window may not be the best thing for your design, but since I don't know any of the details of your view hierarchy, this is the way that will always work.
Caution: If you do not cover up the segmented control, and it is enabled, the user may click on it and change the state of the app when you aren't expecting it - like when you're trying to load something for them. Be sure that you can cancel this loading view if the user changes the state of the app.
I have a UITableView whose data have sections. I display an overlay view on top of tableView that dims it when searching:
- (UIView *)blackOverlay {
if (!blackOverlay) {
blackOverlay = [[UIView alloc] initWithFrame:[self overlayFrame]];
blackOverlay.alpha = 0.75;
blackOverlay.backgroundColor = UIColor.blackColor;
[tableView insertSubview:blackOverlay aboveSubview:self.parentViewController.view];
}
return blackOverlay;
}
This works perfectly as long as tableView does not contain sections. When tableView does contain sections and the tableView updates (such as when the view reappears after popping a view off of the navigation controller stack), the section headers are rendered above blackOverlay. This leaves tableView dimmed except for the section headers. I've tried calling [tableView bringSubviewToFront:self.blackOverlay] from within viewWillAppear:, but I get the same behavior.
My current work-around is returning nil for tableView section headers while the overlay is present, but this leaves whitespace gaps in the overlaid tableView where the section headers were previously.
How can I insure that tableView section headers are never drawn above blackOverlay? Or, is it possible to create a view in front of tableView from within a UITableViewController subclass that is not a subview of tableView?
First off, your function should be tweaked a bit. If you're returning an object that was alloc'd but not autorelease'd, then your method name should indicate that (i.e. newBlackOverlay). Second, your method is modifying a tableView object that was not given to it, so its interactions with other components is not obvious (see Law of Demeter).
The problem is that you're putting this black overlay as a child of the table view. You should be inserting it at the same level of the table view, i.e.:
UIView (set to the view controller's view)
|
+-UITableView
|
+-UIView (your new black overlay)
You can create it inside Interface Builder and set the backgroundColor/alpha properties as you see fit. Create a new UIView #property in your view controller and set it to your new UIView. Then you can change the overlay's alpha value and/or hide it completely in your callback functions for when the user starts/ends searching tasks.
I have a UITableView whose data have
sections. I display an overlay view on
top of tableView that dims it when
searching
FWIW, in case you don't know, you can build search screens fairly easily with the new UISearchDisplayController class Apple introduced in iPhone OS 3.x. Might save you re-inventing the wheel, here.
I solved this problem by creating a root view controller and making my table view a subview of this controller:
- (void)viewDidLoad {
[super viewDidLoad];
// Create the root view to hold the table view and an overlay
UIView *root = [[UIView alloc] initWithFrame:self.navigationController.view.frame];
root.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
root.autoresizesSubviews = YES;
self.view = root;
// Setup the table view
UITableView *newTableView = [[UITableView alloc] initWithFrame:self.navigationController.view.frame style:UITableViewStylePlain];
newTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.tableView = newTableView;
[newTableView release];
[root addSubview:self.tableView];
[root release];
}
I was then able to use a UISearchDisplayController with a search bar at the top of the tableView without issue.
Below shows the default position when you add a grouped table to a view? How do I push the entire grouped table down in the view?
(source: pessoal.org)
You can assign a transparent view with a fixed height to the tableHeaderView property of the tableView. This will push the table contents down by the height of the transparent view.
You can do this from your UITableViewController's viewDidLoad:
// force the table down 70 pixels
CGRect headerFrame = self.tableView.bounds;
headerFrame.size.height = 70;
UIView *header = [[UIView alloc] initWithFrame: headerFrame];
header.backgroundColor = [UIColor clearColor];
self.tableView.tableViewHeader = header;
[header release];
Look at the delagate to the UITableView.
You will find a property 'heightForHeaderInSection'.
For section 0 just make the header larger (default is 0) it will push the table down the view.
If you are moving the table down, you undoubtedly wish to use the space you gain to add UI elements.
At that point, consider building the page in IB. You can resize the table view to be where you like and put the UI elements above the table. You can use a UIViewController to manage the page and add the UITableViewDelegate/Datasource protocol methods so that you can wire the UITableView back to your view controller as a delegate... then you can also wire the other UI elements to the same view controller.
The simplest way to do it is probably just to modify the frame for the tableview. You'll need to get a reference to the tableview in your controller either through an IBOutlet or by finding the view in the view hierarchy OR you can change the frame in Interface Builder.
In code something like:
tableView.frame = CGRectMake(0.0, 200.0, 320.0, 280.0);
Would position the tableview down the screen and limit its height - the dimensions you use will be dependent on whether you had a tab bar on the view and things like that.
In interface build just select the tableview, then choose the Size inspector (the inspector tab with the ruler icon) and set the height and y offset to shift it down the view.