Incorrect UITableViewCell gets highlighed when dequeued - ios

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.

Related

Duplicate of actions UIView with UITableView

I have table in main view. Next I added view to above table view with height 100 points, then I have first row with 100 points height. Next I check scrollView contentOffset to recalculate position of my added view. When I scroll my table view all fine, my view is duplicate position with my first cell in table view.
But I have problem is:
When I want to scroll from my view (finger in a view) and scroll down, table view is no interaction with my gestures. Yes, that normal. If I set user interaction to NO, all work fine. But I have some buttons in this view and when I disabled user interaction I can't have actions with my subviews in this view.
How I can scroll and tap simultaneously/together without user interaction or something else method. Thx.
All of code:
#import "ViewController.h"
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
{
UIView *someView;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:tableView];
someView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 100)];
someView.backgroundColor = [UIColor redColor];
[self.view addSubview:someView];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
if (indexPath.row == 0) return 100;
else return 44;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
if (indexPath.row == 0) cell.backgroundColor = [UIColor greenColor];
}
return cell;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
someView.center = CGPointMake(someView.center.x, -scrollView.contentOffset.y+50);
}
Try to add button on main view
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:tableView];
someView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 100)];
someView.backgroundColor = [UIColor redColor];
[self.view addSubview:someView];
UIButton *someBotton = [UIButton buttonWithType:UIButtonTypeCustom];
// button initialisation
...
[self.view addSubview:someBotton];
}
In this case table will not interact only below button
Second way is create subclass for someView and override method pointInside:
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event{
for(UIView *subview in self.subviews){
if([subview pointInside:point withEvent:event]){
return YES;
}
}
return NO;
}

UITableViewCell element no longer accessible via [cell.contentView viewWithTag] when scrolled down

