My goal is to have a UISearchBar fixed in a view right above a UITableView. When I set this up in IB and then build, the table view expands to fill the whole window and the search bar is not visible. If I make the UISearchBar a subview of the UITableView, the search bar displays as expected, but this is not what I want. What I'm after is that after the user selects a row, I want to display a detail view with the search bar still remaining on the screen. So I figured it needed to be a separate subview, not part of the table. For some reason though, I can't can the search bar to display when it's simply a subview outside of the table.
You have to do this programatically. Here's what I ended up doing.
First add the following to the .h file of your ViewController.
#interface YourViewController : UITableViewController <UISearchBarDelegate>
{
UISearchBar *mySearchBar;
}
#property (nonatomic, retain) UISearchBar *mySearchBar;
#end
Then put this code in the viewDidLoad method of my RootViewController.
self.mySearchBar = [[[UISearchBar alloc]
initWithFrame:CGRectMake(0.0, 64.0, self.view.bounds.size.width,
44.0)] autorelease];
self.mySearchBar.delegate = self;
self.mySearchBar.showsCancelButton = YES;
self.mySearchBar.hidden = YES;
self.mySearchBar.tintColor = [UIColor lightGrayColor];
[self.navigationController.view addSubview: self.mySearchBar];
You may also need to add something like this to prevent the searchBar from being on top of your tableView.
self.tableView.frame = CGRectMake(0.0, 44.0, 320, 324);
In my case, the searchBar remained in the view when I drilled down to a detail view. I had to call:
self.mySearchBar.hidden = YES;`
In my didSelectRowAtIndexPath to get rid of it when I click on a cell.
It doesn't work with UITableViewController. Here's what will give you desired behaviour:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
return search; //in .h, IBOutlet UISearchBar* search;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 44;
}
Related
This is more of cosmetic issue.
I have added a searchbar via the storyboard and I want to hide the following with the storyboard.
I was able to do this previously using codes that was before storyboard came into the picture.
Can anyone point me in the right direction if this is achievable using storyboard?
Cheers,
Lance
On your storyboard, select your search bar and open the object inspector on the right. In their you will find a property called "hidden". check the box and the object will be hidden when the storyboard is initialized.
If you ctrl-drag from the search bar and create a property in your view controller, you can then control the hidden flag in code. So you can make it re-appear when you need it, something like:
self.searchbar.hidden = NO;
Edited 1/2/2013 -
Here is a different approach.
Checklist:
a)Add a search bar to your tableview's header view in your storyboard. Link that search bar to a property called searchBar. When you link it, xcode will give it a weak reference, change the weak reference to strong. ex:
#property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
b)Add a BOOL property called showSearch to control showing and hiding the search bar.
#property (nonatomic) BOOL showSearch;
c)Add the following methods to your controller code
- (void)setShowSearch:(BOOL)showSearch {
_showSearch = showSearch;
if (! _showSearch) {
self.tableView.tableHeaderView = nil;
}
[self.tableView reloadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection: (NSInteger)section
{
if (self.showSearch && self.tableView.tableHeaderView == nil) {
return self.searchBar.frame.size.height;
}
return 0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (self.showSearch && self.tableView.tableHeaderView == nil) {
return self.searchBar;
}
return nil;
}
by default this will start with the search bar showing. If you want to start with it hidden, just add the following to your viewDidLoad method:
self.showSearch = NO;
best of luck and happy new year!
My storyboard contiains a Navigation Controller, a Table View Controller and a Detail View Controller. How do I get the Detail View Controller to show text relevant to the "cell" selected on the TableView?
I currently have my code set up so it will show an Image if a cell is selected. Like if "Cell 1" was selected it would show "Image 1" if "Cell 2" selected then it would show "Image 2" etc.
- (void)viewDidLoad
{
[super viewDidLoad];
//Create a couple UIImage objects
UIImage *firstImage = [UIImage imageNamed:#"first.png"];
UIImage *secondImage = [UIImage imageNamed:#"second.png"];
UIImage *thirdImage = [UIImage imageNamed:#"third.png"];
//Title of the view
self.title = charName;
//UIImageview based on characterNumber
switch (characterNumber) {
case 0:
CharacterImage.image = firstImage;
break;
case 1:
CharacterImage.image = secondImage;
break;
case 2:
CharacterImage.image = thirdImage;
break;
default:
break;
}
}
How do I do this but for text instead of images? So that when "Cell 1" is selected from the Table View Controller it would lead to the DetailViewController with scrollable text that would be different from the text that would show if the other cells were selected. Would I be using a "UITextView" and upload different .txt files? Thanks
So that when "Cell 1" is selected from the Table View Controller it would lead to the DetailViewController with scrollable text.
You need to create a Segue between the ViewControllers (ctrl+drag from one to another). Then add an identifier:
Then you need to call that from you didSelectRowAtIndexPath method and send the indexPath as number with it:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"DetailSegue" sender:[NSNumber numberWithInt:indexPath.row]];
}
Then you can get the number and add it to your new viewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(NSNumber*)indexNumber
{
if([[segue identifier] isEqualToString:#"DetailSegue"]){
NSInteger index = [indexNumber integerValue];
DetailViewController *detailView = [segue destinationViewController];
detailView.textNumber = index;
}
}
Of course you need to add a NSInteger textNumber to your DetailViewController. Then just check what NSInteger is selected and show different text.
In your storyboard add a UIViewcontroller and connect it to your table view controller with command+drag, click to arrow and enter a segue name and choose push.
in your tableview controller.m
//#pragma mark - Table Did Select
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"segueNameGoesHere" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"segueNameGoesHere"])
{
DetailViewController *detailViewController = [segue destinationViewController];
//This will display on the Document Viewer
detailViewController.fileText=#"What Ever your Text is"; // you can also select that text source from an nsmutablearray , a file or cloud solution but in that case you need to write a method that returns a string to you
}
}
in your detailview controller .h
#interface DetailviewViewController: UIViewController {
UITextView *exampleTxt;
}
#property (nonatomic, strong)NSString *fileText;
in your detailview controller.m
#synthesize fileText=_fileText
// you can create your textview in IB or programatically like below after that all you need to this set your text
- (void)viewDidLoad
{
[super viewDidLoad ];
exampleTxt = [[UITextView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[exampleTxt setText:_fileText]; // look at here
//[exampleTxt setColor:[UIColor redColor]]; //yes, it's deprecated, but works
[self.view addSubview: exampleTxt];
}
If you dont like to add ui text view programatically, you can add it in IB. So to add TextView in IB follow this steps;
Go to your detail view controller on storyboard drag and drop a TextView in to your detailViewController;
detailviewController.h
#interface DetailviewViewController: : UIViewController
{
UITextView *textView;
}
#property(nonatomic,strong)IBOutlet UITextView *textView;
#property (nonatomic, strong)NSString *fileText;
in your deatilviewcontroller.m
#synthesize textView=_textView;
#synthesize fileText=_fileText;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//[_textView setText:#"Your text"];
[_textView setText:_fileText];
}
The purpose of this app is to retrieve the data selected on UITableCell and pass that on to a new view controller. All is well until the user selects the cell. The next view controller is loaded but the screen is black.
On that screen i have a UIImageView and UILabel. I have a UINavigationController set up in the storyboard. I am trying to get the image and text selected on the first screen to the respective objects on the next screen. I have retrieved the data from a database and have loaded it to the first screen.
Here is my code on my storedetail.h which is a subclass to a UIViewController,
#property (nonatomic, copy) UIImage *storeImage;
#property (nonatomic, copy) UILabel *storeCode;
Here is my code where i am calling the nextviewcontroller which is ShowStores.m which is a subclass of a UITableView,
header code ,
#import "ShowStores.h"
#import "StoreDetail.h"
code where i load the next view when the user selects the cell,
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
StoreDetail *storedetail = [[StoreDetail alloc] init];
storedetail.storeImage = cell.imageView.image;
storedetail.storeCode = cell.textLabel;
storedetail.storeCode.text = cell.textLabel.text;
[self.navigationController pushViewController:storedetail animated:YES];
}
I have debugged it and the cell.textLabel.text and cell.imageView.image are not nil or null.
The second view loads but is black. I have set up a back button on the second view which takes the user back to the first view and that works fine.
UIImage and UILabel don't conform to NSCopying protocol, that's most probably the reason. And so declaring #property (nonatomic, copy) doesn't do any effect as your intention.
My suggestion is setting retain for them, and at the point where you want to make copies, just initialize and assign the objects to them.
do you have a nib for your second view controller with the storeCode uiLabel in?
or are you creating the storeCode UILabel programmatically in viewDidLoad?
I would remove this line:
storedetail.storeCode = cell.textLabel;
in this line:
storedetail.storeImage = cell.imageView.image;
storeImage is a UIImage when I think you want it to be a UIImageView. (I would remove that line too and create a storeImageView the same way as you create the storeCode uiLabel - either have it in your nib or create it programmatically in viewDidLoad.
EDIT:
create the objects in viewDidLoad as follows:
storeCode = [[UILabel alloc] initWithFrame:CGRectMake(10, 20, 120, 16)];
[self addSubview:storeCode];
For the image I would set the name of the image (filename or path) to an NSString property on your second view controller and then in viewWillAppear use the string to create the correct UIImage and then assign that UIImage to your UIImageView.
I have a new controller defined as follows:
#interface view1: UITableViewController
I've created (in viewDidLoad) an image view (logo image) and added this image view as subview for view1, but the problem is that table view cells still appear behind this image view, how can completely separate the image view from the table view ?
thanks in advance.
To have a logo type view you either need to set a custom headerview for the tableview via
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
and
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
the other method would be overriding -loadView and creating your own view that has two subviews, your imageview and a tableview.
In the first method, once your scroll some the logo will eventually disappear. The second method makes the logo static.
Try adding it in:
- (void)viewDidAppear:(BOOL)animated
This method is only called once you have called viewDidLoad so if you want something over everything else you might call this one or add the subview to:
[[[UIApplication sharedApplication] keyWindow] addSubview:yourView];
Hopefully it helps you.
2 options:
1.create a UIViewController to hold your UITableViewController controller view and your imageView, then position their frame so they wont overlap
2.add the imageView as a TableView Section Header
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIImageView* imageView = [[UIImageView alloc] initWithImage:
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image" ofType:#"png"]]];
return imageView;
}
and make sure you have at least 1 section of course in:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
What is seems like you want is for your logo to be at the top, above your table view? If so then you can, in -viewDidLoad, set the tableView's tableHeaderView to the view you want, e.g.:
tableView.tableHeaderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image"]]; // assuming ARC, else autorelease or put in variable first...
If you want it to float on top when scrolling then DanZimm's use of -tableView:viewForHeaderInSection: is what you want.
I'm loading a UIViewController into one of my Nav controller's hierarchies, which will contain some text and some images. At the bottom, I will want to create a expandable and collapsable tableview.
First off, is this idea possible? If it is, how do I add it and where do I place the data source and delegate methods?
Can I just make a separate subclass of the TableViewController and then add it to my ViewController as a subview?
Yes, you can create a UITableView whose delegate, datasource, and parent view are not necessarily a UITableViewController. Since the UITableView is a UIView, you can add it as a subview of any other UIView. Any NSObject can be the delegate or datasource, as long as you implement the required protocol methods.
#interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
In fact, in my experience, not many people even use UITableViewControllers. When was the last time you wanted your table view to take up the entire usable space? In general, I create a plain old UIViewController and add a UITableView as a subview of its view, in addition to other subviews.
/************************************************/
/************* MyCustomController.m *************/
/************************************************/
#interface MyCustomController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UITableView *tableView;
#end
#implementation MyCustomController
- (id)initWithNibName:(NSString*)nibName bundle:(NSString*)bundleName
{
self = [super initWitNibName:nibName bundle:bundleName];
if (self)
{
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.datasource = self;
tableView.delegate = self;
[self.view addSubview:self.tableView];
}
return self;
}
#pragma mark - UITableViewDataSource Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// return number of rows
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return cell
}
#pragma mark - UITableViewDelegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// handle table view selection
}
#end
It's pretty easy, in something like your viewDidLoad method:
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:tableView];
Just remember that a UITableViewController is a subclass of UIViewController only with the tableview set as the controller's view.
So yes definitely possible and used quite frequently when you want to have a tableview but also other custom UI elements which prevent you from using the UITableViewController.
I'd normally choose to add it to my view controller's view in either its initialisation method or viewDidLoad method. This will vary based on whether you're creating your views from a NIB or entirely programatically.
In case of NIBs:
- (id)initWithNibName:(NSString*)nibName bundle:(NSBundle*)bundleName
{
if ((self = [super initWitNibName:nibName bundle:bundleName]))
{
self.theTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewWhateverStyleYouWantHere];
theTableView.dataSource = self, theTableView.delegate = self;
[self.view addSubview:theTableView];
[theTableView release];
}
}
And then you can set the frame of your tableview in your viewDidLoad method.
I'd personally prefer to do the whole thing in interface builder as you'd achieve the same result with way less code to maintain.
If you're like me and already had created a UITableViewController and then realizing that you did so much work on it that re-writing it would be a pain, you can just do the following to add the UITableViewController to the UIViewController as a subview.
UITableViewController* tableViewController = [[UITableViewController alloc] init];
[self.view addSubview:tableViewController.tableView];
All the other answers above works great. I figure I'd add to this for those that have a heavily invested implementation of a UITableViewController and feel like refactoring would be a pain.