I am trying to get a custom image working with the accessoryButtonTappedForRowWithIndexPath function. From what I understand in order to do this, you have to use a UIButton, simply adding a UIImageView on the UITableViewCellAccessoryDetailDisclosureButton will not work.
My problem is how to get the touch gesture from my UITableViewCell subclass into the parent UITableView function.
Here is the code in my UITableViewCell subclass:
upVote = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *upVoteImg = [UIImage imageNamed:#"vote.png"];
upVote.frame = CGRectMake(self.frame.size.width-upVoteImg.size.width, 0, upVoteImg.size.width , upVoteImg.size.height);
[upVote setBackgroundImage:upVoteImg forState:UIControlStateNormal];
[self.contentView addSubview:upVote];
[upVote addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
The calling function (also inside the subclass of the UITableViewCell)
- (void)checkButtonTapped:(id)sender event:(id)event
{
UITableView *tableView = (UITableView *)self.superview;
[tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:[tableView indexPathForCell:self]];
}
It crashes at the final line of the above function with this:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewWrapperView
delegate]: unrecognized selector sent to instance 0x16f48160'
Yes it should crash, because delegate of tableview should not be called from custom cell class, better you can use custom delegate. I am posting a sample code, similar to your case, when button tapped it call's the custom delegate method from that u can do whatever you want
//in custom calss
#import <UIKit/UIKit.h>
//create a delegate
#protocol CustomDelegate<NSObject>
-(void)whenButtonTapped:(id)sender; //your delegate method
#end
#interface CustomCell : UITableViewCell<CustomDelegate>
#property(nonatomic, assign)id<CustomDelegate> delegate; //create delegate
#end
//.m file of custom cell
#import "CustomCell.h"
#implementation CustomCell
#synthesize delegate; //sysnthesize delegate
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; //its your button
UILabel *aLabel = [[UILabel alloc]initWithFrame:CGRectZero]; //for example i took label
[aButton addTarget:self action:#selector(whenButtonTapped:) forControlEvents:UIControlEventTouchUpInside];//adding target for button action
[aButton setTag:100];
[aLabel setTag:200];
[self addSubview:aButton];
[self addSubview:aLabel];
//since i am using without ARC
[aLabel release];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)dealloc
{
delegate = nil;
[super dealloc];
}
//i am setting the frames hear
-(void)layoutSubviews
{
[super layoutSubviews];
UIButton *aButton = (UIButton *)[self viewWithTag:100]; //get button
aButton.frame = CGRectMake(200, 5, 55, 40);
[aButton setTitle:#"tapMe" forState:UIControlStateNormal];
UILabel *label = (UILabel *) [self viewWithTag:200]; //get label
label.frame = CGRectMake(40, 5, 50, 35);
label.text = #"hello";
}
//hear is ur button's target
- (void)whenButtonTapped:(id)sender
{
//dont call UITableView delegate method in custom cell it is wrong, ur app get crashed
//insted create custom delegate method to your controller
[self.delegate whenButtonTapped:sender];//call the delegate method when button tapped
}
#end
//.h file where u are using custom cell
#import <UIKit/UIKit.h>
#import "CustomCell.h"
#interface ViewController : UIViewController<UITableViewDataSource , UITableViewDelegate ,CustomDelegate>//set confirms to delegate
#property (retain, nonatomic) IBOutlet UITableView *aTableView;
#end
//.m file
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *aCell = [self.aTableView dequeueReusableCellWithIdentifier:#"cell"];
if(aCell == nil)
{
aCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
aCell.delegate = self;//set delegate to this class
return aCell;
}
//hear is your delegate method
//define your delegate method hear
-(void)whenButtonTapped:(UIButton *)sender
{
//in this method u can do what ever the activity when button tapped
//sender which gives u entire cell information
UITableViewCell *cell = sender.superview;//you can get cell also :)
NSLog(#"button tapped");
}
Hopes this helps
How about a better one?
UITableView *tableview;
if ([self.superview respondsToSelector:#selector(indexPathForCell:)] ) {
tableview = (UITableView *)self.superview;
} else if ([self.superview.superview respondsToSelector:#selector(indexPathForCell:)]) {
tableview = (UITableView *)self.superview.superview;
}
if (tableview) {
// win
}
I have a category on UITableViewCell that looks like this.
- (UITableView *)tableView
{
UIView *view = self.superview;
while (view)
{
if ([view isKindOfClass:[UITableView class]])
{
return (UITableView *)view;
}
else
{
view = view.superview;
}
}
return nil;
}
- (NSIndexPath *)indexPath
{
return [[self tableView]indexPathForCell:self];
}
Then I just hook my custom button up to a method in my custom tableview cell (which imports my category) to a method such as this.
- (IBAction)customButtonPressed:(id)sender
{
[self.tableView.delegate tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:self.indexPath];
}
Related
I am on iOS7 and have a UITableViewCell subclass for my UITableView with static cells. I am overriding the setSelected method in the implementation.
For some reason, the method only gets called when the table loads but doesn't get called when the cell is actually tapped and selected.
What am I doing wrong here? How do I get it to work?
#implementation StudentMenuMultipleOptionsTableViewCell
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
UIView *view = [UIView new];
view.backgroundColor = [UIColor colorWithRed:0.542 green:0.788 blue:0.060 alpha:1.000];
self.selectedBackgroundView = view;
}
else {
for (UIView *view in self.subviews) {
if ([view isKindOfClass:[BlackBackgroundSelectedButton class]]) {
BlackBackgroundSelectedButton *button = (BlackBackgroundSelectedButton *)view;
button.selected = NO;
[button setWhite];
}
}
}
}
#end
The problem was that I was using the setSelected method. The method that needs to be used for the newer iOS versions is:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated;
I am trying to populate UITableView from NSMutableArray. I have UITextField and a button on a ViewController. When I type any text in the UITextField and click button, I can see the text being added to the array with NSLog. I set breakpoints on the data source method of UITableView but it does not even hit those breakpoints when I click the button.
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
{
NSMutableArray *arrBarcode;
IBOutlet UITextField *txtInsert;
}
#property IBOutlet UITableView *myTableView;
-(IBAction)btnPressed:(id)sender;
#end
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
arrBarcode = [[NSMutableArray alloc]init];
}
-(IBAction)btnPressed:(id)sender{
[arrBarcode addObject:txtInsert.text];
NSLog(#"array count is : %i", [arrBarcode count]);
[self.myTableView reloadData];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[txtInsert resignFirstResponder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfSectionsInTableView: (UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if ([arrBarcode count] == 0){
return 0;
}
else{
NSLog(#"Number of Rows : %i", [arrBarcode count]);
return [arrBarcode count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell Identifier";
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *barcode = [arrBarcode objectAtIndex:[indexPath row]];
[cell.textLabel setText:barcode];
return cell;
}
#end
When I initialize a NSMutable Array with some data in the viewDidLoad method, the UITableView is populating fine but not with dynamic array. I am newbie in Objective C, Can someone point me to right direction?
Code looks OK (even if not very efficient). You have to check if the button is indeed connected to the action. In storyboard or Interface Builder, select the button and check the rightmost inspector on the right. See if the action is correctly connected.
Maybe you want to get rid of the touchesBegan call and call resignFirstResponder when the button is pressed.
For numberOfRowsInSection I think this is enough:
return arrBarcode.count;
I'm not sure but the following line looks strange to me:
#synthesize myTableView = myTableView_;
This is telling the compiler to make a getter and setter for the property myTableView and backing it with an iVar named myTableView_. But in your case you have already defined an iVar named myTableView_.
Try connecting the UITableView as a property instead. A property will be backed by an instance variable with the form _yourProperty and have getter and setter generated automatically so #synthesize isn't really needed in this case.
I am trying to achieve this:
but i get this:
I have a view cotroller with a view table on it
This is the interface:
#interface LoginViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tblCredentials;
#end
This is the implementation:
#interface LoginViewController ()
#end
#implementation LoginViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void)viewWillAppear:(BOOL)animated
{
self.tblCredentials.delegate=self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2;
}
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UITextField *textField = [[UITextField alloc] init];
textField.enablesReturnKeyAutomatically = YES;
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
CGRect cellBounds = cell.bounds;
CGFloat textFieldBorder = 10.f;
CGRect aRect = CGRectMake(textFieldBorder, 9.f, CGRectGetWidth(cellBounds)-(2*textFieldBorder), 31.f );
textField.frame = aRect;
if(indexPath.row==0)
{
textField.placeholder = #"Username";
textField.returnKeyType = UIReturnKeyNext;
textField.autocapitalizationType = UITextAutocapitalizationTypeWords;
}
else
{
textField.placeholder = #"Password";
textField.returnKeyType = UIReturnKeyDone;
textField.secureTextEntry = YES;
}
[cell.contentView addSubview:textField];
return cell;
}
#end
I put a breakpoint on the in the cellForRowAtIndexPath and it doesn't stop there, so those text fields don't get rendered.
What am I missing?
PS: Is this a bad approach to achieve the goal? (those two grouped text fields)
LE: I am using stroyboard with no xib files
In viewDidLoad, you must set the delegate and call [self.tblCredentials reloadData] in order for the table view to actually "load its data"
You need to create a Custom Table View cell. have a look at this github link.
You're setting the delegate of the table view, but not the datasource, which is where the number of rows etc. comes from.
You're also setting the delegate a bit late in the cycle. Since this is in a xib, why not set the delegate and datasource in the xib instead of in code? If you declare that your view controller conforms to the delegate and data source properties in the header, you will be able to make the connection in IB. If you insist on setting it in code, it should be in viewDidLoad.
Set delegate and dataSource in -viewDidLoad and put [self.tblCredentials reloadData] in -viewWillAppear:.
- (void)viewDidLoad
{
[super viewDidLoad];
self.tblCredentials.delegate=self;
self.tblCredentials.dataSource=self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated]; // BTW, it's better to call super's -viewWillAppear: here, according to apple's documentation.
[self.tblCredentials reloadData];
}
I am trying to set up UICollectionView programatically in my view controller which extends UIViewController. For some reason, my collection view is not showing up at all. Below is what I have.
Why is it not appearing? I am hooking it up to the delegate and data source and adding it as a subview to self.view. What's missing in my code?
In my .h file:
#interface MainViewController : UIViewController
{
#private
UICollectionView *_collectionView;
NSMutableArray *_results; // data source array
}
#end
In my .m file:
#interface MainViewController () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
#property (nonatomic, retain) UICollectionView *collectionView;
#property (nonatomic, retain) NSMutableArray *results;
#end
#implementation MainViewController
#synthesize collectionView = _collectionView;
#synthesize results = _results;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// some init stuff - nothing to do with collection view.
}
return self;
}
- (void)loadView
{
self.results = [NSMutableArray array];
UIImage *image1 = [UIImage imageNamed:#"img1.jpg"];
UIImage *image2 = [UIImage imageNamed:#"img2.jpg"];
[self.results addObject:image1];
[self.results addObject:image2];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:flowLayout];
self.collectionView = collectionView;
[self.view addSubview:self.collectionView];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.collectionView reloadData];
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
return [self.results count];
}
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithPatternImage:[self.results objectAtIndex:indexPath.row]];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
UIImage *image = [self.results objectAtIndex:indexPath.row];
return CGSizeMake(image.size.width, image.size.height);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(50, 20, 50, 20);
}
I got errors trying to run your code unless I changed the loadView method to viewDidLoad -- according to the docs you're not supposed to directly call loadView. To get the data source and delegate methods to run, I moved the lines setting the delegate and data source to self below where you set self.collectionView = collectionView
self.collectionView = collectionView;
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
Your numberOfSectionsInCollectionView: returns 0. For a collection view with one section, you should either return 1 or just not implement this method.
Also I cannot see where you alloc/init self.collectionView.
I ended up subclassing UICollectionViewController instead of UIViewController and changing the init method to:
- (id)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
and it worked.
You only had to bind your CollectionView delegate, and dataSource to ViewController in the StoryBoard.enter image description here
I have been looking at similar question but couldn't figure it out what is the problem.It seems it should work but it gives me error.
In IOS 5.1 Ipad Stortyboard application I have a right navigation bar item when user click a popover view should open. I had a working popover view but design was not good so I replaced it with a new popover class now it gives me following error
-[UIButton view]: unrecognized selector sent to instance 0xa17ba80
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButton view]: unrecognized selector sent to instance 0xa17ba80'
I have tried following functions but none has worked so far. It gives me similar errors when I change the code.
- (IBAction)setColorButtonTapped:(id)sender{
- (void)setColorButtonTapped:(id)sender{
- (IBAction)setColorButtonTapped:(id)sender forEvent:(UIEvent*)event {
- (void)setColorButtonTapped:(id)sender forEvent:(UIEvent*)event {
and ofcourse I have changed ti following regarding to ibaction or void
[backButton2 addTarget:self action:#selector(setColorButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
here is the code
my.h file
#import <UIKit/UIKit.h>
#import "ColorPickerController.h"
#interface MeetingViewController : UITableViewController<UIApplicationDelegate,UIAlertViewDelegate,DropDownListDelegate,MFMailComposeViewControllerDelegate,EGORefreshTableHeaderDelegate,ColorPickerDelegate>{
UIPopoverController *_popover;
ColorPickerController *_colorPicker;
UIPopoverController *_colorPickerPopover;
}
#property (nonatomic, strong) UIPopoverController *popover;
#property (nonatomic, strong) ColorPickerController *colorPicker;
#property (nonatomic, strong) UIPopoverController *colorPickerPopover;
- (IBAction)setColorButtonTapped:(id)sender;
#end
my.m file
#synthesize popover = _popover;
#synthesize colorPicker = _colorPicker;
#synthesize colorPickerPopover = _colorPickerPopover;
- (void)viewDidLoad
{
[super viewDidLoad];
//gear button on navigation Bar
UIImage* imageback2 = [UIImage imageNamed:#"ICON - Gear#2x.png"];
CGRect frameimgback2 = CGRectMake(0, 0, 40, 40);
UIButton *backButton2 = [[UIButton alloc] initWithFrame:frameimgback2];
[backButton2 setBackgroundImage:imageback2 forState:UIControlStateNormal];
[backButton2 addTarget:self
action:#selector(setColorButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *btn2 = [[UIBarButtonItem alloc] initWithCustomView:backButton2];
self.navigationItem.rightBarButtonItem = btn2;
}
#pragma mark ColorPickerDelegate
- (void)colorSelected:(NSString *)color {
[self.colorPickerPopover dismissPopoverAnimated:YES];
}
#pragma mark Callbacks
- (IBAction)setColorButtonTapped:(id)sender {
if (_colorPicker == nil) {
self.colorPicker = [[ColorPickerController alloc] initWithStyle:UITableViewStylePlain];
_colorPicker.delegate = self;
self.colorPickerPopover = [[UIPopoverController alloc] initWithContentViewController:_colorPicker];
}
[self.colorPickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
utility class
ColorPickerController.h
#import <UIKit/UIKit.h>
#protocol ColorPickerDelegate
- (void)colorSelected:(NSString *)color;
#end
#interface ColorPickerController : UITableViewController {
NSMutableArray *_colors;
id<ColorPickerDelegate> __weak _delegate;
}
#property (nonatomic, strong) NSMutableArray *colors;
#property (nonatomic, weak) id<ColorPickerDelegate> delegate;
#end
utilityclass
ColorPickerController.m
#import "ColorPickerController.h"
#implementation ColorPickerController
#synthesize colors = _colors;
#synthesize delegate = _delegate;
#pragma mark -
#pragma mark Initialization
/*
- (id)initWithStyle:(UITableViewStyle)style {
// Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
if ((self = [super initWithStyle:style])) {
}
return self;
}
*/
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(150.0, 140.0);
self.colors = [NSMutableArray array];
[_colors addObject:#"Red"];
[_colors addObject:#"Green"];
[_colors addObject:#"Blue"];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
return YES;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [_colors 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];
}
// Configure the cell...
NSString *color = [_colors objectAtIndex:indexPath.row];
cell.textLabel.text = color;
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (_delegate != nil) {
NSString *color = [_colors objectAtIndex:indexPath.row];
[_delegate colorSelected:color];
}
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc {
self.delegate = nil;
}
#end
Help is much appreciated , thanks
You're using a UIButton as a customView for a UIBarButtonItem. This could be the problem.
I suggest you use UIBarButtonItem's initWithImage:style:target:action: initializer instead.
UIButton is a view and as such has no view property or instance method.