CKComponentKit CollectionView issue - ios

I am currently experimenting with ComponentKit and I am having an issue. I want to use the CKCollectionView I created on a main view. When I had the CKCollectionView to its container in my MainView(which contains a ScrollView) I am having 2 issues. The first one, if I manually create the frame of the CollectionView, here what it gives me.(Blue square is the "UICollectionViewControllerWrapperView")
But, what I really want to do is set the frame using Masonry and constraints, allowing me to set the frame equal to its container (the yellow square). But when I do that, it FILLS the entire Blue rectangle height with empty cells, like in the picture below:
So it seems like my actual cells (or Components) have a size of 647 and they are causing problems.But at this point I am lost and was wondering if anybody had a similar issue before :).
Here is my code:
The actual component that creates the cell:
#implementation SSOUpcomingAuctionComponent
+ (instancetype)newWithProduct:(Product *)product {
SSOProductHeaderComponent *head = [SSOProductHeaderComponent newWithTitle:product.time];
SSOProductPictureComponent *body = [SSOProductPictureComponent newWithImage:product.image];
SSOProductShareComponent *footer = [SSOProductShareComponent newWithPrice:product.price];
return [super newWithComponent:[CKInsetComponent newWithInsets:UIEdgeInsetsMake(0, 0, 0, 0)
component:[CKStackLayoutComponent newWithView:{
[UIView class], {
{ #selector(setBackgroundColor:), [UIColor whiteColor] }
, { CKComponentViewAttribute::LayerAttribute(#selector(setCornerRadius:)), #6.0 }
, { #selector(setClipsToBounds:), #YES }
}
} size:{}
style:{
.alignItems = CKStackLayoutAlignItemsCenter, .direction = CKStackLayoutDirectionVertical,
.spacing = 2
} children:{{
head,
},
{body},
{footer}}]]];
}
#pragma mark - ProviderMethod
#end
The CollectionViewController:
#import "UpcomingAuctionViewController.h"
#import "SSOUpcomingAuctionComponent.h"
#import <ComponentKit/ComponentKit.h>
#import "Product.h"
#import "ProductPages.h"
#import "ProductModelController.h"
#import <ChameleonFramework/Chameleon.h>
#import "Masonry.h"
#interface UpcomingAuctionViewController () <CKComponentProvider, UICollectionViewDelegateFlowLayout>
#end
#implementation UpcomingAuctionViewController {
CKCollectionViewDataSource *_dataSource;
CKComponentFlexibleSizeRangeProvider *_sizeRangeProvider;
ProductModelController *_productModelController;
}
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout {
if (self = [super initWithCollectionViewLayout:layout]) {
_sizeRangeProvider = [CKComponentFlexibleSizeRangeProvider providerWithFlexibility:CKComponentSizeRangeFlexibleWidth];
_productModelController = [[ProductModelController alloc] init];
self.automaticallyAdjustsScrollViewInsets = NO;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.collectionView.backgroundColor = [UIColor flatWhiteColorDark];
// [self.collectionView setFrame:CGRectMake(0, 0, 320, 180)];
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
[self.collectionView setScrollEnabled:YES];
self.collectionView.delegate = self;
// Creates and sets our dataSource to our CKCollectionViewDataSource, THE MAIN ACTOR/INFRASTRUCTURE that takes our MODEL, creates a COMPONENT STACKS then
// transforms it into a VIEW HIERARCHY.
_dataSource = [[CKCollectionViewDataSource alloc] initWithCollectionView:self.collectionView
supplementaryViewDataSource:nil
componentProvider:[self class]
context:nil
cellConfigurationFunction:nil];
// The following block of code adds a section at 0 and two items at 0 and 1.
CKArrayControllerSections sections;
// insert section 0
sections.insert(0);
[_dataSource enqueueChangeset:{
sections, {}
} constrainedSize:{}];
[self enqueueProductPages:[_productModelController fetchNewUpcomingProductsWithCount:14]];
}
- (void)enqueueProductPages:(ProductPages *)productPage {
NSArray *products = productPage.products;
NSInteger position = productPage.position;
CKArrayControllerInputItems items;
for (NSInteger i = 0; i < products.count; i++) {
items.insert([NSIndexPath indexPathForRow:position + i inSection:0], products[i]);
}
[_dataSource enqueueChangeset:{
{}
, items
} constrainedSize:[_sizeRangeProvider sizeRangeForBoundingSize:self.collectionView.bounds.size]];
}
#pragma mark - CKComponentProvider
// Method that our componentProvider class NEED to implement
+ (CKComponent *)componentForModel:(Product *)product context:(Product *)context {
return [SSOUpcomingAuctionComponent newWithProduct:product];
}
#pragma mark - UICollectionViewDelegateFlowlayout
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return [_dataSource sizeForItemAtIndexPath:indexPath];
}
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
[_dataSource announceWillAppearForItemInCell:cell];
}
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
[_dataSource announceDidDisappearForItemInCell:cell];
}
And finally the mainViewController:
/**
* Initialize upcoming auctions container controller
*/
- (void)initializeUpcomingAuctionsContainerView {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setMinimumInteritemSpacing:0];
[flowLayout setMinimumLineSpacing:10];
flowLayout.sectionInset = UIEdgeInsetsMake(0, 15, 0, 0);
self.upcomingAuctionsVC = [[UpcomingAuctionViewController alloc] initWithCollectionViewLayout:flowLayout];
[self addChildViewController:self.upcomingAuctionsVC];
[self.bottomView addSubview:self.upcomingAuctionsVC.view];
[self.upcomingAuctionsVC didMoveToParentViewController:self];
}
#end
Thanks for the help everyone and have a great day.

