I was trying to implement a view like twitter's iOS app. The view controller contains a scroll view can scroll horizontally, in each page of the scrollview, there is a tableview. For simplicity I just created two UITableView, and add them inside two UIView containers, because besides tableView, I also have some view to show, so the tableView and all other views are added as subViews of the viewContainer for each page.
The view hierarchy is like this:
UIViewController
--view
--scrollView
--view1
--tableView1
--someOtherViews
--view2
--tableView2
--someOtherViews
In the viewDidLoad methods, I implemented something like this:
-(void)viewDidLoad
{
//Some other setup...
scrollView = [[UIScrollView alloc]initWithFrame(0,y0,self.view.frame.size.width,self.view.frame.size.height-offset)];
scrollView.pageEnabled = YES;
scrollView.contentSize = CGSizeMake(self.view.frame.size.width * 2, self.view.frame.size.height - offset);
[self.view addSubView:scrollView];
view1 = [[UIView alloc]initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height-offset)];
tableView1 = [[UITableView alloc]initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height-offset) style:UITableViewStyleGrouped];
tableView1.delegate = self;
tableView1.dataSource = self;
//other setup...
[view1 addSubView:tableView1];
[scrollView addSubView:view1];
view2 = [[UIView alloc]initWithFrame:CGRectMake(self.view.frame.size.width,0,self.view.frame.size.width,self.view.frame.size.height-offset)];
tableView2 = [[UITableView alloc]initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height-offset) style:UITableViewStyleGrouped];
tableView2.delegate = self;
tableView2.dataSource = self;
//other setup...
[view2 addSubView:tableView2];
[scrollView addSubView:view2];
}
For test purpose, I populate the same datasource for both tables. The problem is if I only add one tableView container (for instance view1, which includes tableView1) as the subView of the scrollView, the view shows perfect, one can page to second page, which is blank, and the view controller can be load and show. The same for the second one.
However, if I use the code above, which adds both view containers as the subView of the scrollView, the app would crash when load this view controller. However, if I add the second view container (view2 or view1), but in the view container, I am not adding tableView as its subView, but has other subViews, it works perfectly.
So I figured the problem probably comes from two tableViews. However, I have tried to debug this for a few hours, and still no luck. Anyone can help me?
Thanks!!
I think it is something with you UITableViewDelegate or DataSource methods.
Probably it is the reason you crash.
-Suggestion:
try to make your UITableViews as an iVar and in dataSource methods
specify the tableView you want
like:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
if(tableView == _tableView1)
return _table1DataSource.count;
else
return _table2DataSource.count;
}
try to do it for other methods.
Related
I'm using parse's PFQueryTableViewController, which is almost exactly the same as a UITableViewController except it handles some querying in the background.
My goal is to place a static toolbar at the bottom of the screen. I decided to do this by giving tableView a smaller frame, and creating and adding my toolbar subview below the tableView, as a subview to the same view that the tableView is a subview of.
Here's a photo. I am trying to add my toolbar to the little white space at the bottom of the screen. That whitespace does NOT scroll with the table view:
I have tried [self.view addSubview: toolbar], however, this just adds it to the tableView, and as a result, my toolbar scrolls with it. I can't seem to find any documentation on the view hierarchy for a UITableViewController. Anyone know where I should add my toolbar subview? I should also mention that all of this is sitting inside of a UINavigationController.
A PFQueryTableViewController (like all UITableViewControllers) has a table view as its view.
If you want to have other views within the view controller, either don't use a table view controller, or subclass UINavigationController.
Alternatively, you can set the view controller's toolbarItems property, and the navigation controller will take care of making and configuring a standard toolbar.
implement viewFAorHeaderInSection delegate method of UITableView:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 90)];
customView.backgroundColor = [UIColor blackColor];
return customView;
}
and heightForFooterInSection
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 80;
}
it should solove your problem.
I am trying to make a view controller which deals with the user login. Since I needed the view controller to be scrollable, contain a separate view (for the login), and contain a background, I decided to go with the route of making a tableviewcontroller, subclassing it, and than adding in the necessary views. I subclassed UITableViewController and added this code into the viewdidload()
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"TableViewControllerBlurred.png"]];
[tempImageView setFrame:self.tableView.frame];
self.tableView.backgroundView = tempImageView;
[tempImageView release];
This successfully added my background image to the controller and at this point, the view controller looked like: http://imgur.com/ST4H8uf as it was supposed to.
Moving on, I began working with static cells, dropped in a view into one of the cells and began to design the sign in screen. At this point, my storyboard looked like: http://imgur.com/n6GKeGq&ST4H8uf but the problem comes about when I run the project.
When I run the project, I keep getting the same background screen as seen in the first image without any of the new static cells or views. All and any help is much appreciated as to what may be the cause of this problem. Thank you.
CellForRowAtIndexPath Code:
*/
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<##"reuseIdentifier"#> forIndexPath:indexPath];
// Configure the cell...
return cell;
}
*/
If what you want is a UITableView with just static cells, then learn to use UIScrollView with a UIViewController.
#interface vc : UIViewController
#property (nonatomic, strong) UIScrollView *scrollView;
#end
#implementation vc
- (id)init // or whatever initializer you are using to make your view controller
{
self = [super init];
if (self) {
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,320,568)];
[_scrollView setContentSize:CGSizeMake(320,568)]; // equals one screen
[_scrollView setContentSize:CGSizeMake(320,568*2)]; // equals two screens, etc
// contentSize property determines how much you can scroll inside the UIScrollView view if that makes any sense to you.
[self.view addSubview:_scrollView]
// one way of adding a background
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"imageName"]];
[self.view addSubview:backgroundImageView];
[_scrollView addSubview:[self newStaticCellAtPosition:CGRectMake(0,0,320,45)]];
[_scrollView addSubview:[self newStaticCellAtPosition:CGRectMake(0,45,320,45)]];
// add subviews, you can even use UITableViewCell if you want.
// I'd use simple UIView's and draw separators and whatnot myself if I were you.
}
return self;
}
- (UIView *)newStaticCellAtPosition:(CGRect)position
{
UIView *staticCell = [[UIView alloc] initWithFrame:position];
[staticCell setBackgroundColor:[UIColor redColor]];
return staticCell;
}
#end
For other properties you should check out UIScrollView documentation. Remember UITableView inherits from UIScrollView so if it's easy to pick and choose what you want.
first check datasource and delegate of tableview has to be set.
You might be geeting a problem beacuse of that.
Never use a UITableViewController! In almost every case I have come across it is much much easier to use a UIViewController and add a table view. You simply cannot get at the backgroundView of a UITableViewController and have it scroll properly. I realize that you can only make a "static" table view with a UITableViewController but its simple enough to mimic the exact same behaviour with a regular table view and you don't have to deal with the headache of not being able to add views behind the table (like a background image).
I'm encountering this weird bug regarding UISearchDisplayController's table view, which occurs only in iOS 6. I just created my tableview in a nib file and then programmatically added a search bar above it and a search display controller to filter data in the table view:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.mpSearchBar = [[MPSearchBar alloc] initWithFrame:CGRectMake(0, 0, 250, 44)];
self.mpSearchBar.placeholder =#"Card Search";
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.mpSearchBar contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.resultTableView.delegate = self;
self.resultTableView.dataSource = self;
[self.resultTableView reloadData];
}
When I first enter some query in the search bar, the search display controller filters the data and the controller's result table view works fine. However when I tap the clear button in the search bar and type something else, the result table view which contains the new set of filtered data can no long scrollable. What's weird is, when I try to log the frame and contentSize of the table view, the content size height is larger than the frame height, as it's supposed to be:
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
tableView.scrollIndicatorInsets = UIEdgeInsetsZero;
tableView.contentInset = UIEdgeInsetsZero;
[tableView hideEmptySeparators];
if (IOS_EQUAL_OR_NEWER_THAN_7){
tableView.separatorInset = UIEdgeInsetsZero;
}
NSLog(#"Frame height %f, Content height %f", tableView.frameHeight, tableView.contentSize.height);
}
And this is what I get from the log:
Frame height 504.000000, Content height 1402.000000
This happens only when I test on iOS 6 devices and I have no clue how to debug this issue.
Please suggest and thanks.
Turns out this is a (not well) known issue of UISearchController's table view in iOS 6. My temporary solution is to get the contentSize from willShowSearchResultsTableView and programmatically set it to the table view in viewDidLayoutSubviews:
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if ([self.searchController isActive]){
// fix wrong content size due to search bar glitch in iOS 6
self.searchController.searchResultsTableView.contentSize = newContentSize;
}
}
Hope this helps anyone who encounters the same problem as mine.
I have a collection view populated with data like:
[self.graniteImages addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"Angel Cream", #"name",
#"angel-cream.jpg", #"image", nil]];
[self.graniteImages addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"Angola Black", #"name" ,
#"angola_black1.jpg", #"image" , nil]];
and then have a segue to a detail view which is static.
I now want to add paging to the detail view so that I can swipe through the images that I have contained in my collection view in the same way that the iPhone photo gallery works.
I'm guessing either a scrollview or a second collectionview would be needed however I'm not sure where to start with this so any pointers, sample code or any other help you guys could give would be massively appreciated.
Thanks
If you already have a collection view that does what you want just turn on paging. self.collectionView.pagingEnabled = YES You can also enable paging in IB by checking the paging box in the attributes inspector. Using a UICollectionView gives you the added benefit of reusable cells.
Edit
You could still use UICollectionView. Create an UICollectionViewCell subclass that contains your detail view. Then when you want to launch directly to a particular image you can use - (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated If you're loading a ton of images in this view the scrollview method will load all of your images at once rather than on demand like they would in a collectionview scenario. You can always work around that in a scrollview but all that work's been done for you in UICollectionView.
Edit2
I started this in a comment but it was getting big...
In your view controller subclass you will need to register either your class or a nib that you created to lay out that cell. I prefer the nib so I can lay everything out in Interface Builder. If you go the nib route you will create an empty xib and drag a UICollectionViewCell out of the object library in the bottom right. Then select that cell and make sure the Class is set to the custom subclass you've created.
Now in your view controller subclass you'll call – registerNib:forCellWithReuseIdentifier: in the viewDidLoad method like this:
[self.collectionView registerNib:[UINib nibWithNibName:#"WhateverYouNamedYourNib" bundle:nil] forCellWithReuseIdentifier:#"cell"];
Your view controller will conform to the UICollectionViewDataSource protocol and you will implement this method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CustomCellClass *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath
//Setup the cell with image and whatever else
return cell;
}
You should simply use a UIScrollView with paging enabled. The following code should do the trick:
NSInteger numberOfImages = [self.graniteImages count];
CGRect bounds = self.scrollView.bounds;
self.scrollView.contentSize = CGSizeMake(bounds.size.width * numberOfImages, bounds.size.height);
scrollView.pagingEnabled = YES;
CGFloat x = 0;
for (NSMutableDictionary *dict in images) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[dict valueForKey:#"image"]]];
imageView.frame = CGRectMake(x, 0, bounds.size.width, bounds.size.height);
[scrollView addSubview:imageView];
x += self.view.bounds.size.width;
}
EDIT: This code would go in your detail view controller's ViewDidLoad method.
Your detail view controller should also have a property index of type NSUInteger and a graniteImages property of type NSMutableArray* that you can set in your collection view controller's prepareForSegue method just like:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [segue.identifier isEqualToString:#"yourSegue"]){
((DetailViewController*)segue.destinationViewController).graniteImages = self.graniteImages;
((DetailViewController*)segue.destinationViewController).index = self.tappedImageIndex;
}
}
and in your ViewDidLoad method you add:
[scrollView scrollRectToVisible:CGRectMake(bounds.size.width * self.index, 0, bounds.size.width, bounds.size.height) animated:NO];
I've made header using this post: Table Header Views in StoryBoards
But i am unable to make header stick (fix) to the top of the screen while scrolling.
How can that be achieved?
P.S. Table style is plain, and when i tired to overload viewForHeaderInSection and returned outlet for header view, it just got worse.
Thanks in advance!
Here's the code which I believe makes the header view stick to the table top (that is not it's default behavior):
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect rect = self.tableHeaderView.frame;
rect.origin.y = MIN(0, self.tableView.contentOffset.y);
self.tableHeaderView.frame = rect;
}
An alternative is to have header view for the first section. You can't use any subview at viewForHeaderInSection, you have to return there the view which is not yet at views hierarchy. The advantage of the method is that the section header view is designed to be at the table top, the drawback is that you might want to have headers for sections in the feature, it will break the solution.
I think it's better for you to use a UIViewController, instead of a UITableViewController in the storyboard, to achieve this. Just put a header in the top of the view, in the storyboard, and put a UITableView under the header.
I was able to do it (at least in iOS 6) like this, don't know why this thing works:)
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if(self.headerManualView == nil) {
//allocate the view if it doesn't exist yet
headerManualView = [[UIView alloc] init];
//create the button
UITextField *txtField = [[UITextField alloc] initWithFrame:CGRectMake(10, 3, 250, 44)];
//the button should be as big as a table view cell
txtField.borderStyle = UITextBorderStyleRoundedRect;
//set action of the button
//[txtField addTarget:self action:#selector(removeAction:) forControlEvents:UIControlEventTouchUpInside];
//add the button to the view
[headerManualView addSubview:txtField];
}
//return the view for the footer
return headerManualView;
}