Xcode Custom Cell With IBOutlet Objects and Not - ios

I created a Custom Cell:
#import <UIKit/UIKit.h>
#import "SevenSwitch.h"
#interface cellaMain : UITableViewCell {
SevenSwitch *subscribed;
}
#property (nonatomic, retain) IBOutlet UIImageView *imageMain;
#property (nonatomic, retain) IBOutlet UILabel *titleMain;
#property (nonatomic, retain) SevenSwitch *subscribed;
#end
The UIImage and the Label are added to cell by the storyboard but the sevenswitch is added in the method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
With this code:
/* Switch Inside the cell */
cella.subscribed = [[SevenSwitch alloc] initWithFrame:CGRectMake(cella.frame.size.width-60, cella.frame.size.height / 2 - 12, 50, 25)];
cella.subscribed.offImage = [UIImage imageNamed:#"off.png"];
cella.subscribed.onImage = [UIImage imageNamed:#"on.png"];
cella.subscribed.thumbTintColor = [UIColor colorWithRed:(230/255.0) green:(230/255.0) blue:(230/255.0) alpha:1];
cella.subscribed.activeColor = [UIColor colorWithRed:(204/255.0) green:(204/255.0) blue:(204/255.0) alpha:1];
cella.subscribed.inactiveColor = [UIColor colorWithRed:(204/255.0) green:(204/255.0) blue:(204/255.0) alpha:1];
cella.subscribed.onTintColor = [UIColor colorWithRed:(204/255.0) green:(204/255.0) blue:(204/255.0) alpha:1];
cella.subscribed.isRounded = NO;
cella.subscribed.tag = [[tempCat objectForKey:#"Id"] intValue];
[cella.subscribed addTarget:self action:#selector(changeSingleCategory:) forControlEvents:UIControlEventValueChanged];
if ([[tempCat objectForKey:#"Subscribed"] isEqualToString:#"Y"]) {
cella.subscribed.on = YES;
} else {
cella.subscribed.on = NO;
}
[cella.contentView addSubview:cella.subscribed];
/* End Switch Editing */
The problem is that the scroll lags a lot.
How can I do to add the SevenSwitch object in the cellaMain.m and let the image and the label be added by the Storyboard?
Or maybe is it better add to my cell view all the objects (Label, Image and SeveSwitch) in my cellaMain.m file?

Adding to matt's answer. When you scroll UITableView the function below get called everytime, and you are initializing the switch again and again which has already been created and that is actually causing lag in scroll.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
There is a very simple solution for that, follow these steps
Put a UISwitch in your custom cell xib and follow the instructions in the images below
Create an IBOutlet of the UISwitch in the .h class of your CustomCell, remember to import 'SevenSwitch.h'. When you will create an IBOutlet for the UISwitch, your code should look like below
#property(nonatomic, strong) IBOutlet SevenSwitch *subscribed;
Now your code in cellForRowAtIndexPath should look like below
/* Switch Inside the cell */
cella.subscribed.offImage = [UIImage imageNamed:#"off.png"];
cella.subscribed.onImage = [UIImage imageNamed:#"on.png"];
cella.subscribed.thumbTintColor = [UIColor colorWithRed:(230/255.0) green:(230/255.0) blue:(230/255.0) alpha:1];
cella.subscribed.activeColor = [UIColor colorWithRed:(204/255.0) green:(204/255.0) blue:(204/255.0) alpha:1];
cella.subscribed.inactiveColor = [UIColor colorWithRed:(204/255.0) green:(204/255.0) blue:(204/255.0) alpha:1];
cella.subscribed.onTintColor = [UIColor colorWithRed:(204/255.0) green:(204/255.0) blue:(204/255.0) alpha:1];
cella.subscribed.isRounded = NO;
cella.subscribed.tag = [[tempCat objectForKey:#"Id"] intValue];
[cella.subscribed addTarget:self action:#selector(changeSingleCategory:) forControlEvents:UIControlEventValueChanged];
if ([[tempCat objectForKey:#"Subscribed"] isEqualToString:#"Y"]) {
cella.subscribed.on = YES;
} else {
cella.subscribed.on = NO;
}
/* End Switch Editing */
You will notice I have removed the first and the last line of your code, so now your switch is getting initialized from xib only and only once, and in the function your are just changing the properties.
Hope it helps.

The problem is that you are saying
addSubview:cella.subscribed
for every cell. But cells are reused. So you are adding this subview even if it has already been added. You need to make all of that code conditional; don't add the subview if it is already there.

Related

iOS - UIViewController as Popup with dynamic height

I have a Popup-View which contains two labels, a tableview and button. I created a ViewController as in Display UIViewController as Popup in iPhone described.
My special requirement is now, that the tableview is not necessary in all cases, so I tried to hide it and expected a reduced height of the Popup-View. But I always get the same height. I also tried to use a UIStackView, but the height of the view wasn't changed in case of hiding the tableview.
I also need to have the view in center of the display in both cases of height.
enter image description here
#interface AuthorizationMessageViewController ()
#property (weak, nonatomic) IBOutlet UIView *messageView;
#property (weak, nonatomic) IBOutlet UILabel *titelLabel;
#property (weak, nonatomic) IBOutlet UILabel *detailsLabel;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (weak, nonatomic) IBOutlet UIButton *okButton;
- (IBAction)okButtonTouchUp:(id)sender;
#end
#implementation AuthorizationMessageViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.messageView.layer.cornerRadius = 5;
self.messageView.layer.masksToBounds = YES;
self.messageView.backgroundColor = COLOR_BACKGROUND_WHITE;
self.messageView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.backgroundColor = COLOR_BACKGROUND_WHITE;
self.titelLabel.text = WHLocalizedString(#"EventHeaderAuthorization", nil);
[self setupView];
}
- (void)setupView
{
NSString *ns_messageText;
ns_messageText = #"test";
if (YES)
{
ns_messageText = #"Hide"
[self.tableView setHidden:YES];
}
else
{
ns_messageText = #"No Hide"
[self.tableView setHidden:NO];
}
self.detailsLabel.text = ns_messageText;
self.detailsLabel.textColor = COLOR_TEXT_GREY_KEY;
self.detailsLabel.numberOfLines = 0;
[self.detailsLabel sizeToFit];
}
#pragma mark - Table view data source
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 7;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 21;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"testCell"];
UILabel *weekDayLabel = (UILabel *)[cell viewWithTag:10];
weekDayLabel.text = #"weekday";
weekDayLabel.textColor = COLOR_TEXT_GREY_KEY;
weekDayLabel.font = FONT_LIGHT_SIZE_15;
UILabel *testLabel = (UILabel *)[cell viewWithTag:11];
testLabel = #"testLabel"
testLabel = COLOR_TEXT_GREY_KEY;
testLabel = FONT_LIGHT_SIZE_15;
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
I hope that someone has a solution or an idea for that.
Imagine the following UI
a centered UIView that contains a UIButton and UITableView , you need to hook height constraint of the table and do this inside the popup if you want to hide it
#IBOutlet weak var heightTblCon:NSLayoutConstraint!
//
self.heightTblCon.constant = show ? 300 : 0
self.view.layoutIfNeeded()
BTW i changed color of background view for clarification purposes that should be transparent for modals
Try calling sizeToFit() on Popup-View after hiding the tableView:
popupView.sizeToFit()
Try to Adjust the Height of your view using the NSLayoutConstraint. Create an outlet for the same and manage height programatically. For example:
myConstraintOutlet.constant = 10
myTableView.layoutIfNeeded()
Here is the link for further assistant.
Regarding your second query to have the pop up always in centre you can either do it using Autolayout or programatically define the centre of your pop up.
myView.center = CGPoint(x: superView.center.x, y: superView.center.y)
Hope that helps.

Custom implementation of UICollectionViewCell makes cells invisible

For the sake of context I'm developing a calendar app with 3 different views. Day, Month and Year View.
In order to display the days I've decided to use a UICollectionView with a custom implementation of UICollectionViewCell (so that I'm able to customize the aspect of each cell).
On the init of my NSObject CtrlCalendar class I register 3 cell Classes like this:
//Used for the yearView
[self.grid registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:#"monthCell"];
//Used for the monthView
[self.grid registerClass:[CollectionViewCell class] forC ellWithReuseIdentifier:#"dayCell"];
//Used for the dayView
[self.grid registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:#"hourCell"];
Than, on collectionView:collectionView cellForItemAtIndexPath:indexPath I'm doing as follows:
CollectionViewCell *cell = nil;
if ([self.currentDisplayType isEqualToString:#"monthView"]) {
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"dayCell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor grayColor];
self.month = [self.displayingViews get:indexPath.section];
if (indexPath.row + 1 >= self.month.firstWeekDay && indexPath.row + 1 < self.month.numberOfDays + (self.month.firstWeekDay)) {
NSDateComponents *tempDay = [self.calendar components:NSCalendarUnitDay fromDate:self.month.date];
cell.date = [self.dateHelper addToDate:self.month.date days:(int)(tempDay.day + indexPath.row - self.month.firstWeekDay)];
cell.cellTitle.text = [NSString stringWithFormat:#"%i", (int)(tempDay.day + indexPath.row + 1 - self.month.firstWeekDay)];
cell.cellTitle.textColor = [UIColor blackColor];
if ([[self.dateHelper addToDate:self.month.date days:(indexPath.row + 1 - self.month.firstWeekDay)] isEqualToDate:self.today]) {
cell.cellTitle.textColor = [UIColor redColor];
}
cell.userInteractionEnabled = YES;
cell.separator.hidden = NO;
cell.contentView.hidden = NO;
} else {
cell.userInteractionEnabled = NO;
}
And finally here is my implementation of CollectionViewCell:
#interface CollectionViewCell ()
#property (nonatomic, retain) UILabel *cellTitle;
#property (nonatomic, retain) NSString *titleText;
#property (nonatomic, retain) UILabel *separator;
#property (nonatomic, retain) NSDate *date;
#end
#implementation CollectionViewCell
#synthesize cellTitle;
#synthesize titleText;
#synthesize separator;
#synthesize date;
- (void)dealloc {
[cellTitle release];
[titleText release];
[separator release];
[date release];
[super dealloc];
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.cellTitle = [[[UILabel alloc] initWithFrame:self.bounds] autorelease];
self.cellTitle.textColor = [UIColor blackColor];
self.cellTitle.textAlignment = NSTextAlignmentCenter;
self.separator = [[[UILabel alloc] initWithFrame:CGRectMake(0, (self.frame.size.height - 0.25), self.frame.size.width, 0.5)] autorelease];
self.separator.backgroundColor = [UIColor lightGrayColor];
[self.contentView addSubview:self.separator];
[self.contentView addSubview:self.cellTitle];
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
self.cellTitle.text = nil;
self.separator.hidden = YES;
[self.cellTitle setTextColor:[UIColor blackColor]];
//the presence of this line is explained after the edit bellow
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
}
#end
The first time I run the app, the Month View is configured as expected, but as soon as it performs the dequeue, the cells turn blank.
After some debugging I found that the CollectionViewCell's cellTitle property is correctly set. The problem resides in the fact that after the dequeue the labels are hidden for some reason.
I know this is long question, but if you can help in anyway or know someone who can help please let me know!
Thanks a lot!
For clarification of what the problem is I'm adding some screens
Before scrolling:
After scrolling:
UPDATE 1
As #Alessandro Chiarotto answered, the
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)]
does make the cells empty. The caveat here is that I need that selector to remove from the cells some UILabels I'm adding to the yearView.
My yearView UICollection has 12 cells (one for each month). Each cell than has the number of UILabels as the days in each month. I'm adding this UILabels from the collectionView:collectionView cellForItemAtIndexPath:indexPath like this:
for (int d = 1; d < self.month.numberOfDays; d++) {
UILabel *day = [[[UILabel alloc] initWithFrame:dayRect] autorelease];
day.text = currentDay;
[cell addSubview:day];
}
If i don't perform the selector in prepareForReuse, after scrolling the view I have all the day labels in duplicate in each month cell.
If you scroll the collection then prepareForReuse will be called. In prepareForReuse you have the following call:
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
this will remove all the subviews of the cell (UILabel and so on).
At this point your cell will "white"...
I've found the problem. As #Alessandro said in his answer the [self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)]; was removing everything from the cell, therefore making it blank.
That would be it if it weren't for another aspect of the problem.
As I said in my question Update, I need that selector in order to remove some UILabels that are being added in the yearView. Those labels are the days in each month cell.
Solution:
I added a UIView property to the CollectionViewCell that has a frame equal to the cell's bounds. I than add the UILabels to this view and on the prepareForReuse I perform the removeFromSuperView on the self.labelsView.subviews. It works like a charm.
The correct implementation of prepareForReuse would be:
- (void)prepareForReuse {
[super prepareForReuse];
self.cellTitle.text = nil;
self.separator.hidden = YES;
[self.cellTitle setTextColor:[UIColor blackColor]];
[self.labelsView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
}

Why can't I change my table footer's text color?

When the user gives improper input within a textfield cell of a UITableView, I want to change the footer to be a warning with colored text, describing the error. I've gotten it to work perfectly aside from the coloring. What of my code below am I doing wrong, such that the text is not colored?
- (UIView *) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
switch (section)
{
// Inspection confirms this case is entered when needed.
case SECTION_VALIDATABLE_FORM:
{
UITableViewHeaderFooterView *warningFooter = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:K_FOOTER_WARNING];
UIColor *color = [MyColors uiColorForKey:K_COLOR_TEXT_ERROR]; // inspection confirms this is the UIColor equivalent of #BB2222
[warningFooter.textLabel setTextColor:color];
return warningFooter;
}
// other sections...
}
return nil;
}
UITableViewHeaderFooterView uses a custom UILabel subclass and apparently, the color can't be changed.
You should subclass UITableViewHeaderFooterView and add your own label manually.
#interface XXTableViewHeaderFooterView : UITableViewHeaderFooterView
#property (nonatomic, strong) UILabel *myLabel;
#end
#implementation XXTableViewHeaderFooterView
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;
{
self = [super initWithReuseIdentifier:reuseIdentifier];
if (self) {
_myLabel = [[UILabel alloc] initWithFrame:...];
_myLabel.textColor = ...;
[self.contentView addSubview:_myLabel];
}
return self;
}
#end

Delegate method is being called but doesn't execute properly

I'm having a problem with one of my delegate methods. I have a collectionViewController to which I have added a UILongPressGestureRecognizer, which is calling a delegate method fadeOutLabels in my UICollectionViewCell. I can confirm the delegate method being called by a NSLog statement NSLog(#"fadeOutLabels was called");. But the other code inside that function isn't being executed. I'm quite sure I'm missing something completely obvious, but I can't seem to figure it out myself. Code as follows:
FOFPhotoCell.h
#protocol FOFPhotoCellDelegate <NSObject>
#required
-(void)fadeOutLabels;
#end
#interface FOFPhotoCell : UICollectionViewCell {
id delegate;
}
#property (nonatomic, weak) id<FOFPhotoCellDelegate> delegate;
#property (nonatomic) UIImageView *imageView;
#property (nonatomic) NSDictionary *photo;
#property (nonatomic) NSArray *fetchPhotos;
#property (nonatomic) UILabel *titleLabel;
#end
FOFPhotoCell.m
#implementation FOFPhotoCell
#synthesize delegate = _delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CGFloat widthFromBounds = self.contentView.bounds.size.width;
self.imageView = [[UIImageView alloc] init];
[self.contentView insertSubview:self.imageView atIndex:0];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, widthFromBounds, 60)];
self.titleLabel = titleLabel;
self.titleLabel.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.3];
self.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
self.titleLabel.textColor = [UIColor whiteColor];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.contentView insertSubview:self.titleLabel atIndex:1];
}
return self;
}
-(void)fadeOutLabels
{
NSLog(#"fadeOutLabels was called");
[UIView animateWithDuration:1.0
delay:0.0 /* do not add a delay because we will use performSelector. */
options:UIViewAnimationOptionCurveEaseIn
animations:^ {
self.titleLabel.alpha = 0.0;
}
completion:^(BOOL finished) {
[self.titleLabel removeFromSuperview];
}];
}
FOFPhotosViewController.h
#import <UIKit/UIKit.h>
#import "FOFPhotoCell.h"
#interface FOFPhotosViewController : UICollectionViewController <FOFPhotoCellDelegate>
#end
FOFPhotosViewController.m
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
FOFPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"photo" forIndexPath:indexPath];
NSArray *photosArray = [self.dishes valueForKeyPath:#"avatar_url"];
NSArray *nameArray = [self.dishes valueForKeyPath:#"name"];
// NSLog(#"photoURL %#", _responseDictionary);
cell.backgroundColor = [UIColor lightGrayColor];
[cell.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://xx.yy.zz.qq:4000%#",[photosArray objectAtIndex: indexPath.row]]]];
cell.titleLabel.text = [NSString stringWithFormat:#"%#", [nameArray objectAtIndex:indexPath.row]];
UILongPressGestureRecognizer *tapAndHold = [[UILongPressGestureRecognizer alloc] initWithTarget:cell action:#selector(fadeOutLabels)];
tapAndHold.minimumPressDuration = 0.5;
[self.collectionView addGestureRecognizer:tapAndHold];
[self.collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
return cell;
}
I would really appreciate if some one could help me with this issue.
Thanks in advance
Chris
I believe your problem comes from the LongPressGestureRecognizer that should be instantiated in your custom cell and not in your view controller.
Basically, if you have a hundred cell how the long press gesture recognizer is supposed to know which cell you have pressed and which label to fade out.
You can try this instead, in your custom cell :
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UILongPressGestureRecognizer *tapAndHold = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(fadeOutLabels)];
tapAndHold.minimumPressDuration = 0.5;
[self addGestureRecognizer:tapAndHold];
....
}
}
And of course remove those lines in the view controller.

UIButton not responding to click event in UITableViewCell

there is this dark sorcery in ios is preventing my button being clicked. if i don't add button to the uitableviewcell, and i click the button, the event is triggered.
but if the button is in uitableviewcell, it won't get triggered, it seems table
i have sample code ready, if you guys can help me, please just create a simple single-view application in xcode, and just paste the following code
//GRDViewController.h
#import <UIKit/UIKit.h>
#interface GRDViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UIView* container;
#property (nonatomic, strong) UIButton* button;
#property (nonatomic, strong) UITableView* tableView;
#property (nonatomic, strong) NSArray* arr;
#end
//GRDViewController.m
#import "GRDViewController.h"
#implementation GRDViewController
#synthesize button, container, arr, tableView;
- (void)_btnTapped {
NSLog(#"TAPPED");
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
[self.button addTarget:self action:#selector(_btnTapped) forControlEvents:UIControlEventTouchUpInside];
[self.button setTitle:#"CLICK ME" forState:UIControlStateNormal];
self.arr = [[NSArray alloc] initWithObjects:#"123", #"456", #"678", nil];
self.container = [[UIView alloc]initWithFrame:self.button.frame];
[self.container addSubview:self.button];
[self.view addSubview:self.container];
//[self.view addSubview:self.button];
self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 100, 400, 400)];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
self.tableView.backgroundColor = [UIColor redColor];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"coolcell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
//cell.accessoryType = UITableViewCellAccessoryNone;
UIButton * btn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
[btn addTarget:self action:#selector(_btnTapped) forControlEvents:UIControlStateNormal];
[btn setTitle:[self.arr objectAtIndex:[indexPath row]] forState:UIControlStateNormal];
[cell.contentView addSubview:btn];
}
return cell;
}
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
return [self.arr count];
}
#end
please help
i feel this case should be common in ios, but nobody has solution for this???
edit: when click on the button it prints NSLOG msg in the xcode console...so make sure...u r looking at the results there...
you have not given any control event to button .Change it to UIControlEventTouchUpInside from UIControlStateNormal
Instead of using UIControlStateNormal for ControlEvents use UIControlEventTouchUpInside like this
[btn addTarget:self action:#selector(_btnTapped) forControlEvents:UIControlEventTouchUpInside];
Try doing this:
[btn.titleLabel setUserInteractionEnabled: NO];

Resources