Related

How to locate the layout across view hierarchy?

I have a menuView in a list view controller. The menuView added on the UITableViewCell when a more button in the cell being taped.
I achieved the effect with singleton.
#implementation ProductsOperationMenu
static ProductsOperationMenu *_instance;
+ (instancetype)sharedInstance{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] initWithFrame:CGRectZero];
});
return _instance;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setup];
}
return self;
}
ZBMyProductsCell.m
#implementation ZBMyProductsCell
- (void)awakeFromNib
{
[super awakeFromNib];
_operationMenu = [[ProductsOperationMenu alloc] initWithFrame: CGRectZero];
}
- (IBAction)operationButtonClick:(UIButton *)sender {
if ([self.contentView.subviews containsObject:_operationMenu]) {
_operationMenu.hidden = ![_operationMenu isHidden];
} else{
[self.contentView addSubview:_operationMenu];
_operationMenu.hidden = NO;
}
[_operationMenu mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(205);
make.height.mas_equalTo(60);
make.bottom.mas_equalTo(self.operationButton).offset(0);
make.right.mas_equalTo(self.operationButton.mas_left).offset(-10);
}];
}
Without Singleton, it became this:
So the question come.
I want to put the menuView on the controller's view, because it is unique or hidden, which used to belong to the cell.
How to convert layout of the more button selected to the controller's view?
How to use the methods to calculate?
- convertPoint:toView:
- convertPoint:fromView:
......
I did it in a simple way. Here is the code:
- (void)clickOperationButtonOfProductsCell:(ZBMyProductsCell *)myProductsCell{
NSUInteger * operationIndex = [self.myProductsTableView.visibleCells indexOfObject:myProductsCell];
CGFloat originY = operationIndex.row * 110 + 50 + 40;
CGRect originFrame = CGRectMake(KScreenWidth - 55, originY, 0, 60);
CGRect finalFrame = CGRectMake(KScreenWidth - 260, originY, 205, 60);
self.operationMenuView.frame = originFrame;
[UIView animateWithDuration: 0.5 delay: 0 options: UIViewAnimationOptionCurveEaseIn animations:^{
self.operationMenuView.frame = finalFrame;
} completion:^(BOOL finished) { }];
}
How to achieve it more adaptively?
Maybe you can try it like this:
// here is your cell where the more button belongs to
#interface ZBMyProductsCell: UITableViewCell
#property (nonatomic, copy) void(^moreAction)(ZBMyProductsCell *cell);
#end
#implementation ZBMyProductsCell
- (void)_moreButtonClicked:(UIButton *)sender {
!self.moreAction ?: self.moreAction(self);
}
#end
// here is your view controller where your table view belongs to
// this is a `UITableViewDataSource` delegate method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ZBMyProductsCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ZBMyProductsCell" forIndexPath:indexPath];
// Configure the cell...
cell.moreAction = ^(ZBMyProductsCell *cell) {
CGRect rect = [tableView rectForRowAtIndexPath:indexPath];
// write your own code to show/hide the menu
};
return cell;
}
Create a variable in each cell model called cellIndexpath and in cellForRow init it
cell.cellIndexpath = indexpath
have a look of UIPopoverPresnetationController and see if it can do the job. It should be available on iPhone. Putting menu view on the controller’viewwill cause issue when you scroll the table view.
use
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:self.detaiLabel.frame inView:self];

