In my app I am trying to navigate to a new View from a TableViewCell, But i dont know how. Could you help guys? I am using Xcode 4.6. and .xib, no storyboard. I am very new to coding so please explain it as simple as possible! Here is what i have tried, please correct me:
- (void)viewDidLoad
{
tableData = [[NSArray alloc] initWithObjects:#"aaoversikt1", #"Paul", #"George", #"Ringo", nil];
[super viewDidLoad];
UILabel *nav_title1 = [[UILabel alloc] initWithFrame:CGRectMake(60, 10, 220, 25)];
nav_title1.font = [UIFont fontWithName:#"Arial-BoldMT" size:18];
nav_title1.textColor = [UIColor whiteColor];
nav_title1.adjustsFontSizeToFitWidth = NO;
nav_title1.textAlignment = NSTextAlignmentCenter;
nav_title1.text = #"Ă…lesund";
nav_title1.backgroundColor = [UIColor clearColor];
self.navigationItem.titleView = nav_title1;
}
#pragma mark - TableView Data Source methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section;
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = nil;
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - TableView Delegate methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AAOversiktViewController *aaoversikt1 = [[AAOversiktViewController alloc] initWithNibName:#"AAOversiktViewController" bundle:nil];
[self.navigationController pushViewController:aaoversikt1 animated:YES];
}
Thank You!
From first glance I would say that the problem lies within your [self.navigationController pushViewController] method. Have you initiated a navigation controller in your app either in the app delegate or root view controller?
If not i would recommend:
[self presentViewController:aaoversik1 animated:YES completion:NULL];
If you are wanting to push through the navigation stack so that you have a back button then I would look at implementing a UINaviationController.
Otherwise you can create a custom back button and use the same method in this post to present the root view controller (not totally recomended as using UINavigationController is much cleaner).
Let me know if this has been of any help, T
Related
I have been looking until 6 o'clock this morning, but I can't figure out why the didSelectRowAtIndexPath method is not being called. I am getting quite desparate on this one.
The tableview is shown properly, but I cannot succeed to enable the selection of a cell.
In the header file , I added:
#interface AlertsTable : UIViewController<UITableViewDelegate, UITableViewDataSource, CMPopTipViewDelegate>{
UITableView *TableView;
}
#property (nonatomic, retain) UITableView *TableView;
In the implementation file:
#synthesize TableView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
//Set the title
//Format Alerts table
//self.view.backgroundColor = [UIColor redColor];
CGFloat sideMargin = 10;
CGFloat topBottomMargin = 44;
CGFloat originX = sideMargin;
// compute width based on view size
CGFloat sizeWidth = (self.view.bounds.size.width - (sideMargin * 2));
CGFloat originY = topBottomMargin;
// compute height based on view size
CGFloat sizeHeight = (self.view.bounds.size.height - (topBottomMargin * 2));
//self.view.frame = CGRectMake(originX, originY, sizeWidth, sizeHeight);
self.TableView = [[UITableView alloc] initWithFrame:CGRectMake(originX, originY, sizeWidth, sizeHeight) style:UITableViewStylePlain];
//Initialize the array.
AlertsItems = [[NSMutableArray alloc] initWithObjects: #"Alert 1", #"Alert 2", #"Alert 3" , #"Alert 4", #"Alert 5", #"Alert 6", nil];
[self.TableView setDelegate:self];
[self.TableView setDataSource:self];
[self.view addSubview:TableView];
TableView.userInteractionEnabled = YES;
TableView.allowsSelection = YES;
TableView.allowsSelectionDuringEditing = YES;
NSLog(#"delegate:%# dataSource:%#", self.TableView.delegate, self.TableView.dataSource);
}
The delegate and datasource are both not nil on the check.
Note that the "Alertstable" inherits from a UIViewController, not a UITableViewController.
This is necessary due to the implementation I chose: the tableview is shown on a popupwindow shown on the screen (using another class that I took from the internet).
This is the didSelectRowAtIndexPath method:
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *alertString = [NSString stringWithFormat:#"Clicked on row #%d", [indexPath row]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertString message:#"" delegate:self cancelButtonTitle:#"Done" otherButtonTitles:nil];
[alert show];
}
The methods:
[super touchesBegan:...];
[super touchesEnded:...];
[super touchesMoved:...];
are not implemented.
I added the AlertTable from another ViewController
AlertsTable *AlertTable = [[AlertsTable alloc] WithButton:sender withArray:self.PopTipViews];
[self.view addSubview:AlertTable.view];
I also implemented:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Set up the cell...
[[cell textLabel] setText:[AlertsItems objectAtIndex:indexPath.row]];
NSLog (#"%#",[AlertsItems objectAtIndex:indexPath.row]);
return cell;
}
Do you have any idea what the problem could be?
I'm not very experienced in Xcode and I'm really stuck.
Edit:
I know that it is not custom, but the link to the project can be found here (perhaps I'm overlooking something:
https://www.bilbu.be/BarConnect_v2.zip
The LoginViewController.xib is not properly linked (it is available in the en.lproj subfolder) so you may need to link first (I noticed too late and I had the file uploaded by a friend before - I cannot re-upload it myself unfortunately).
ViewController VC class calls the AlertsTable VC class. There is more in the project that I suppose you can ignore...
Note that the purpose of this project is only to serve as visual interface prototype. It is not meant to be the best optimized application (this is what other developers will do). If this doesn't work, I will use Photoshop to create the interfaces, but I guess that's not gonna be as convincing...
I successfully compiled your project. The problem is that you're going against the MVC pattern. The controller (AlertsTable) is inside of a view (CMPopTipView). I'd suggest you to rethink the hierarchy of the controllers and views. Hope this will help you.
Try changing
TableView.userInteractionEnabled = YES;
TableView.allowsSelection = YES;
TableView.allowsSelectionDuringEditing = YES;
to
self.TableView.userInteractionEnabled = YES;
self.TableView.allowsSelection = YES;
self.TableView.allowsSelectionDuringEditing = YES;
and are you allocating self.TableView? Something like...
self.TableView = [[UITableView alloc] init];//[[UITableView alloc] initWithStyle:UITableViewStylePlain];
I just started using xcode and OBJ-c this year.
I am using mwfeedparser for a app I'm making but would like to change the look of the detailview.
right now i'm using the demo app that came with mwfeedparser to change the detail view.
i would like the detail view to have labels instead of being a tableview
i have changed this code
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detail = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detail.item = (MWFeedItem *)[itemsToDisplay objectAtIndex:indexPath.row];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detail animated:YES];
// Deselect
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
when i run the code the detailview doesn't even come up. am I doing something wrong?
thanks for your help.
btw when i do get this done I'll put it up on github incase anybody else needs it
enter code hereself.parsedItems = [[NSMutableArray alloc] init];
- (void)feedParser:(MWFeedParser *)parser didParseFeedItem:(MWFeedItem *)item{
if (item) {
[self.parsedItems addObject:item];
}
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detail = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detail.item = [self.parsedItems objectAtIndex:indexPath.row];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detail animated:YES];
}
I have a tableview with two actions in it, for the first on i use the delegate didSelectRowAtIndexPath, for the second one i would like to use an action on a button on my cell to do something else. My problem is that i don't succeed to get the indexpath ? What is the best practice to do that.
If you have added the button to the cell as,
[cell.contentView addSubview:button];
then, you can get the index path as,
- (void)onButtonTapped:(UIButton *)button {
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
// Go ahead
}
I'm using this solution -- getting index path of cell using points
CGPoint center= [sender center];
CGPoint rootViewPoint = [[sender superview] convertPoint:center toView:_tableView1];
NSIndexPath *indexPath = [_tableView1 indexPathForRowAtPoint:rootViewPoint];
NSLog(#"%#",indexPath);
Its work perfectly
here is the full code for a custom button:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomCellFilter *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {cell = [[CustomCellFilter alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}
//configure your cell here
cell.titleLabel.text = #"some title";
//add button
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
resetButton.frame = CGRectMake(40, 10, 18, 18);
[resetButton addTarget:self action:#selector(onButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[resetButton setImage:[UIImage imageNamed:#"someimage.png"] forState:UIControlStateNormal];
[cell.contentView addSubview:myButton];
//afterwards return the cell
return cell;
- (void)onButtonTapped:(UIButton *)button {
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
NSIndexPath *indexPath = [filterTable indexPathForCell:cell];
NSLog(#"%#", indexPath);
//use indexPath here...
}
In case you are using a collection view, you can use Yogesh method, but change indexPathForRowAtPoint for indexPathForItemAtPoint like this:
CGPoint center= [sender center];
CGPoint rootViewPoint = [[sender superview] convertPoint:center toView:_tableView1];
NSIndexPath *indexPath = [_tableView1 indexPathForRowAtPoint:rootViewPoint];
NSLog(#"%#",indexPath);
In case that your button is moved or Apple changes the view hierarchy for accessory views, this method goes up the chain to look for a UITableViewCell:
- (void)tapAccessoryButton:(UIButton *)sender {
UIView *parentView = sender.superview;
// the loop should take care of any changes in the view heirarchy, whether from
// changes we make or apple makes.
while (![parentView.class isSubclassOfClass:UITableViewCell.class])
parentView = parentView.superview;
if ([parentView.class isSubclassOfClass:UITableViewCell.class]) {
UITableViewCell *cell = (UITableViewCell *) parentView;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[self tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
}
}
How to change it back from activity indicator to disclosure ??
the problem is:
When i didSelectRow, i made disclosure to activity indicator because it will load some picture for the next view controller and It's worked, but i dont have any luck to change it back to disclosure after pushViewController. i already tried to reload the table from the 2ndViewController but it's crashed.
So anybody have a solution for this problem..
Thanks in advance
This is my code in didSelectRow :
-(void)threadStartAnimating:(id)data
{
[activityView startAnimating];
[self.navigationController pushViewController:bdvController animated:YES];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[cell setAccessoryView:activityView];
[NSThread detachNewThreadSelector:#selector(threadStartAnimating:) toTarget:self withObject:nil];
// Navigation logic -- create and push a new view controller
if(bdvController == nil)
bdvController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:[NSBundle mainBundle]];
AppRecord *appRecord = [self.entries objectAtIndex:indexPath.row];
bdvController.appsRecord = appRecord;
bdvController.HeaderText.text = appRecord.appName;
bdvController.title = appRecord.artist;
[bdvController.tableView reloadData];
}
The best way is to set pointer nil to the accessoryView, example:
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
In my code these operations work fine.
I'm working with the google YouTube API, and I'm using this code found here http://pastebin.com/vmV2c0HT
The Code that slows things down is this one here
cell.imageView.image = [UIImage imageWithData:data];
When I remove that code it scrolls smoothly. Any idea on how I can go about having it load the images from google but still scroll smoothly? I've read some of the answers on loading images in a different way, but I still can't figure out how I'll make that work with the code I'm using.
Any help will be appreciated.
Bellow is the full code.
#import "RootViewController.h"
#interface RootViewController (PrivateMethods)
- (GDataServiceGoogleYouTube *)youTubeService;
#end
#implementation RootViewController
#synthesize feed;
- (void)viewDidLoad {
NSLog(#"loading");
GDataServiceGoogleYouTube *service = [self youTubeService];
NSString *uploadsID = kGDataYouTubeUserFeedIDUploads;
NSURL *feedURL = [GDataServiceGoogleYouTube youTubeURLForUserID:#"BmcCarmen"
userFeedID:uploadsID];
[service fetchFeedWithURL:feedURL
delegate:self
didFinishSelector:#selector(request:finishedWithFeed:error:)];
[super viewDidLoad];
}
- (void)request:(GDataServiceTicket *)ticket
finishedWithFeed:(GDataFeedBase *)aFeed
error:(NSError *)error {
self.feed = (GDataFeedYouTubeVideo *)aFeed;
[self.tableView reloadData];
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[feed entries] count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
GDataEntryBase *entry = [[feed entries] objectAtIndex:indexPath.row];
NSString *title = [[entry title] stringValue];
NSArray *thumbnails = [[(GDataEntryYouTubeVideo *)entry mediaGroup] mediaThumbnails];
cell.textLabel.text = title;
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[thumbnails objectAtIndex:0] URLString]]];
cell.imageView.image = [UIImage imageWithData:data];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100.0f;
}
- (void)dealloc {
[super dealloc];
}
- (GDataServiceGoogleYouTube *)youTubeService {
static GDataServiceGoogleYouTube* _service = nil;
if (!_service) {
_service = [[GDataServiceGoogleYouTube alloc] init];
[_service setShouldCacheDatedData:YES];
[_service setServiceShouldFollowNextLinks:YES];
}
// fetch unauthenticated
[_service setUserCredentialsWithUsername:nil
password:nil];
return _service;
}
#end
GCD is a wonderful thing. Here is what I do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"youTubeCell";
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
GDataEntryBase *entry = [[feed entries] objectAtIndex:indexPath.row];
NSString *title = [[entry title] stringValue];
NSArray *thumbnails = [[(GDataEntryYouTubeVideo *)entry mediaGroup] mediaThumbnails];
cell.textLabel.text = title;
// Load the image with an GCD block executed in another thread
dispatch_queue_t downloadQueue = dispatch_queue_create("image downloader", NULL);
dispatch_async(downloadQueue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[thumbnails objectAtIndex:0] URLString]]];
UIImage * image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
[cell setNeedsLayout];
});
});
dispatch_release(downloadQueue);
return cell;
}
Scrolling is now super smooth. The only drawback is that when you scroll quickly, cells are re-used and sometimes the images change as new ones come in.