UITableView dislocates automatically - ios

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.

Related

Why UITableView sectionFooterView is floating at the bottom of screen,rather than attached to the bottom of the section group?

When I build applications using XCode9.1 encountered such a strange problem.
I am trying to run in the simulator(iOS 11 and iOS 10),but the result is the same.
Here is the some code.
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *mainTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
mainTableView.dataSource = self;
mainTableView.delegate = self;
mainTableView.rowHeight = 52.f;
[mainTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
[self.view addSubview:mainTableView];
UIView *headerView = [[UIView alloc] init];
headerView.backgroundColor = [UIColor orangeColor];
headerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 270);
mainTableView.tableHeaderView = headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 15.f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 15.f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSString *text = [NSString stringWithFormat:#"Header section==%ld",section];
return [self createViewWithTitle:text];
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
NSString *text = [NSString stringWithFormat:#"Footer section==%ld",section];
return [self createViewWithTitle:text];
}
- (UIView *)createViewWithTitle:(NSString *)title {
UIView *view = [UIView new];
view.backgroundColor = [UIColor yellowColor];
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(0, 0, 200, 15);
label.text = title;
[view addSubview:label];
return view;
}
It's working as intended, both header and footer section views are attached to top and bottom of table view when you scrolling inside respective sections.
If you keep the footer as section footer. Then it will behave the way you have mentioned which is not a bug. In case if you want the footer to be attached at the bottom of the screen, you can use tableFooterView property of tableview and assign as footer view to it.
[self.tableView registerNib:[UINib nibWithNibName:#"FooterView" bundle:nil] forHeaderFooterViewReuseIdentifier:#"FooterView"];
FooterView *footerView = [[[NSBundle mainBundle] loadNibNamed:#"FooterView" owner:self options:nil] firstObject];
footerView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
// Assigning the footer view to table footer view property
self.infoTableView.tableFooterView = footerView;

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.

Incorrect UITableViewCell gets highlighed when dequeued

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.

label display text not well when use [cell setNeedsDisplay]

I have a UICollectionView to display username of user, and when I add new or modify a user -> I will update into database -> then get all data again(from the data base). and then reload UICollectionView. All I want is: if I modify a user at index 3 then after reload this user is still stay at index 3(and if I add a new user this user will display at the end position). So that I use setNeedsDisplay. But I have a problem that my label display text not well when I use setNeedsDisplay,as below:
when I comment out [cell setNeedsDisplay]; then the text of label is display well. But the index of each user is not display right as I want.Here is my code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
if(!dbManager)
dbManager = [DBManager sharedInstant];
UIBarButtonItem *btnAdd = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(showAdd)];
self.navigationItem.rightBarButtonItem = btnAdd;
UIBarButtonItem *btnFilter = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:#selector(showFilter)];
self.navigationItem.leftBarButtonItem = btnFilter;
[[DBManager sharedInstant] setDelegate:self];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
[self.collectionView setBackgroundColor:[UIColor clearColor]];
[self.collectionView registerClass:[UserCollectionItemView class] forCellWithReuseIdentifier:#"UserCollectionItemView"];
cells = [[NSMutableArray alloc] init];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (!dbManager.synchronized) {
[datasource removeAllObjects];
datasource = nil;
if (contactType == ContactTypeCustomer)
[dbManager requestData:kDbCustomers predicate:nil target:self];
else if (contactType == ContactTypeSuppplier)
[dbManager requestData:kDbSuppliers predicate:nil target:self];
}
[self setLayout];
}
and for collectionview:
#pragma mark
#pragma UICollectionDelegate
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)cv numberOfItemsInSection:(NSInteger)section
{
return [datasource count];
}
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
[cells addObject:cell];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UserCollectionItemView *cell;
// if([cells count])
// {
// cell = [cells lastObject];
// [cells removeLastObject];
// }
// else
cell = [cv dequeueReusableCellWithReuseIdentifier:#"UserCollectionItemView" forIndexPath:indexPath];
if (contactType == ContactTypeCustomer) {
POSCustomer *customer = [datasource objectAtIndex:indexPath.item];
cell.displayname = customer.CompanyName;
}
else if (contactType == ContactTypeSuppplier){
POSSupplier *supplier = [datasource objectAtIndex:indexPath.item];
cell.displayname = supplier.CompanyName;
}
cell.backgroundColor = [UIColor clearColor];
[cell setNeedsDisplay];
return cell;
}
- (void)collectionView:(UICollectionView *)cv didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
dbManager.synchronized = YES;
if (contactType == ContactTypeCustomer) {
POSCustomer *customers = [datasource objectAtIndex:indexPath.item];
[self showEditCustomer:customers];
}
else if (contactType == ContactTypeSuppplier){
POSSupplier *suppliers = [datasource objectAtIndex:indexPath.item];
[self showEditSupplier:suppliers];
}
}
-(void)showEditCustomer:(POSCustomer *)customer{
ContactFormViewController *form = [[ContactFormViewController alloc] initWithNibName:#"ContactFormViewController" bundle:nil];
[form setContactType:ContactTypeCustomer];
form.posCustomer = customer;
[self.navigationController pushViewController:form animated:YES];
}
-(void)showEditSupplier:(POSSupplier *)supplier{
ContactFormViewController *form = [[ContactFormViewController alloc] initWithNibName:#"ContactFormViewController" bundle:nil];
[form setContactType:ContactTypeSuppplier];
form.posSupplier = supplier;
[self.navigationController pushViewController:form animated:YES];
}
#pragma mark
#pragma DBDelegate
- (void)requestDataCompleted:(NSMutableArray *)results
{
datasource = results;
[self.collectionView reloadData];
}
and here is for custom collectionview:
#synthesize displayname;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGRect frame = self.contentView.frame;
UIView *view = [[UIView alloc] initWithFrame:frame];
view.layer.borderWidth = 0.5;
[view.layer setBorderColor:[UIColor colorWithRed:0.3 green:0.6 blue:0.2 alpha:1].CGColor];
view.layer.cornerRadius = 5;
[view setBackgroundColor:[UIColor colorWithRed:0.3 green:0.6 blue:0.2 alpha:0.3]];
UIImageView *avatarView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 10, frame.size.width, rect.size.width)];
[avatarView setBackgroundColor:[UIColor clearColor]];
[avatarView setImage:[UIImage imageNamed:#"users_icon"]];
[view addSubview:avatarView];
UILabel *displayName = [[UILabel alloc] initWithFrame:CGRectMake(3, frame.size.width - 10, rect.size.width - 6, 50)];
displayName.numberOfLines = 2;
displayName.text = displayname;
[displayName setFont:[UIFont fontWithName:#"Arial" size:12]];
displayName.textAlignment = NSTextAlignmentCenter;
[displayName setTextColor:[UIColor colorWithRed:0.3 green:0.6 blue:0.2 alpha:1]];
[view addSubview:displayName];
[self.contentView addSubview:view];
}
Thanks for any helps.
Because of this line [self.contentView addSubview:view];, It've added multiple times because setNeedDisplay will call drawRect: every time. To avoid this, try below..
UIView *view = [[UIView alloc] initWithFrame:frame];
view.tag = SomeTagValue;
.
.
.
.
UIView *preView = [self.contentView viewWithTag:SomeTagValue];
[preView removeFromSuperview];
[self.contentView addSubview:view];

Resources