I am trying to create expand/collapse cell. On every cell, it has subview of UIView for border bottom. If expanded, the border should also go to bottom of the cell. It is working fine on initial load of the cells, however, when I scroll down, the border is no longer going to the bottom.
I am adjusting the border originY via taskOptionsExpand method. That method is getting the border view via [cell.contentView viewWithTag:2].
Code below:
#import "HomeViewController.h"
#interface HomeViewController ()<UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) UITableView *tableView;
#property (strong, nonatomic) NSIndexPath *selectedIndexPath;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.selectedIndexPath = nil;
[self.view addSubview:self.tableView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (UITableView *)tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc] init];
_tableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[_tableView addSubview:self.tableRefreshControl];
}
return _tableView;
}
# pragma mark - table view delegates
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 100;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.selectedIndexPath isEqual:indexPath]) {
return 80;
}else{
return 50;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// text view
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 0, self.view.frame.size.width-20, 50)];
view1.backgroundColor = [UIColor clearColor];
view1.tag = 0;
UILabel *title = [[UILabel alloc] initWithFrame:view1.frame];
title.text = #"Lorem ipsum";
title.textColor = [UIColor grayColor];
[view1 addSubview:title];
// options view
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
view2.backgroundColor = [UIColor orangeColor];
view2.tag = 1;
// border bottom
CGRect frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
if ([self.selectedIndexPath isEqual:indexPath]) {
frame.origin.y = 79; //expand
} else {
}
UIView *border = [[UIView alloc] initWithFrame:frame];
border.backgroundColor = [UIColor blueColor];
border.tag = 2;
cell.clipsToBounds = YES;
[cell.contentView addSubview:view1];
[cell.contentView addSubview:view2];
[cell.contentView addSubview:border];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.selectedIndexPath isEqual:indexPath]) {
[self taskOptionsExpand:NO indexPath:indexPath];
self.selectedIndexPath = nil;
} else {
[self taskOptionsExpand:YES indexPath:indexPath];
[self taskOptionsExpand:NO indexPath:self.selectedIndexPath];
self.selectedIndexPath = indexPath;
}
[tableView beginUpdates];
[tableView endUpdates];
}
- (void) taskOptionsExpand:(BOOL) expand indexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIView *border = [cell.contentView viewWithTag:2];
NSLog(#"border: %#", border);
if (expand) {
border.frame = CGRectMake(20, 79, self.view.frame.size.width-40, 1);
}else{
border.frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
}
}
#end
When scrolling the table view, the cell is dequeued to get reusable cell and as reusable cell will already have viewWithTag 2 (since it was added when the cell being reused was created) so adding another view with tag 2 will create the issues like above. To overcome the above issue you should remove the earlier added viewWithTag 2 and than re-add the view with the same tag, like-
// remove (previously added) border if it exists
UIView *border = nil;
border = [cell.contentView viewWithTag:2];
if(border)
[border removeFromSuperview];
// again create border view
Update your cellForRowAtIndexPath: method as
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// text view
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 0, self.view.frame.size.width-20, 50)];
view1.backgroundColor = [UIColor clearColor];
view1.tag = 0;
UILabel *title = [[UILabel alloc] initWithFrame:view1.frame];
title.text = #"Lorem ipsum";
title.textColor = [UIColor grayColor];
[view1 addSubview:title];
// options view
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
view2.backgroundColor = [UIColor orangeColor];
view2.tag = 1;
// border bottom
CGRect frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
if ([self.selectedIndexPath isEqual:indexPath]) {
frame.origin.y = 79; //expand
} else {
}
UIView *border = nil;
border = [cell.contentView viewWithTag:2];
if(border)
[border removeFromSuperview];
border = [[UIView alloc] initWithFrame:frame];
border.backgroundColor = [UIColor blueColor];
border.tag = 2;
cell.clipsToBounds = YES;
[cell.contentView addSubview:view1];
[cell.contentView addSubview:view2];
[cell.contentView addSubview:border];
// release your allocated instances after adding them
[view1 release];
[view2 release];
[border release];
return cell;
}
Also you should release your subviews which you have allocated like view1, view2, border after adding them to the cell's content view as
[view1 release];
[view2 release];
[border release];
This will make there retain count from 2 to 1 and when the cell is deallocated than they will be removed from there parent which is cell.
Table views re-use cells. When a cell is scrolled offscreen it is added to a queue, and will be re-used for the next cell to be scrolled onscreen. That means your configuration code in tableView:cellForRowAtIndexPath: method will be run again on the same cell multiple times at different indexPaths. Since you're just adding your border view every time your configuration code runs, they will stack one on top of the other. When you call viewWithTag: you will only get one of the multiple views you've added.
The correct approach is to create a custom cell (subclass of UITableViewCell) with properties for each subview that needs to be configured (IBOutlets if using xibs/storyboard), so that they can be accessed.

UITableView dislocates automatically

