I have a UIViewController with a UICollectionView image gallery created inside it programmatically. I want to add a button to the on each uiimage of UICollectionView cell: The code in CMFViewController.h.m file for adding button to imageview is:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CMFGalleryCell *cell = (CMFGalleryCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
NSString *imageName = [self.dataArray objectAtIndex:indexPath.row];
[cell setImageName:imageName];
// [[cell myButton] addTarget:self action:#selector(myClickEvent:event) forControlEvents:UIControlEventTouchUpInside];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(80.0, 210.0, 100.0, 20.0);
[button addTarget:self action:#selector(show) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"ShowView" forState:UIControlStateNormal];
// NSMutableArray *buttonArray = [NSMutableArray arrayWithCapacity:100];
// for (int i = 0; i < 4; i++) {
// NSUInteger index = arc4random() % 4;
// newButton.frame = CGRectMake( 5, 5, 10, 10); // Whatever position and size you need...
// UIImage *buttonImage = [UIImage imageNamed:[self.dataArray objectAtIndex:indexPath.row]];
//[newButton setBackgroundImage:buttonImage forState:UIControlStateNormal];
// [buttonArray addObject:newButton];
// }
// newButton = buttonArray; // Where myButtons is a NSArray property of your class, to store references to the buttons.
// [newButton addTarget:self action:#selector(loadImages:) forControlEvents:UIControlEventTouchUpInside];
//[newButton addTarget:self action:#selector(updateCell) forControlEvents:UIControlEventTouchUpInside];
[cell updateCell];
return cell;
}
I have tied to get help from codes at following links
adding-a-uibutton-to-a-uicollectionview
UIButton in cell in collection view not receiving touch up inside event
Please give my your suggestion and help me on this issue.
from this link u can download source code in Creating a Paged Photo Gallery With a UICollectionView: their i want to place next and previous buttons on middle lines of each image of the screen
For implementing next and previous buttons, don't added it on each image, better u add it on collection view, what chinttu-maddy-ramani told in his answer is correct, but he is doing in xib file, but programatically u can do it like below,
just add this code
Edit for requirement updating the buttons
in CMFViewController.h file make two button properties
replace by below code
#import <UIKit/UIKit.h>
#interface CMFViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
#property (nonatomic, strong) UIButton *nextButton;
#property (nonatomic, strong) UIButton *prevButton;
#end
in CMFViewController.m file
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self loadImages];
[self setupCollectionView];
[self addNextAndPreviousButtons];//add a method to add previous and next buttons
}
//hear u are adding previous and next images, but i didn't added the constraints u add it if u want t work in both orientation
- (void)addNextAndPreviousButtons
{
_nextButton = [UIButton buttonWithType:UIButtonTypeSystem];
_nextButton.frame =CGRectMake(self.view.bounds.size.width - 40, self.view.bounds.size.height/2, 50, 30);
[_nextButton setTitle:#"Next" forState:UIControlStateNormal];
[_nextButton addTarget:self action:#selector(nextButtonAction:) forControlEvents:UIControlEventTouchUpInside];
_prevButton = [UIButton buttonWithType:UIButtonTypeSystem];
_prevButton.frame = CGRectMake(self.view.bounds.origin.x, self.view.bounds.size.height/2, 50, 30);
[_prevButton setTitle:#"Prev" forState:UIControlStateNormal];
[_prevButton addTarget:self action:#selector(previousButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_nextButton];
[self.view addSubview:_prevButton];
}
//previous button action
- (void)previousButtonAction:(id)sender
{
NSArray *visibleCell = [_collectionView visibleCells];
if(visibleCell)
{
NSIndexPath *path = [_collectionView indexPathForCell:[visibleCell lastObject]];
if(!path.row == 0)
{
NSIndexPath *nextPath = [NSIndexPath indexPathForItem:(path.row - 1) inSection:0];
[_collectionView scrollToItemAtIndexPath:nextPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}
}
}
//next button action
- (void)nextButtonAction:(id)sender
{
NSArray *visibleCell = [_collectionView visibleCells];
if(visibleCell)
{
NSIndexPath *path = [_collectionView indexPathForCell:[visibleCell lastObject]];
if(path.row < [_dataArray count] - 1)
{
NSIndexPath *nextPath = [NSIndexPath indexPathForItem:(path.row + 1) inSection:0];
[_collectionView scrollToItemAtIndexPath:nextPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}
}
}
//edited the method addNextAndPreviousButtons please replace it by this edited answer
//for all cases even when u are swiping
//this is to handle buttons either by tapping or navigation through swiping the collection view
- (void)updateButtons:(NSInteger)row
{
//at the beginning
if(row == 0)
{
_prevButton.hidden = YES;
_nextButton.hidden = NO;
return;
}
else if(row == ([_dataArray count] -1))
{
_nextButton.hidden = YES;
_prevButton.hidden = NO;
}
else
{
_nextButton.hidden = NO;
_prevButton.hidden = NO;
}
}
//finally u have to call updateButtons method this method
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CMFGalleryCell *cell = (CMFGalleryCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
NSString *imageName = [self.dataArray objectAtIndex:indexPath.row];
[cell setImageName:imageName];
[cell updateCell];
[self updateButtons:indexPath.row]; //update the buttons
return cell;
}
you can add button in you cell to direct drag & drop button in CMFGalleryCell.xib please check attach screenshot. and add button constraint to center horizontally and center vertically with your cell.
for suggestion only if you want next-previous functionality then you can also add button in main xib in CMFViewController.xib as per below screenshot.
Related
I created the UITableView programatically, and in my UITableView have 3 rows in the UITableView section. I have a UIButton in 3 rows. Initially, all the buttons of three rows have gray color. If I select the button in the 2nd row, then the button in the 2nd row should be red and the all others gray and so on. Can any one suggest me.
In your cellForRowAtIndexPath
UIButton *button = [[UIButton alloc]initWithFrame:Your Frame];
[button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
button.tag = indexPath.section;
[cell.contentView addSubview:button];
Then write buttonClicked method
-(void)buttonClicked:(UIButton*)button
{
UIButton *but1;
UIButton *but2;
if (button.tag == 0)
{
but1 = (UIButton *)[self.view viewWithTag:1];
but2 = (UIButton *)[self.view viewWithTag:2];
[but1 setBackgroundColor:[UIColor grayColor]];
[but2 setBackgroundColor:[UIColor grayColor]];
[button setBackgroundColor:[UIColor redColor]];
}
if (button.tag == 1)
{
but1 = (UIButton *)[self.view viewWithTag:0];
but2 = (UIButton *)[self.view viewWithTag:2];
[but1 setBackgroundColor:[UIColor grayColor]];
[but2 setBackgroundColor:[UIColor grayColor]];
[button setBackgroundColor:[UIColor redColor]];
}
if (button.tag == 2)
{
but1 = (UIButton *)[self.view viewWithTag:0];
but2 = (UIButton *)[self.view viewWithTag:1];
[but1 setBackgroundColor:[UIColor grayColor]];
[but2 setBackgroundColor:[UIColor grayColor]];
[button setBackgroundColor:[UIColor redColor]];
}
}
Hope it helps.
Try this:
Create the button as mentioned by patil (look below for his answer) ,and try to give it a tag.
button.tag=indexpath.section;
You need to set target-action of each button.Write the following line in the button action method:
[button setTarget:self action:#selector(someMethod:) forControlEvents:UIControlEventTouchUpInside];
Then implement someMethod: like this:
- (void)someMethod:(UIButton *)sender {
if (sender.tag == 1) {
// do action for button with tag 1
//change color here
[button setBackgroundColor:[UIColor redColor]];
} else if (sender.tag == 2) {
// do action for button with tag 2
} // ... and so on
}
I'm not too fond of the multiple if cases as you would need to re-write a lot when your amount of sections / rows change.
This is a more generic answer but it might not be so easy as the others. It involves created a UIButton subclass and a UITableViewCell subclass.
Create a UIButton subclass with a property to store the NSIndexPath of the cell where the button will be shown on:
//
// IndexPathButton.h
//
//
// Created by You on 28/07/15.
//
//
#import <UIKit/UIKit.h>
#interface IndexPathButton : UIButton
#property (nonatomic) NSIndexPath *indexPath;
#end
There should not be anything implemented in the .m file.
Create a UITableViewCell subclass which has the custom IndexPathButton on it. If you need help creating a custom UITableViewCell I suggest searching on SO or creating a new question.
In your UIViewController with your UITableView do the import of the custom UIButton
#import "IndexPathButton.h"
Also create an class variable to store the selectedIndexPath:
NSIndexPath *selectedButtonIndexPath;
Now we can start changing the UITableViewDataSource method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellId = #"SomeCell";
YourCustomCellWithButton *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell)
{
cell = [[YourCustomCellWithButton alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
//Default setup of IndexPathButton on YourCustomCellWithButton
cell.button.backgroundColor = [UIColor grayColor];
cell.button.indexPath = indexPath; //Here we store the indexPath for later use
[cell.button addTarget:self action:#selector(cellButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
//Check here if it should be red or not
if (selectedButtonIndexPath == indexPath)
{
cell.button.backgroundColor = [UIColor redColor];
}
return cell;
}
And the button target action:
-(void)cellButtonPressed:(IndexPathButton*)sender
{
//Set the selectedIndexPath
selectedButtonIndexPath = sender.indexPath;
[yourTableView reloadData];
}
I have a subclassed UITableViewCell with a "Start" and "Done" button on each cell. The "Done" button gets created after you press "Start". If I have my button press logic in my subclassed UITableViewCell file, it triggers just fine.
But I realize I actually want the button press to trigger the editing mode in the table view, so I want to have some logic in my cellForRowAtIndexPath instead of the subclassed file. But then I can't get the button to fire :(
What am I doing wrong or not understanding?
My TableViewCell.m
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self.startButton = [[UIButton alloc] initWithFrame:CGRectMake(250 + 0.60 * self.screenWidth, 65, 150, 30)];
[self.startButton addTarget:self action:#selector(onStartButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
self.startButton.backgroundColor = [UIColor colorWithRed:0.16 green:0.65 blue:0.19 alpha:1.0];
btnLayer = [self.startButton layer];
[btnLayer setMasksToBounds:YES];
[btnLayer setCornerRadius:5.0f];
[self.startButton setTag:1];
[self addSubview:self.startButton];
}
- (void)onStartButtonPressed:(id)sender {
if (self.countdown)
{
[self beginDoneButton];
}
}
-(void)beginDoneButton {
self.startButton.enabled = NO;
self.startButton.hidden = YES;
self.doneButton = [[UIButton alloc] initWithFrame:CGRectMake(250 + 0.60 * self.screenWidth, 65, 150, 30)];
self.doneButton.backgroundColor = [UIColor colorWithRed:0.16 green:0.65 blue:0.19 alpha:1.0];
CALayer *btnLayer = [self.doneButton layer];
[btnLayer setMasksToBounds:YES];
[btnLayer setCornerRadius:5.0f];
[self.doneButton setTitle:#"Done "forState:UIControlStateNormal];
[self addSubview:self.doneButton];
}
My TableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// get index of Data
int index = (int) indexPath.row;
id order = [orders objectAtIndex:index];
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"orderCell"];
cell = [[OrderTableViewCell alloc] initWithStyle:UITableViewCellSelectionStyleNone reuseIdentifier:#"orderCell"];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.customerNameLabel.text = [order objectForKey:#"first_name"];
cell.orderLabel.text = [NSString stringWithFormat: #"Order #%#", [order objectForKey:#"order_id"]];
[cell.customerImageView sd_setImageWithURL:[NSURL URLWithString: [order objectForKey:#"profile_image"]]
placeholderImage:[UIImage imageNamed:#"stub"]
];
[cell.messageButton setTitle:#"Message" forState:UIControlStateNormal];
// This doesn't work
[cell.doneButton addTarget:self action:#selector(onDoneButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
// This doesn't get fired
- (IBAction)onDoneButtonPressed:(id)sender {
NSLog(#"pressed");
UITableViewCell *cell = (UITableViewCell *)[sender superview];
NSIndexPath *pathToCell = [self.tv indexPathForCell:cell];
}
How about this:
In your custom table view cell, create your buttons but don't add target/actions to them Just connect them to an IBOutlet in your cell's class.
Then in your cellForRowAtIndexPath, cast your cell pointer to your custom cell class, and use cell.button1Outlet outlet to set the target/action on the buttons with the view controller as the target. Now your cell buttons will invoke a method in the view controller, not in the cell, even though the outlets belong to the cells.
I have written a subclass of UITableViewCell to allow horizontal swipe to give some actions to users. Here is what I am doing:
Create a scrollView
Create a buttonView and add in scrollView.
Create a UIButton and add all cell controls as subview to it. Add in scroll view.
Add scrollView to cell contentView.
For #3 I am setting the highlighted image to give a feel of user tap like in normal cell.
The issue is when my table view is loaded on iOS 6 with 6 cells and user tap on any of the cell, cell gets highlighted properly and the details are shown properly for the tapped cell. But if user scrolls up and first cell is re-used and user tap on the top cell (which is second row), cell next to it gets highlighted. If user scrolls up and purge 2 cells and tap on the top cell, cell 2 cells down it gets highlighted. Although tapped cell shows the data of the correct cell.
Any clue?
- (id)initWithStyle:(UITableViewCellStyle)iStyle reuseIdentifier:(NSString *)iReuseIdentifier andMenuButtonDetails:(NSArray *)iMenuButtonDetails {
if ((self = [super initWithStyle:iStyle reuseIdentifier:iReuseIdentifier])) {
self.catchWidth = kMenuButtonWidth * [iMenuButtonDetails count];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(kScreenOrigin, kScreenOrigin, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds) + self.catchWidth, CGRectGetHeight(self.bounds));
self.scrollView.delegate = self;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.scrollEnabled = YES;
[self.contentView addSubview:self.scrollView];
self.scrollViewButtonView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds) - self.catchWidth, kScreenOrigin, self.catchWidth, CGRectGetHeight(self.bounds))];
[self.scrollView addSubview:self.scrollViewButtonView];
if ([iMenuButtonDetails count]) {
// Adding menu buttons to the cell.
CGFloat anXOffset = kScreenOrigin;
for (NSDictionary *aMenuButton in iMenuButtonDetails) {
if ([aMenuButton containsObjectForKey:kTitleKey]) {
UIButton *aButton = [[UIButton alloc] initWithFrame:CGRectMake(anXOffset, kScreenOrigin, kMenuButtonWidth, kCellHeight64)];
[aButton addTarget:self action:#selector(buttonSelected:) forControlEvents:UIControlEventTouchUpInside];
if ([aMenuButton containsObjectForKey:kButtonTagKey])
aButton.tag = [[aMenuButton stringForKey:kButtonTagKey] intValue];
aButton.titleEdgeInsets = UIEdgeInsetsMake(kScreenOrigin, 2.0, kScreenOrigin, 2.0);
aButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
[aButton.titleLabel setTextAlignment:NSTextAlignmentCenter];
[aButton setTitle:[aMenuButton stringForKey:kTitleKey] forState:UIControlStateNormal];
[aButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
if ([aMenuButton objectForKey:kButtonColorKey]) {
aButton.backgroundColor = [aMenuButton objectForKey:kButtonColorKey];
}
[self.scrollViewButtonView addSubview:aButton];
anXOffset += kMenuButtonWidth;
}
}
}
self.scrollViewContentView = [UIButton buttonWithType:UIButtonTypeCustom];
self.scrollViewContentView.frame = CGRectMake(kScreenOrigin, kScreenOrigin, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
if (![Utilities isIOS7orAbove]) {
[self.scrollViewContentView addTarget:self action:#selector(cellHighlighted) forControlEvents:UIControlEventTouchDown];
[self.scrollViewContentView addTarget:self action:#selector(cellCancelHighlight) forControlEvents:UIControlEventTouchDragExit];
}
[self.scrollViewContentView addTarget:self action:#selector(selectCell:) forControlEvents:UIControlEventTouchUpInside];
self.scrollViewContentView.backgroundColor = [UIColor whiteColor];
UIImage *aBGHighlightedImage = nil;
if ([Utilities isIOS7orAbove]) {
aBGHighlightedImage = [UIImage imageNamed:kCellHighlightedImageIOS7];
} else {
aBGHighlightedImage = [UIImage imageNamed:kCellHighlightedImageIOS6];
}
[self.scrollViewContentView setBackgroundImage:[aBGHighlightedImage stretchableImageWithLeftCapWidth:11.0f topCapHeight:0] forState:UIControlStateHighlighted];
[self.scrollView addSubview:self.scrollViewContentView];
[self.scrollViewContentView addSubview:self.imageView];
[self.scrollViewContentView addSubview:self.textLabel];
[self.scrollViewContentView addSubview:self.detailTextLabel];
}
- (void)prepareForReuse {
[super prepareForReuse];
self.scrollViewContentView.enabled = YES;
[self.scrollView setContentOffset:CGPointZero animated:NO];
}
- (UITableViewCell *)tableView:(UITableView *)iTableView cellForRowAtIndexPath:(NSIndexPath *)iIndexPath {
MyTableViewCell *aCell = (MyTableViewCell *)[iTableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (!aCell) {
aCell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"CellIdentifier" andMenuButtonDetails:aMenuButtons];
}
// Set data on cell now
return aCell
}
Let me know if there is something I'm missing here, but it seems like you're adding a ton of complexity to your class for no reason. Are you familiar with UICollectionView?
Here's an example implementation (which scrolls horizontally):
#interface asdf () <UICollectionViewDataSource, UICollectionViewDelegate>
#property (strong, nonatomic) UICollectionView *collectionView;
#end
#implementation asdf
- (id)init
{
self = [super init];
if (self)
{
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.collectionViewLayout];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.view addSubview:self.collectionView];
NSString *className = NSStringFromClass([UICollectionViewCell class]);
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:className];
}
return self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.collectionView.frame = self.view.bounds;
}
- (UICollectionViewLayout *)collectionViewLayout
{
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 0;
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
return layout;
}
#pragma mark - UICollectionView
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 5;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *className = NSStringFromClass([UICollectionViewCell class]);
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:className forIndexPath:indexPath];
// This is for dequeuing
NSInteger tag = 12324;
UIView *view = [cell viewWithTag:tag];
if (view)
[view removeFromSuperview];
view = [[UIView alloc] initWithFrame:cell.bounds];
view.tag = tag;
// Add all of your subviews to the view property
[cell addSubview:view];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(collectionView.bounds.size.width, 50);
}
#end
I wrote this quickly as a sample, so it's not tailored specifically to what you're building, but this should give you a nice idea of how simple it is to implement a UICollectionView.
This answer may come across as random for what you're asking, but when possible, you should always try to use what Apple provides over what you would spend precious hours re-inventing the wheel w/ & likely experience random nuances like yours.
I'm trying to implement a table view where all rows have 2 buttons which then do something with the data at the index row they are on.
here is what I have so far:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"NotificationCell";
NotificationCell *cell = (NotificationCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[NotificationCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NotificationObject *notification = nil;
notification = [_notificationArray objectAtIndex:indexPath.row];
cell.profileImage.image = notification.profileImage;
cell.profileImage.layer.cornerRadius = cell.profileImage.frame.size.height /2;
cell.profileImage.layer.masksToBounds = YES;
cell.profileImage.layer.borderWidth = 0;
cell.detailTextView.text = notification.action;
UIButton *denyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIButton *acceptButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
//set the position of the button
denyButton.frame = CGRectMake(cell.frame.origin.x + 285, cell.frame.origin.y + 20, 23, 23);
[denyButton setBackgroundImage:[UIImage imageNamed:#"DenyRequest.png"] forState:UIControlStateNormal];
[denyButton addTarget:self action:#selector(denyButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
denyButton.backgroundColor= [UIColor clearColor];
[cell.contentView addSubview:denyButton];
acceptButton.frame = CGRectMake(cell.frame.origin.x + 240, cell.frame.origin.y + 20, 23, 23);
[acceptButton setBackgroundImage:[UIImage imageNamed:#"AcceptRequest.png"] forState:UIControlStateNormal];
[acceptButton addTarget:self action:#selector(AcceptButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
acceptButton.backgroundColor= [UIColor clearColor];
[cell.contentView addSubview:acceptButton];
return cell;
}
-(void)denyButtonPressed:(id)sender{
NSLog(#"buttonPressedDeny");
}
-(void)AcceptButtonPressed:(id)sender{
NSLog(#"buttonPressedAccept");
}
However I am not sure how to find out which index row the selected button was pressed so that I can get the relevant data.
The simplest solution is to assign a tag to each button. For example:
denyButton.tag = 1000 + indexPath.row;
Then on denyButtonPressed:
-(void)denyButtonPressed:(id)sender{
UIButton *b = (UIButton *)sender;
NSInteger row = b.tag - 1000;
NSLog(#"buttonPressedDeny: %d", row);
}
The variable row will hold the index path row where the button was pressed. The addition of 1000 is to avoid collision with other views you may already have.
Let me emphasize that this is the SIMPLEST solution but not the most friendly from a design/architecture point of view.
A more elaborate solution could be to have the buttons as part of NotificationCell, have NotificationCell be the delegate for those buttons, and create a protocol that allows your view controller to be the delegate of each NotificationCell. Then when the button is pressed, it will be handled by NotificationCell, which will pass whatever object is needed to your view controller.
For example, create the following protocol in NotificationCell.h
#protocol NotificationCellDelegate
- (void)denyActionForNotificationObject:(NotificationObject *)notificationObject;
- (void)acceptActionForNotificationObject:(NotificationObject *)notificationObject;
#end
Also add NotificationCell add a property to hold a notification and a delegate:
#property (nonatomic, strong) NotificationObject *notificationObject;
#property (nonatomic, strong) id<NotificationCellDelegate> delegate;
Create a method awakeFromNib (if you are using storyboards)
- (void)awakeFromNib {
[super awakeFromNib];
UIButton *denyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIButton *acceptButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
//set the position of the button
denyButton.frame = CGRectMake(self.contentView.frame.origin.x + 285, self.contentView.frame.origin.y + 20, 23, 23);
[denyButton setBackgroundImage:[UIImage imageNamed:#"DenyRequest.png"] forState:UIControlStateNormal];
[denyButton addTarget:self action:#selector(denyButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
denyButton.backgroundColor= [UIColor clearColor];
[self.contentView addSubview:denyButton];
acceptButton.frame = CGRectMake(self.contentView.frame.origin.x + 240, self.contentView.frame.origin.y + 20, 23, 23);
[acceptButton setBackgroundImage:[UIImage imageNamed:#"AcceptRequest.png"] forState:UIControlStateNormal];
[acceptButton addTarget:self action:#selector(AcceptButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
acceptButton.backgroundColor= [UIColor clearColor];
[cell.contentView addSubview:acceptButton];
}
Implement the selectors you declared:
- (void)denyButtonPressed:(id)sender {
if (_delegate) {
[_delegate denyActionForNotificationObject:_notificationObject];
}
}
- (void)AcceptButtonPressed:(id)sender {
if (_delegate) {
[_delegate acceptActionForNotificationObject:_notificationObject];
}
}
Then in your cellForRowAtIndexPath in your view controller add:
cell.notificationObject = notificationObject;
cell.delegate = self;
Also in your view controller, implement the protocol:
- (void)denyActionForNotificationObject:(NotificationObject *)notificationObject {
// Do something with the notification object
}
- (void)acceptActionForNotificationObject:(NotificationObject *)notificationObject {
// Do something with the notification object
}
I have not tested this in XCode, my apologies if it doesn't compile
Why not work backwards through the view hierarchy and check the button's superview, which should be the content view of the table view cell. Whose superview should be the cell?
-(void)denyButtonPressed:(id)sender{
UIButton *button = (UIButton *)sender;
UIView *contentView = button.superview;
UITableViewCell *cell = contentView.superview;
NSIndexPath * indexPath = self.tableView indexPathForCell:cell];
NSLog(#"row containing button: %d", indexPath.row);
}
I have a collection view where each cell contains 7 buttons, (created via code not storyboard).
They are sharp initially, however if I scroll up / down a few times the quality decreases.
The sharpness is restored when I change views and return.
Any ideas ?
Addit:
I am making the buttons like this, within a loop (can be 1 to 7 buttons)
- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"patientCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
Patient *aPt = [self.fetchedResultsController objectAtIndexPath:indexPath];
PatientCVCell *ptCell = (PatientCVCell *) cell;
ptCell.ptName.text = aPt.name;
ptCell.ptRoom.text = aPt.room;
ptCell.ptRx.text = aPt.diagnosis;
int xPos = 20;
NSArray *daysForRx = aPt.ofList.listDays;
// loop through to add button for each day of Rx
for (int i = 0; i < [daysForRx count]; i++) {
// get the treatment day that == postition in array
for (Treatment *t in aPt.patientRx) {
if (t.day == daysForRx[i]) {
//NSLog(#"%i", xPos);
StatusButton *testButton = [StatusButton buttonWithType:UIButtonTypeCustom];
testButton.frame = CGRectMake(xPos, 110, 28, 28);
testButton.btnTreatment = t;
// match status of the RX to the correct button
if ([t.status intValue] == NotSeen) {
[testButton setImage:[UIImage imageNamed:#"toSee"] forState:UIControlStateNormal];
testButton.linkNumber = NotSeen;
}
else if ([t.status intValue] == SeenNotCharted) {
[testButton setImage:[UIImage imageNamed:#"seenNotCharted"] forState:UIControlStateNormal];
testButton.linkNumber = SeenNotCharted;
}
else if ([t.status intValue] == SeenCharted) {
[testButton setImage:[UIImage imageNamed:#"seenCharted"] forState:UIControlStateNormal];
testButton.linkNumber = SeenCharted;
}
else if ([t.status intValue] == NotSeeing) {
[testButton setImage:[UIImage imageNamed:#"notSeeing"] forState:UIControlStateNormal];
testButton.linkNumber = NotSeeing;
}
else if ([t.status intValue] == NotSeeingDC) {
[testButton setImage:[UIImage imageNamed:#"notSeeingDischarged"] forState:UIControlStateNormal];
testButton.linkNumber = NotSeeingDC;
}
[testButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:testButton];
xPos = xPos + 36;
}
}
}
return cell;
}
The image is correct size so no need to scale the image.
Occurs in simulator and on device.
After looking more closely, the inside of the images are sharp! So this issue has to do with the transparency for my circle shape of a button within a square button!
You are dequeuing a cell, then you add your buttons to the dequeued cell.
Those buttons never get removed. When you scroll up and down cells that go off screen are put on the dequeue queue. At this time they still have the buttons, then they are dequeued and you add more buttons. You have many buttons above each other, and that's why it looks blurry and your memory footprint gets bigger.
I would add the buttons from inside the cell. Save them in a array so you can remove them later. Then I would add a method to set the number of buttons you'll need. Like this:
// header
#property (strong, nonatomic) NSMutableArray *buttons;
// implementation
- (void)setNumberOfButtons:(NSInteger)numberOfButtons withTarget:(id)target selector:(SEL)selector {
// remove existing buttons from view
[self.buttons makeObjectsPerformSelector:#selector(removeFromSuperview)];
// "save" existing buttons in a reuse queue so you don't have to alloc init them again
NSMutableArray *reuseQueue = self.buttons;
self.buttons = [NSMutableArray arrayWithCapacity:numberOfButtons];
for (NSInteger i = 0; i < numberOfButtons; i++) {
UIButton *button = [reuseQueue lastObject];
if (button) {
[reuseQueue removeLastObject];
}
else {
button = [UIButton buttonWithType:UIButtonTypeCustom];
// you should always use the same target and selector for all your cells. otherwise this won't work.
[button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
}
[self.buttons addObject:button];
button.frame = ....
// don't set up images or titles. you'll do this from the collectionView dataSource method
}
}
you would then set the number of buttons in collectionView:cellForItemAtIndexPath: and configure each button according to your needs. something along those lines:
- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Cell *cell = ... dequeue ...
Object *object = ... get from your backend ...
/* configure your cell */
if ([cell.buttons count] != object.numberOfItems) {
// no need to remove and add buttons if the item count stays the same
[cell setNumberOfButtons:object.numberOfItems withTarget:self selector:#selector(buttonPressed:)];
}
for (NSInteger i = 0; i < [object.numberOfItems count]; i++) {
UIButton *button = cell.buttons[i];
[button setImage:... forState:UIControlStateNormal];
}
}
And the action would look like this:
- (IBAction)buttonPressed:(UIButton *)sender {
UICollectionView *collectionView;
CGPoint buttonOriginInCollectionView = [sender convertPoint:CGPointZero toView:collectionView];
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:buttonOriginInCollectionView];
NSAssert(indexPath, #"can't calculate indexPath");
Cell *cell = [collectionView cellForItemAtIndexPath:indexPath];
if (cell) {
NSInteger pressedButtonIndex = [cell.buttons indexOfObject:sender];
if (pressedButtonIndex != NSNotFound) {
// do something
}
}
else {
// cell is offscreen?! why?
}
}
pretty straight forward. Get the indexPath, get the collectionViewCell, check which index the pressed button has