IOS UICollectionView Cell with different instance of cell class

I am trying to create custom cell for UiCollectionView where I need to update each cell from background.
So I have created custom class for each cell named Cell_Obj and updating the cell content from the Cell_Obj itself using a timer.
The below code add an image on cell and increment a counter in each 2 second and display it on new cell label.
On each time when I add new cell using a button on a viewcotroller the cell updating but every cell getting the same value on the label. It suppose to have different counter value as each cell is different instance of Cell_Obj but the counter value and labelTxt(the cell number) has the same value when each time the timer triggered.
ViewController.h
#import <UIKit/UIKit.h>
#import "Cell_Obj.h"
#interface ViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegate>
#property (weak, nonatomic) IBOutlet UICollectionView *collection;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController (){
NSMutableArray *GridArray;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.collection setDelegate:self];
[self.collection setDataSource:self];
// Do any additional setup after loading the view, typically from a nib.
GridArray = [[NSMutableArray alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return GridArray.count;
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (Cell_Obj *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
Cell_Obj *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
// cell.label.text = #"123";
/*cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"AppIcon.png",indexPath.row]];*/
return cell;
}
- (void)addImage
{
Cell_Obj *cell = [[Cell_Obj alloc] init];
// cell.label.text = #"123";
//cell.label.text = [NSString stringWithFormat:#"%d",[dvrGridArray count]-1];
NSString * txt = [NSString stringWithFormat:#"%d",[GridArray count]];
[cell updateTextLabelName: txt];
[GridArray addObject:cell];
[_collection insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:[GridArray count]-1 inSection:0]]];
/* NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];
[arrayWithIndexPaths addObject:cell];
[self.collection insertItemsAtIndexPaths:arrayWithIndexPaths];*/
}
- (IBAction)addClicked:(id)sender {
[self addImage];
}
- (IBAction)changeImage:(id)sender {
// DVR_Obj *cell = [dvrGridArray objectAtIndex:0];
// [cell changeImage ];
// [_collection reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
Cell_Obj *cell = [_collection cellForItemAtIndexPath:indexPath];
[cell changeImage ];
}
#pragma mark Collection view layout things
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
CGSize mElementSize = CGSizeMake((screenWidth/4)-2, (screenHeight/4)-2);
return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 1.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 1.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(1,1,1,1); // top, left, bottom, right
}
#end
Cell_Obj.h
#import <UIKit/UIKit.h>
#interface Cell_Obj : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (weak, nonatomic) IBOutlet UILabel *label;
- (void)changeImage;
- (void)updateTextLabelName:(NSString*)str;
#end
Cell_Obj.m
#import "Cell_Obj.h"
static NSString *labelTxt ;// = [[NSString alloc] init];
static int counter;
#implementation Cell_Obj{
}
+ (void)initialize {
if (self == [Cell_Obj class]) {
labelTxt = [[NSString alloc] init];
counter=0;
}
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)awakeFromNib {
_imageView.image = [UIImage imageNamed:#"flower1.png"];
_label.text = labelTxt;
[NSTimer scheduledTimerWithTimeInterval:2.0f
target:self
selector:#selector(updateImage)
userInfo:nil
repeats:YES];
}
- (void)updateImage
{
_imageView.image = [UIImage imageNamed:#"AppIcon.png"];
counter++;
NSString * txt = [NSString stringWithFormat:#"%#-%d",labelTxt,counter];
_label.text = txt;
}
- (void)updateTextLabelName :(NSString*)str
{
labelTxt = str;
}
#end
Your each cell is not new cell. Cell_Obj *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath]; this statement reuses your cell with identifier "Cell". To create new cell each time , don't pass indexPath, pass nil instead.

Imageview is not showing up in a programmatically created collectionview

I am having a hard time figuring out why cell.imageview property doesn't show me image below. UIImage is not nil, cells are created, if I assign a background to cell, it is displayed which proves I am creating collectionview and my cells correctly. I programmatically create my collectionview and don't use any IB or interface builder. I have done this lots of times before, but I am really scratching my head with this one.
Thanks in advance.
#interface MainViewController : UIViewController
#property(strong, nonatomic) UICollectionView *collectionView;
#end
#interface MainViewController ()<
UICollectionViewDataSource, UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate>
#property(nonatomic, strong) MHTransitionShowDetail *interactivePushTransition;
#property(nonatomic) CGPoint lastPoint;
#property(nonatomic) CGFloat startScale;
#property(strong, nonatomic) NSMutableArray *carImages;
#end
#implementation MainViewController
- (instancetype)init {
self = [super init];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_carImages = [#[
#"chevy_small",
#"mini_small",
#"rover_small",
#"smart_small",
#"highlander_small",
#"venza_small",
#"volvo_small",
#"vw_small",
#"ford_small",
#"nissan_small"
] mutableCopy];
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UICollectionViewFlowLayout *layout =
[[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(106, 106);
layout.minimumLineSpacing = 1.0;
layout.minimumInteritemSpacing = 1.0;
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame
collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
self.collectionView.alwaysBounceVertical = YES;
[self.collectionView setContentInset:UIEdgeInsetsMake(20, 10, 10, 10)];
[self.collectionView registerClass:[IKGCollectionViewCell class]
forCellWithReuseIdentifier:#"myCell"];
self.collectionView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.collectionView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma CollectionView & FlowLayout methods
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(120, 120);
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section {
return self.carImages.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
IKGCollectionViewCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:#"myCell"
forIndexPath:indexPath];
long row = [indexPath row];
UIImage *image = [UIImage imageNamed:self.carImages[row]];
cell.imageView.userInteractionEnabled = YES;
cell.imageView.image = image;
NSLog(#"cell.image view %#", image);
// [self makeCell:(IKGCollectionViewCell *)cell atIndexPath:indexPath];
return cell;
}
}
#end
#interface IKGCollectionViewCell : UICollectionViewCell
#property(nonatomic, strong) UIImageView *imageView;
#end
#implementation IKGCollectionViewCell
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.imageView = [[UIImageView alloc] initWithFrame:self.bounds];
NSLog(#"self.bounds is %#", NSStringFromCGRect(self.bounds));
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = self.contentView.bounds;
}
#end
You missed to add the cell's imageView as a it's subview.
So in cell's initWithFrame
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.imageView = [[UIImageView alloc] initWithFrame:self.bounds];
//Add imageView as subview
[self addSubview:self.imageView];
NSLog(#"self.bounds is %#", NSStringFromCGRect(self.bounds));
}
return self;
}

Creating a UICollectionView within a subview

I have a view controller (that sits in a tab bar controller), but need to add a collection view to that controller. I see lots of tutorials on google but they all seem to point to creating a UICollectionViewController and starting in viewDidLoad. But how do I do it in a subview?
I have my view controller.m file like so:
- (void) createView // called from viewDidLoad
{
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 64.0, screenWidth, screenHeight)];
[scrollView.layer addGradient];
ACollectionView *theview = [[ACollectionView alloc] init];
[self.view addSubview:theview];
}
Next I started a UICollectionView subclass called ACollectionView.h
#interface ACollectionView : UICollectionView
#end
And the .m file is this:
#import "ACollectionView.h"
#implementation BestCollectionView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
Where do I start the collection view, in the initWithFrame?
I am trying to follow this:
Creating a UICollectionView programmatically
Is my paradigm correct?
#property (nonatomic, strong) UICollectionView *collectionView;
- (void)viewDidLoad
{
[super viewDidLoad];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.yourSubview.frame collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.yourSubview addSubview:self.collectionView];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 50;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 100);
}