Issue
I am encountering a weird issue with UITableView. Following is the link to video that explains the issue I'm facing. (turned on slow animation)
https://dl.dropboxusercontent.com/u/97646145/Issue/UITableView_Issue.swf
The table is dislocating only when the controller is visited for the first time. Later on, the issue isn't popping.
Code
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBarHidden = FALSE;
[self.navigationController.topViewController.navigationItem setHidesBackButton:YES];
[self.view setBackgroundColor:[UIColor clearColor]];
_extrasTable = [[UITableView alloc] initWithFrame:CGRectMake(50, 44, CGRectGetWidth(self.view.frame) - 75, CGRectGetHeight(self.view.frame) - 44) style:UITableViewStylePlain];
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[_extrasTable setBackgroundColor:[UIColor clearColor]];
_extrasTable.rowHeight = CGRectGetHeight(_extrasTable.bounds) / 5;
_extrasTable.separatorStyle = UITableViewCellSeparatorStyleNone;
_extrasTable.dataSource = self;
_extrasTable.delegate = self;
[self.view addSubview:_extrasTable];];
}
#pragma mark - UITableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [EXTRAS count];
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
cell.textLabel.font = [UIFont fontWithName:NobileMedium size:15];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.text = EXTRAS[indexPath.row];
[cell setBackgroundColor:[UIColor clearColor]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
#pragma mark - Visible cells
- (NSArray*)visibleCells
{
return [_extrasTable visibleCells];
}
EDIT
I'm adding this TableView' controller as a subview to another View controller. The code for the same as follows:
for (UIView *view in [self.view subviews]) {
[view removeFromSuperview];
}
[self.navigationController setNavigationBarHidden:NO];
[self.navigationController.topViewController.navigationItem setHidesBackButton:YES];
[currentController removeFromParentViewController];//currentController - instance of UIViewController
MMExtrasVC *controller = [[MMExtrasVC alloc] init];//the controller that contains table view
controller.view.frame = [[self view] bounds];
[self.view addSubview:controller.view];
[self addChildViewController:controller];
[controller didMoveToParentViewController:self];
currentController = controller;
Implement ViewDidLayoutSubView and set Frame there for your table.
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
_extrasTable setFrame:CGRectMake(x, y, width, height)];
}
I think the problem is caused by the navigation bar.
Firstly, I would try removing below from viewDidLoad:
self.navigationController.navigationBarHidden = FALSE;
Secondly, I would remove the tick (if there's one) from:
Extend Edges, Under Top Bars
from the Attributes Inspector of the view controller.

iOS How to create undefined UIControl in custom UITableViewCell

I'm trying to write a prototype UITableViewCell with title and undefined UIControl that we are setting in cellForRowAtIndexPath:
Now I have implementation for cell:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.contentView addSubview:self.titleLabel];
[self.contentView addSubview:self.control];
}
return self;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
[_titleLabel setBackgroundColor:[UIColor clearColor]];
_titleLabel.numberOfLines = 2;
[_titleLabel setFont:[UIFont fontWithName:#"Georgia-Italic" size:15]];
[_titleLabel setTextColor:RGBColor(51, 102, 153)];
[_titleLabel setTextColor:[UIColor darkGrayColor]];
}
return _titleLabel;
}
- (UIControl *)control{
if (!_control) {
_control = [[UIControl alloc] init];
[_control setBackgroundColor:[UIColor whiteColor]];
}
return _control;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect contentRect = [[self contentView] bounds];
self.titleLabel.frame = CGRectMake(10, 5, 85, contentRect.size.height-10);
self.control.frame = CGRectMake(100, 5, contentRect.size.width-105, contentRect.size.height-10);
[self.contentView bringSubviewToFront:self.control];
[self bringSubviewToFront: self.control];
}
And implemented cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellAddOrder";
ICControlCell *cell = (ICControlCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ICControlCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
[cell setAccessoryType:UITableViewCellAccessoryNone];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
NSObject *cellContent = [self.cellList objectAtIndex:indexPath.row];
cell.titleLabel.text = ICLocalized([cellContent valueForKey:#"name"]);
switch ([[cellContent valueForKey:#"control"] intValue]) {
case 0: {
UITextField *textField = [[UITextField alloc] init];
textField.placeholder = ICLocalized([[cellContent valueForKey:#"name"] stringByAppendingString:#"_placeholder"]);
textField.delegate = self;
textField.returnKeyType = UIReturnKeyNext;
textField.autocapitalizationType = UITextAutocapitalizationTypeWords;
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.text = [cellContent valueForKey:#"data"];
textField.tag = indexPath.row;
cell.control = textField;
}
break;
case 1:
case 2:
case 3: {
UISwitch *switchControl = [[UISwitch alloc] init];
[switchControl setOn:[[cellContent valueForKey:#"data"] boolValue]];
[switchControl addTarget:self
action:#selector(switchStateChanged:)
forControlEvents:UIControlEventValueChanged];
switchControl.tag = indexPath.row;
cell.control = switchControl;
}
break;
default:
break;
}
return cell;
}
But when I'm trying to test that controller controls for cell are not displaying, just title labels..
How can I handle that problem? Please help me
you should use different cell identifiers for different items for example if you have UITextField and UISwitch then you should use two identifiers because you are reusing the cell.So it should be the same type of cell to be reused.
Doc says:
You cannot use the UIControl class directly to instantiate controls.
So, you can just declare the UIControl variable the cell prototype class but set it to nil there. All the control related operations should be done from inside the delegate, because that is the place where you exactly know which class to use. So,
Don't initialize control in cell class snippet from 'control' property:
- (UIControl *)control{
return _control;
}
Cell's constructor should also not call addSubview for control. So,
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.contentView addSubview:self.titleLabel];
}
return self;
}
Add background color setting in cell's layoutSubviews here:
- (void)layoutSubviews {
...
if (cell.control) {
[cell.control setBackgroundColor:[UIColor whiteColor]];
self.control.frame = CGRectMake(100, 5, contentRect.size.width-105, contentRect.size.height-10);
[self.contentView bringSubviewToFront:self.control];
[self bringSubviewToFront: self.control];
}
}
Add subview in the delegate's cellforrow method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
cell.control = textField;
[cell.contentView addSubview:cell.control];
...
}

subclass uitableviewcell and override layoutsubviews

I need to make cell selectionBackgroundView not on full width in plain UItableView. For this I made UItableViewCell subclass and override layoutsubviews method
- (void)layoutSubviews
{
[super layoutSubviews];
self.selectedBackgroundView.frame = CGRectMake(self.frame.origin.x + 10.0f, self.frame.origin.y, self.frame.size.width - 20.0f, self.frame.size.height);
}
My cellForRowAtIndexPath method looks like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [NSString stringWithFormat: #"CELL %i %i", indexPath.section, indexPath.row];
GroupedTableCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if(cell == nil)
{
cell = [[GroupedTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
UIView *cellBgView = [[UIView alloc] init];
cellBgView.frame = CGRectMake(10, 0, 300, 80);
[cellBgView setBackgroundColor:[UIColor colorWithRed:242 / 255.0 green:242 / 255.0 blue:242 / 255.0 alpha:1.0]];
[cell.contentView addSubview:cellBgView];
}
[cell setBackgroundColor:[UIColor clearColor]];
UIView *selectionView = [[UIView alloc] init];
[selectionView setBackgroundColor:[UIColor colorWithRed:181 / 255.0 green:211 / 255.0 blue:53 / 255.0 alpha:1.0]];
selectionView.frame = CGRectMake(10, 0, 300, 80);
cell.selectedBackgroundView = selectionView;
return cell;
}
But only for first row selectedView works correct. For other rows I have selectedView with clear color. Please, help me.
All I need was to set frame with numbers.
- (void)layoutSubviews
{
[super layoutSubviews];
self.selectedBackgroundView.frame = CGRectMake(10.0f, 0, 300, 80);
}
Instead add the background in the subclassed cell itself,
do like this it is an example how you can manage the selection and deselection state in the cell change it to your requirements
//in your subclassed cell
#import "GroupedTableCell.h"
#implementation GroupedTableCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
//add the background view hear only, changes the frame in the layoutsubviews
UIView *cellBgView = [[UIView alloc] init];
[cellBgView setTag:12345];//using tag to access in the layoutsubviews
[self addSubview:cellBgView];//hear u added the background view
}
return self;
}
//manage the cell selection and deselection state hear
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
// Configure the view for the selected state
[super setSelected:selected animated:animated];
UIView *cellBgView = [self viewWithTag:12345];
if(selected)
{
[cellBgView setBackgroundColor:[UIColor colorWithRed:242 / 255.0 green:242 / 255.0 blue:242 / 255.0
alpha:1.0]]; //your selected background color
}
else
{
[cellBgView setBackgroundColor:[UIColor clearColor]]; //your deselected background color
}
}
//setting the frames of views within the cell
- (void)layoutSubviews
{
[super layoutSubviews];
UIView *cellBgView = [self viewWithTag:12345];
cellBgView.frame = CGRectMake(10, 0, 300, 80);//always set the frame in layoutSubviews
}
in your controller just do like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GroupedTableCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil)
{
cell = [[GroupedTableCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
return cell;
}
Hope this helps u :)

Resources