I have attached my sample project with github and provided the link belowI have a table view and in that tableview the cell consists of a UICollectionView. This means that every cell can scroll horizontally upto a certain limit,lets say 5.Both the tableView cell and collectionview cell have custom cell classesThe tableview cell has also a UIPageControl which will change when we will scroll the UICollectionViewCells horizontally
I managed to do this part of work but suppose I have scrolled the 2nd tableview cell's collectionview to 3rd Position and this repeats somewhat around on 9th tableview cell. The 9th tableview cell also has the same data. But I havent set anything yet on 9th. So this means the problem is of reusability and data in getting incorrect while scrolling.
My Code so far is
//ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
Implementation Class
//ViewController.m
#import "ViewController.h"
#import "MyCollectionViewCell.h"
#import "MyTableViewCell.h"
#interface ViewController ()
{
MyTableViewCell* tableViewCell;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark TableView Delegates
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section{
return 10;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
tableViewCell=(MyTableViewCell*)[tableView dequeueReusableCellWithIdentifier:#"MyTableViewCell"];
if(tableViewCell==nil)
{
tableViewCell=[[MyTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyTableViewCell"];
}
UICollectionViewFlowLayout *flowLayout =
[[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[tableViewCell.collectionView setPagingEnabled:YES];
[tableViewCell.collectionView setCollectionViewLayout:flowLayout];
[tableViewCell.collectionView setBackgroundColor:[UIColor whiteColor]];
tableViewCell.pageControl.tag=indexPath.row;
tableViewCell.collectionView.tag=indexPath.row;
NSLog(#"Index path row %ld",indexPath.row);
[tableViewCell setSelectionStyle:UITableViewCellSelectionStyleNone];
tableViewCell.path=indexPath;
return tableViewCell;
}
#pragma mark CollectionView Delegates
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 5;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MyCollectionViewCell* cell=(MyCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"MyCollectionViewCell" forIndexPath:indexPath];
if(cell==nil)
{
cell=[[MyCollectionViewCell alloc]initWithFrame:CGRectMake(0, 0, collectionView.frame.size.width, collectionView.frame.size.height)];
}
[cell.myLabel setText:[NSString stringWithFormat:#"%ld",(long)indexPath.row]];
return cell;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return collectionView.frame.size;
}
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout: (UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
return UIEdgeInsetsMake(0, 0, 0, 0);
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
if ([scrollView isKindOfClass:[UICollectionView class]])
{
UICollectionView *mainCollection = (UICollectionView *) scrollView;
NSIndexPath *myIP = [NSIndexPath indexPathForRow:mainCollection.tag inSection:0];
MyTableViewCell *cell = (MyTableViewCell *)[self.tableView cellForRowAtIndexPath:myIP];
CGRect visibleRect = (CGRect){.origin = mainCollection.contentOffset, .size = mainCollection.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [mainCollection indexPathForItemAtPoint:visiblePoint];
NSLog(#"visibleIndexPath %ld",(long)visibleIndexPath.row);
[cell.pageControl setCurrentPage:visibleIndexPath.row];
}
}
#end
Cells classes
//MyTableViewCell.h
#import <UIKit/UIKit.h>
#interface MyTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
#property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
#property (strong, nonatomic) NSIndexPath * path;
#end
MyCollectionViewCell.h
//MyCollectionViewCell.h
#import <UIKit/UIKit.h>
#interface MyCollectionViewCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#end
View is Something like
My concern is that whenever I make any change lets say on cell 1 on table viewcell and scroll the collection in it to lets say 2nd index, then this is re repeated whenever i scroll the complete table
NOTE: I have kept number of cells of table to 10 to see the repeated impact.
The Github link of my sample project is https://github.com/RajanMaheshwari/TableAndCollection
First of all:
[collectionView dequeueReusableCellWithReuseIdentifier:#"MyCollectionViewCell" forIndexPath:indexPath]
always returns a view, so you don't need that:
if(cell==nil)
{
cell=[[MyCollectionViewCell alloc]initWithFrame:CGRectMake(0, 0, collectionView.frame.size.width, collectionView.frame.size.height)];
}
since it's not gonna happen.
And the real reason for you is that you have only one cell for all UITableView...
Where the idea of keeping tableCell as property comes from ?
MyTableViewCell* tableViewCell;
You need to create a cell instance for each indexPath separately, right now you have one instance which is displayed several times, that's why changing collection view page on one of them is affecting other rows - since it's the same object (view).
After you remove that problem, you need to remember that elements will be reused - which means your first row instance, you be reused again on 5th row, after it dissapears from the screen, so after you dequeue the elements, you need to set all variables to this row.
You cannot keep your variables inside this row, because it will be reused, so even though you have 100 rows, you will around 5-6 instances (depends on row height) that will be reused across whole table.
You need to keep important variables, necessary to render every row, outside of the views and configure views based on those.
In your case you should keep page index of pageControl for every row - use NSDictionary for that and keep a NSNumber for every indexPath in your UITableView.
Whenever page is changing, update the value in this NSDictionary (defaults to zero).
When you create a cell with collection view, set proper value to pageControl based on what you have in NSDictionary for this indexPath
Related
I created a table view that has collection view inside its cells with this tutorial Creating a Scrolling Filmstrip Within a UITableView but I want to achieve a banner kind of feature that has centred paging and scrolls automatically to each cell item. I enabled page scrolling but didn't work. How do I do this? I currently have a UIView in the table view cell that serves as the data source for the collection view. Here is the code for the UIView subclass.
#interface ContainerCellView () <UICollectionViewDataSource, UICollectionViewDelegate>
#property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
#property (strong, nonatomic) NSArray *collectionData;
#end
#implementation ContainerCellView
#pragma mark - Getter/Setter ovverides
- (void)setCollectionData:(NSArray *)collectionData {
_collectionData = collectionData;
[_collectionView setContentOffset:CGPointZero animated:YES];
[_collectionView reloadData];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.collectionData count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ArticleCollectionViewCell";
BannersCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *cellData = [self.collectionData objectAtIndex:indexPath.row];
cell.articleTitle.text = [cellData objectForKey:#"title"];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *cellData = [self.collectionData objectAtIndex:indexPath.row];
[[NSNotificationCenter defaultCenter] postNotificationName:#"didSelectItemFromCollectionView" object:cellData];
}
#end
You are possibly looking for property for collectionView called isPagingEnabled which comes from UIScrollView, otherwise, you should create your cell big enough to achieve this pretty nice effect. However, you can relate here, if you are looking for paging by cells click here Hope this may help you
I often faces this issue when developing tableview custom cell.
Here is problem, I have a tableview and it has lots of customized cell (a UIImageView and UILabel) When user tap any of this cell pushes new UIViewController and user filling some data and tapped the "Save" viewcontroller push back with delegation method.
In this delegate method I inspect tapped cell and change that tint color (like selected state but I'm only changing custom imageview tint color). So this changes correctly but when I'm scrolling any vertical direction tint color disappear. Below pictures and code for figuring out correctly.
When pop to view controller from delegate method (works correctly)
When scrolling vertical direction tin
// Custom cell
#interface CustomCell : UITableViewCell
#property(strong, nonatomic) UIImageView *imageView;
#property(strong, nonatomic) UILabel *titleLabel;
#end
// Custom Cell implementation nothing special here.
// UIViewController delegate method when pop back
// I'm filling specific color
#interface UIViewController
#property (strong,nonatomic) CustomCell *myCustomCell;
#end
#implementation UIViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
_myCustomCell = (CustomCell *)[self.tableView dequeueReusableCellWithIdentifier:#"CustomCell" forIndexPath:indexPath];
...
}
- (void)userTappedBackButton {
_myCustomCell.imageView.image = [cell.customImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
_myCustomCell.imageView.tintColor = [UIColor colorWithRed:0.27 green:0.58 blue:0.98 alpha:1];
}
#end
The problem you have is that you are saving a reference to the UITableViewCell but the cells are being reused.
You need to save the information about the cell to be highlighted in another manner, that cannot be influenced by the cells being reused. I would suggest by using the indexPath.
Something like the following should work:
#property (nonatomic, strong) NSIndexPath *lastSelectedIndexPath;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
CustomCell *cell = (CustomCell *)[self.tableView dequeueReusableCellWithIdentifier:#"CustomCell" forIndexPath:indexPath];
if([indexPath isEqual:self.lastSelectedIndexPath]) {
cell.imageView.image = [cell.customImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
cell.imageView.tintColor = [UIColor colorWithRed:0.27 green:0.58 blue:0.98 alpha:1];
}
...
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Save the selected indexPath
self.selectedIndexPath = indexPath;
}
- (void)userTappedBackButton {
// Reload the row that needs to be updated with the new tint color
[tableView reloadRowsAtIndexPaths:#[self.selectedIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
Let me know if it worked out.
Keep track of the index path of the tapped cell when it is selected rather than the cell itself, which is reused as you scroll. Apply the selected styling in cellForRow when you're presenting the cell for the matching "selected" index path, in addition to when you return back to the view
Update: adding code to clarify
In your custom cell, provide simple ways to enable/disable the tint:
#interface CustomCell : UITableViewCell
#property(strong, nonatomic) UIImageView *imageView;
#property(strong, nonatomic) UILabel *titleLabel;
- (void)enableLastSelectedHighlight;
- (void)disableLastSelectedHighlight;
#end
Implementation:
#implementation CustomCell
- (void)prepareForReuse
{
[super prepareForReuse];
// Reset prior to being reused
[self disableLastSelectedHighlight];
}
- (void)enableLastSelectedHighlight
{
self.imageView.image = [cell.customImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.imageView.tintColor = [UIColor colorWithRed:0.27 green:0.58 blue:0.98 alpha:1];
}
- (void)disableLastSelectedHighlight;
{
self.imageView.image = [cell.customImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}
#end
In your TableViewController.m file, keep track of the selection, either via didSelectRowAtIndexPath, or your existing custom delegate userTappedBackButton. The implementation of the will be the same:
#interface MyTableViewController ()
#property (nonatomic, strong) NSIndexPath *lastSelectedCellIndexPath;
#end
#implementation MyTableViewController
// Your existing implementation
// ...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Update our reference to the tinted row
[self setLastSelectedCellIndexPath:indexPath];
// Un-tint any currently tinted cells
[self.tableView.visibleCells makeObjectsPerformSelector:#selector(disableLastSelectedHighlight)];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Get your cell
CustomCell *cell = (CustomCell *)[self.tableView dequeueReusableCellWithIdentifier:#"CustomCell" forIndexPath:indexPath];
if (indexPath == self.lastSelectedCellIndexPath) {
// This cell should be tinted
[cell enableLastSelectedHighlight];
}
// The rest of your cell setup...
}
#end
I am new in ios development .I have searched many tutorials that are using framework for data-grid with License key.I want to show data like this table at given link . How i can use uicollection view to display tabular data like in link ?
In code in gridview.h file is :
import
#interface GridViewCell : UITableViewCell
#property (nonatomic, strong) UIButton *column1;
#property (nonatomic, strong) UIButton *column2;
#property (nonatomic, strong) UIButton *column3;
#end
The code in gridview.m file is :
//
// GridViewCell.m
// SQLite3DBSample
//
// Created by Dezine House on 22/12/2014.
// Copyright (c) 2014 Bilal ARSLAN. All rights reserved.
//
#define CELL_WIDTH 100
#define CELL_HEIGHT 80
#import "GridViewCell.h"
#implementation GridViewCell
#synthesize column1, column2, column3;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
column1 = [[UIButton alloc] initWithFrame:CGRectMake(5, 5, CELL_WIDTH, CELL_HEIGHT)];
[self addSubview:column1];
column2 = [[UIButton alloc] initWithFrame:CGRectMake(CELL_WIDTH+ 10, 5, CELL_WIDTH, CELL_HEIGHT)];
[self addSubview:column2];
column3 = [[UIButton alloc] initWithFrame:CGRectMake(CELL_WIDTH + CELL_WIDTH + 15, 5, CELL_WIDTH, CELL_HEIGHT)];
[self addSubview:column3];
}
return self;
}
- (void)awakeFromNib
{
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
GridViewCell *cell = (GridViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[GridViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell.column1 setBackgroundColor:[UIColor blackColor]];
[cell.column2 setBackgroundColor:[UIColor blackColor]];
[cell.column3 setBackgroundColor:[UIColor blackColor]];
return cell;
}
#end
For creating the grid of n X m use the collectionView delegates
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return n;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return m;
}
Then for creating them of specific size use the delegate method of CollectionView which returns the layout for each cell in collectionView
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
//for bigger cell
if (indexPath.row == 0) {
return CGSizeMake(120, 44);
}
//for smaller ones
else{
return CGSizeMake(44, 44);
}
}
Hope you know how to use collectionView in ios
I've been working on doing something like this and while I'm not finished tinkering with it, it isn't that hard to do. It may be cleanest to subclass the UICollectionViewCell and the UICollectionViewFlowLayout, but I've not found it necessary as yet. My biggest problem thus far is getting cell borders to look like I want them to. I envision that it may be necessary to subclass one or both of these but thus far it isn't requiring that much code in my VC so I've not done it yet.
In addition to the usual UICollectionView data source/delegate, you want to add UICollectionViewDelegateFlowLayout. In my case, I made each section in my data correspond with a row in the table and each "row" in the indexPath to coincide with a column in the table. It seems to work. Then, implement the following method to give you the size of the cell for each column in a section (looking at the indexPath.row value to determine which column you're working with):
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
In your cellForItemAtIndexPath for my application it was simple enough to compute the column number as follows (my table has six columns):
NSInteger col = indexPath.row % 6;
So, col==0 is the first column, col==5 is the sixth column. Then, create a label to put in the cell:
UILabel *label = [[UILabel alloc] initWithFrame:cell.bounds;
Fill in the label as required and add it as a subview of the cell's content view.
I have a good deal of tweaking to do, but it is reasonably close after just a couple hours of looking around.
I'm just beginning IOS development and am wondering if anybody could help me figure out how to get the cell details that are being clicked.
I have a cell like this:
#import <UIKit/UIKit.h>
#interface ICICell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#property (weak, nonatomic)IBOutlet ICICell *myCell;
#property (weak, nonatomic) IBOutlet UIImageView *myGallery;
#end
in the view controller I am populating the cells like this:
-(UICollectionViewCell * ) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
ICICell * aCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"myCell" forIndexPath:indexPath];
aCell.myLabel.text = self.dataArray[indexPath.row];
UIImage *img;
long row = [indexPath row];
img = [UIImage imageNamed:self.iciImages[row]];
aCell.myGallery.image = img;
return aCell;
}
I have found the didDeselectItemAtIndexPath method, but is there a method didSelectItemAtIndexPath?
I am trying to get the label text for a selected cell. Bit confused why there is a didDeselect and no didSelect? Thanks in advance.
Linda Keating,
There are both methods available as you are expecting..have a reference from below
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
/* Here you can do any code for Selected item at indexpath.*/
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
}
Thanks.
Of course You can navigate into Detail Screen of Collection View cell.
Just use didSelectItemAtIndexPath method.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
VIPRoomDetailController *enterIntoRoomDetail = [[VIPRoomDetailController alloc]initWithNibName:#"VIPRoomDetailController" bundle:nil];
[self.navigationController pushViewController:enterIntoRoomDetail animated:YES];
}
Also Import Detail controller in your collection View class In my case it is VIPRoomDetailController
Very simple situation, multiple rows and only one row should have the checkmark at a time. User selects row X, row X gets checkmark, checkmark removed from previously selected row. But how to animate the change? (Fade in fade out).
I thought maybe this would work:
[UIView animateWithDuration:1.0 animations:^{
cell.accessoryType = UITableViewCellAccessoryNone;
cell.accessoryType = UITableViewCellAccessoryCheckmark;
previous.accessoryType = UITableViewCellAccessoryCheckmark;
previous.accessoryType = UITableViewCellAccessoryNone;
}];
and also
[tableView reloadRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
The first did nothing, the second deleted both of the cells referred by the NSIndexPath's in the paths array. I also tried wrapping reloadRowsAtIndexPaths in [tableView beginUpdates/endUpdates].
UPDATE:
Calling reloadRowsAtIndexPath on the incoming indexPath (trivial implementation below) is doing the same thing, the row "goes blank".
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
The table is a static table, I have properties declared and synthesized for each cell, cellForRowAtIndexPath returns the corresponding cell for each row...
.h
#property (strong, nonatomic) IBOutlet UITableViewCell *cellNever;
#property (strong, nonatomic) IBOutlet UITableViewCell *cell030;
#property (strong, nonatomic) IBOutlet UITableViewCell *cell100;
.m
#synthesize cellNever;
#synthesize cell030;
#synthesize cell100;
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [cells objectAtIndex:indexPath.row];
}
- (void) viewDidLoad {
cells = [NSArray arrayWithObjects:cellNever, cell030, cell100, cell130, cell200, cell230, cell300, cell400, cell500, nil];
}
Many thanks.