UIScrollview within UITableViewCell and maintaining scrollview page

I have a UIScrollView within a UITableViewCell for being able to scroll through images within a cell. However, as a cell is reused the scroll position/content is reloaded and therefore the cell doesn't remember what scroll position (page) it was on when it comes into view again.
What's the best way to have a scroll view within a UITableView cell and have it maintain position as it comes back into view. The AirBnB app (https://itunes.apple.com/us/app/airbnb/id401626263?mt=8) seems to have accomplished this for example.
You need to keep track of your scroll views' content offset in a property. In the example below, I do this with a mutable dictionary. In cellForRowAtIndexPath:, I give the scroll view a tag and set the controller as the delegate. In the scroll view delegate method, scrollViewDidEndDecelerating:, the scroll view's content offset is set as the object for the key corresponding to the scroll view's tag. In cellForRowAtIndexPath:, I check for whether the indexPath.row (converted to an NSNumber) is one of the keys of the dictionary, and if so, restore the correct offset for that scroll view. The reason I add 1 to the tags is because the table view has its own scroll view which has a tag of 0, so I don't want to use 0 as a tag for one of the cell's scroll views.
So in cellForRowAtIndexPath, you need something like this:
cell.scrollView.tag = indexPath.row + 1;
cell.scrollView.delegate = self;
if ([self.paths.allKeys containsObject:#(indexPath.row + 1)]) {
cell.scrollView.contentOffset = CGPointMake([self.paths[#(indexPath.row + 1)] floatValue],0);
}else{
cell.scrollView.contentOffset = CGPointZero;
}
return cell;
And in the delegate method:
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if (scrollView.tag != 0)
[self.paths setObject:#(scrollView.contentOffset.x) forKey:#(scrollView.tag)];
}
paths is a property (NSMutableDictionary) that I create in viewDidLoad.
Use my tableView customs cells
homeScrollCell.h
#import <UIKit/UIKit.h>
#import "MyManager.h"
#interface homeScrollCell : UITableViewCell<UIScrollViewDelegate>
{
MyManager *manager;
UIScrollView *__scrollView;
}
-(void)setPage:(int)page;
#property int currentPage;
#end
homeScrollCell.m
#import "homeScrollCell.h"
#implementation homeScrollCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
manager=[MyManager sharedManager];
__scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width,self.bounds.size.height)];
[__scrollView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
NSInteger viewcount= 3;
for(int i = 0; i< viewcount; i++)
{
CGFloat x = i * self.bounds.size.width;
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(x, 0,self.bounds.size.width,self.bounds.size.height)];
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
UILabel *label=[[UILabel alloc] initWithFrame:CGRectMake(50, 20, 200, 50)];
[label setBackgroundColor:[UIColor redColor]];
label.text=[NSString stringWithFormat:#"Hi, I am label %i",i];
[view addSubview:label];
view.backgroundColor = [UIColor greenColor];
[__scrollView addSubview:view];
}
[__scrollView setBackgroundColor:[UIColor redColor]];
__scrollView.contentSize = CGSizeMake(self.bounds.size.width *viewcount, 100);
__scrollView.pagingEnabled = YES;
__scrollView.bounces = NO;
__scrollView.delegate=self;
[self addSubview:__scrollView];
// Initialization code
}
return self;
}
-(void)setPage:(int)page
{
CGFloat pageWidth = __scrollView.frame.size.width;
float offset_X=pageWidth*page;
[__scrollView setContentOffset:CGPointMake(offset_X, __scrollView.contentOffset.y)];
_currentPage=page;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
static NSInteger previousPage = 0;
CGFloat pageWidth = scrollView.frame.size.width;
float fractionalPage = scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
if (previousPage != page) {
_currentPage=page;
[manager setpage:_currentPage ForKey:[NSString stringWithFormat:#"%i",self.tag]];
previousPage = page;
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
And use a Singleton file for keeping record or pages inside cell.
MyManager.h
#import <Foundation/Foundation.h>
#interface MyManager : NSObject
+ (id)sharedManager;
-(void)setpage:(int)page ForKey:(NSString*)key;
-(int)getpageForKey:(NSString*)key;
#end
MyManager.m
#import "MyManager.h"
static NSMutableDictionary *dictionary;
#implementation MyManager
#pragma mark Singleton Methods
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
-(void)setpage:(int)page ForKey:(NSString*)key
{
[dictionary setValue:[NSString stringWithFormat:#"%i",page] forKey:key];
}
-(int)getpageForKey:(NSString*)key
{
return [[dictionary valueForKey:key] intValue];
}
- (id)init {
if (self = [super init]) {
dictionary=[[NSMutableDictionary alloc] init];
}
return self;
}
- (void)dealloc {
// Should never be called, but just here for clarity really.
}
#end
And use this custom cell in cellForRow as
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Home Scroll Cell";
homeScrollCell *cell =[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell = [[homeScrollCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.tag=indexPath.row;
[cell setPage:[manager getpageForKey:[NSString stringWithFormat:#"%i",indexPath.row]]];
return cell;
}
Set your page inside CustomCell and scroll and after re scrolling get back to previous position will show you page set by you before scrolling.
It will persist your page moved as it is.
Download And Run
rdelmar's answer is missing something. scrollViewDidEndDecelerating will only be called if a users scroll triggers the deceleration behaviour.
A drag only scroll won't call this method so you will get inconsistent behaviour for the user who won't distinguish between the two types of scroll. You need to catch it with scrollViewDidEndDragging:willDecelerate
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate) {
self.tableCellContentOffsets[#(scrollView.tag)] = #(scrollView.contentOffset.x);
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
self.tableCellContentOffsets[#(scrollView.tag)] = #(scrollView.contentOffset.x);
}

Resources