I want to achieve the following in xcode.
I have a view controller. Within this UIViewController I have a UITabBar. Below them is a UIView. What is the best way to add a UITableView to the UIView? Then being able to click on a UITableViewCell and opening up another UIViewController to show more information about the UITableViewCell?
Here is the current setup of my storyboard:
Could you offer me a solution to this problem? Thanks
You need a solution to your problem but I'm not sure what your problem is.
In storyboard, drag a UIView in your UIViewController. Then drag a UITableView (not controller) in that UIVIew.
You'll be able to see the view hierarchy on the left.
Then link your tableview datasource and delegate to the parent controller.
in your .h file, add the UITableViewDataSource and UITableViewDelegate protocols, also link your tableview as an Outlet.
In your .m files, add the tableview delegate methods (numberOfRowsInSection: and cellForRowAtIndexPath:)
I also suggest adding didSelect: among the tableview methods because, well, you'll need it.
and you're good to go. :)
It's actually the EXACT same thing as creating a tableview, except that your tableview is a subview of a UIView, which doesn't matter at all if it comes to code. The only thing you'll have to be "careful" of is to build your view properly in storyboard, and make sure the constraints don't make your tableview unusable for some reason.
Check one of my previous answers where I explain how to make a tableview and make it load another controller while passing data, which is something you might need if everything I wrote here still confuses you.
FOLLOW UP:
From your comments I understand that this subview of your UIView can be different things ; a tableview, a webview, and so on.
There are many ways to do that, and from my little knowledge I see two that can be easy and reliable (from my <1year experience as a developer...).
Get all the possibilities ready in your parent viewcontroller, if you only have 2 possibilities for example, that's "okay".
The best way is to prepare a container view (it's literally called container view) which would load different OTHER view controllers according to your needs.
I think option 2 is more reliable, because it will split the code into different classes, will allow you to modify each of them independently, and you can easily remove/add new views.
To my knowledge, you'll have some kind of switch statement in your parent controller that will load the desired UIViewController (or tableview or anything). Whatever you do there will just be as usual, but constricted to a smaller view inside another VC.
You can create that container view in storyboard and pre-link every other VC with segues (ToTable, ToWeb, ToCollection) are good examples for segue names that would link that container view to your 3 UIViewControllers.
Note that you can pass data if need be, but you would have all the separate controllers handle their own stuff even though it is visible inside your current vc.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [catagorry count]; //count number of row from counting array hear cataGorry is An Array
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the provided setImageWithURL: method to load the web image
// Ensure you use a placeholder image otherwise cells will be initialized with no image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://example.com/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
cell.textLabel.text = #"My Text";
return cell;
}
these are the basic method to create a basic table view. to load an view controller corresponing to the cell click u can use did select row method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
/* //Pushing next view
cntrSecondViewController *cntrinnerService = [[cntrSecondViewController alloc] initWithNibName:#"cntrSecondViewController" bundle:nil];
[self.navigationController pushViewController:cntrinnerService animated:YES];
*/
[self performSegueWithIdentifier:#"identifier" sender:self];
}
Related
I would like to subclass a UICollectionView (not a UICollectionViewController), and I would like to know how I can set it up so that when the user highlights (or selects) a cell, the collection view can be notified, so I can perform a little animation on the cell. You may ask why I can't do that in a view controller. I chose to subclass UICollectionView so that it could be reusable. I am relatively new to iOS programming, and I would welcome any suggestions or ideas.
You can use a block ^{}
Create a class with a .xib file. The .xib file will be used for each cell.
In your .xib file, add a clear UIButton, so that is on top of all your subviews. So the user can click on it.
In your .h file add
#property (copy, nonatomic) void (^actionBlock)(void);
In your .m file add and link it to your UIButton in the .xib file
- (IBAction)showAnimation:(id)sender
{
if (self.actionBlock) {
self.actionBlock();
}
}
Now in UICollectionViewController, cellForItemAtIndexPath, call the block
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCellClass *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:#"cell"
forIndexPath:indexPath];
cell.actionBlock = ^{
//Here you have access to indexPath.section and indexPath.row
NSLog(#"Going to animate the cell %# x %#", indexPath.section, indexPath.row);
//do any other code for this specific cell
};
return cell;
}
Using action blocks, is like opening a portal into each cell, happy coding
UICollectionView is the view and UICollectionViewController is the viewController.
The UICollectionView you are subclassing is use for updating user interface with viewController's core logic to be triggered while highlighting (or selecting) the cell.
So you should set up the selected logic in your viewController.
If you understood Delegate Pattern, the normal way to update your UICollectionView's cell while selected is using a delegate. When something triggered, call viewcontroller to do that for you.
Check out these links about
Cocoa MVC Design Pattern and Designing Your Data Source and Delegate for CollectionView.
I am having an interesting problem creating the custom tableview I need...
I found this question, but it does not really address my issue...
I am trying to put a subclassed UIView inside a subclassed UITableViewCell. The custom view holds a UIButton and a couple labels. Simplified, it's like this:
Both the custom view and custom tableviewcell have xibs.
MyCustomView.xib's class is set to MyCustomView and I have properties for the labels and the button as well as an IBAction for the button.
MyCustomTableView.xib has a property for MyCustomView and is importing MyCustomView.h.
In MyCustomView.xib, I have this init:
-(id)initWithNibName:(NSString *)nibName nibBundle:(NSBundle *)nibBundle myLabelText:(NSString *)labelText {
//The custom view in the tableviewcell is 69 by 64...
if ((self = [super initWithFrame:CGRectMake(0, 0, 69, 64)])) {
[self setmyLabelText:labelText];
}
return self;
}
And in my TableViewController...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomTableViewCell *cell = (MyCustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"theCell" forIndexPath:indexPath];
// Configure the cell...
cell.customView = [[MyCustomView alloc] initWithNibName:#"MyCustomView" nibBundle:nil fileContentID:#"Some Text..."];
return cell;
}
When I run the app, the custom tableview cell's contents are fine, but the content of the custom view inside the custom tableview cell is blank.
It seems that MyCustomView's initializer(-initWithNibName:nibBundle:myLabelText:) don't load any xib.
This post will help you.
How to load a xib file in a UIView
...and MyCustomView should be created once inside MyCustomTableViewCell, as #rdelmar says.
You need to do most of the formatting work in MyCustomTableViewCell - I would not use a XIB and code the views directly because that class is called many times. Apple has number of sample codes regarding TableViewCells - One of them I believe is called Elements that use fancy tableview cells for the Elements of the Periodic Table. Most of my apps use custom cells with icon images and I started with that sample code many years back (since IOS 4).
Your CellForRowatIndexPath should just be passing the image and the label text to your tableviewCell Class instance. If you have question just ask - but I am sure that sample code from apple is sufficient to get you started.
I want to create a prototype cell which can be used in different table view via the storyboard.. What is the right way to do this? Any pointers appreciated.
I don't think you can create a prototype cell and share it between tables in a storyboard, but you can create a prototype cell in a nib and then load that in the ViewDidLoad method and then use that in your table view. It is really quite simple, here is how...
A. add the nib file:
1. Select New File...
2. Select IOS -> User Interface
3. Select "Empty" -> this will add a new file .xib file to your project
4. Drag a UITableViewCell from the object browser into your xib file and customize to your liking
5. Use the Utilities pane to change properties -> editing a nib is very
similar to editing a storyboard.
6. Make sure you name your cell - I chose the name cellFromNib, but you will probably want something else.
B. Load the UITableViewCell in each table's viewDidLoad method:
- (void)viewDidLoad
{
// load the cell in the nib - the nib can only contain this one UITableViewCell
[self.tableView
registerNib:[UINib nibWithNibName:[self #"nibFileNameWithoutExtension"]
bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:[self #"cellFromNib"]];
}
C. De-queue the nib's tableViewCell...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellFromNib" forIndexPath:indexPath];
// customize your cell here...
}
D. Add a "dummy" prototype cell to your TableView in your storyboard.
Make a segue from this "dummy" cell to the view you want displayed when the cell is selected - make sure to name the segue - I'll call it #"theSegue" for this example. You will reference this segue in your code.
E. Finally, add code to segue from that cell...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// this is basically what the storyboard does under the hood...
// make sure you have a "dummy" prototype cell with this segue name for each
// tableview that uses this cell
[self performSegueWithIdentifier:#"theSegue" sender:self];
}
If you want to specialize your cell code, create a class that subclasses UITableViewCell
I think that is everything you need.
I would say do not be afraid of doing something like this because, if you are serious about IOS programming, you will learn something new. It really does make for much better reusable code.
I have added a UITableView inside a UIViewController in IB, I have set the TableView content to "Static Cells" since that's what I want, and everything seems fine when I haven't added any content to the UITableView. But if I for example change the first UITableViewCell's background color to black it doesn't display black when running the app. I have added UITableViewControllerDelegate and UITableViewDataSource and set the tableView.delage = self;. But still no changes I make to the tableView displays when I run the app.
What can the problem be?
NOTE: I have also tried to add tableView.dataSource = self;, but that just make the app crash.
Yes, you can have static table view content in UIViewController.
All you need to do is:
-Create the table's static cells in interface builder and design them the way you like.
-Make the UIViewController implement table view's data source and delegate:
#interface MyViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
-Connect the table view's delegate and dataSource to the view controller in interface builder
-Implement -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section to return the number of your cells. (e.g. return 10, yes simple as that)
-Connect your cells to your code as IBOutlets in Interface Builder. IMPORTANT: Make sure they are strong, weak won't work. e.g. #property (strong, nonatomic) IBOutlet UITableViewCell *myFirstCell;
-Implement -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to return the correct cell at index path. e.g:
int num = indexPath.row;
UITableViewCell *cell;
switch (num) {
case 0:
cell = self.myFirstCell;
break;
case 1:
cell = self.mySecondCell;
break;
}
return cell;
If you apply all these steps, you should have working static cells that works for tables with not many cells. Perfect for tables that you have a few (probably no more than 10-20 would be enough) content. I've ran the same issue a few days ago and I confirm that it works. More info check here: Best approach to add Static-TableView-Cells to a UIViewcontroller?
You will want to use a UITableViewController, not a UIViewController with a UITableView added to it, because you're only supposed to use static cells with a UITableViewController. There are probably ways to hack around it so you can get the static cells to work, but it's much simpler to just use a UITableViewController, and you'll have fewer issues to deal with, especially if you ever change the content of the table.
Seems you have problem with the background issue for UITableViewCell. So don't use background for checking if content is drawing or not.
You can use debugger for this for example or NSLog.
NOTE: the cell has content view that can be modified. I don't remember but seems the cell has not got background property that can be adjusted with a color.
If you tried this line below e.g. - it will no work and color will be white as default color.
[cell setBackgroundColor:[UIColor blackColor]];
Try to add something to the cell for example picture and then you can see the result as I think.
Use this code:
[cell.contentView setBackgroundColor:[UIColor blackColor]]; in this delegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
it will help you as I think.
Have you implementede the protocol? ...
another thing is that when implementing the protocol i had an issue when no cell was displayed..
try with this implementation for the given method.
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier=#"Cell";
CobranzaCell *cell = [[CobranzaCell alloc]init];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil) {
cell = [[CobranzaCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Configure the cell...
return cell;
}
You cannot use the static cells in simple UIViewController subclass. Instead, you should use the instance of UITableViewController. The hack is in your storyboard drag the instance of UIViewController to your storyboard canvas. Then, drag the Container View from objects library and drop it to your UIViewController's view. By default it will create the embed segue with related UIViewController instance. What you want to do - delete this view controller, drag and drop instance of UITableViewController from objects library, then right click and drag from your Container View to just dropped UITableViewController. Chose embed. Now your table view controller gets the size of container view and you can use static cells in it! Hope it will help!
I have a view controller (EmbeddedMenuView) that uses a custom view (HorizontalMenuView). The Embedded menu view uses multible HorizontalMenuViews. The HorizontalMenuView contains a UITableView. Each cell in the table view uses quite a bit of memory (high quality images.).
Now, I need to execute a task every time a section of the table view cells in the HorizontalMenuView is touched. I did this by creating a protocol in the table view cell and assigning the HorizontalMenuView its delegate. Then I created a protocol in the HorizontalMenuView and assigned the EmbeddedMenuView its delegate. So I pass the touch event up to the EmbeddedMenuView.
The problem is, when I assign the cell's delegate, the HorizontalMenuView does not get deallocated. Since this view refreshes itself every time the view appears, the memory footprint gets out of control fast.
If I comment out the part where the cell is assigned a delegate, everything works fine.
My question is: How can I properly release a UITableViewCell's delegate?
This is the code snippet from the HorizontalMenuView:
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Custom Logic
HorizontalMenuItemTableViewCell *cell = (HorizontalMenuItemTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[NSClassFromString([[AMPUIManager sharedManager] classNameForName:cellIdentifier]) alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
cell.shouldAlwaysTransform = shouldAlwaysTransform;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.colorsDict = colorsDict;
if ([cell isKindOfClass:[ATCustomTableViewCell class]]) {
((ATCustomTableViewCell *)cell).delegate = self; //Commenting this out solves my problem.
}
}
//More Custom Logic
return cell;
}
PS I am using manual reference counting. ARC is not an option for this project.
It sounds like you may have a circular reference. You almost always want to use 'assign' convention with delegates.
See: Why are Objective-C delegates usually given the property assign instead of retain?