UICollectionView align logic missing in horizontal paging scrollview - iphone

I've got a UICollectionView, which works ok, until I start scrolling.
Here some pics first:
As you can see it's great. As I start scrolling (paging enabled) the first one goes a bit offscreen:
This is the problem. Originaly my view have 3 views and I want to scroll and show 3 views only. But as it scrolls (paging enabled) it hides a little bit of the first view and show little bit of the next first view from the next page.
And here is a video, because it's kinda hard to explain:
Video of the problem (Dropbox)
Here is a picture of my UICollectionView settings:
It's going to be great if someone can help!

The fundamental issue is Flow Layout is not designed to support the paging. To achieve the paging effect, you will have to sacrifice the space between cells. And carefully calculate the cells frame and make it can be divided by the collection view frame without remainders. I will explain the reason.
Saying the following layout is what you wanted.
Notice, the most left margin (green) is not part of the cell spacing. It is determined by the flow layout section inset. Since flow layout doesn't support heterogeneous spacing value. It is not a trivial task.
Therefore, after setting the spacing and inset. The following layout is what you will get.
After scroll to next page. Your cells are obviously not aligned as what you expected.
Making the cell spacing 0 can solve this issue. However, it limits your design if you want the extra margin on the page, especially if the margin is different from the cell spacing. It also requires the view frame must be divisible by the cell frame. Sometimes, it is a pain if your view frame is not fixed (considering the rotation case).
The real solution is to subclass UICollectionViewFlowLayout and override following methods
- (CGSize)collectionViewContentSize
{
// Only support single section for now.
// Only support Horizontal scroll
NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView
numberOfItemsInSection:0];
CGSize canvasSize = self.collectionView.frame.size;
CGSize contentSize = canvasSize;
if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
{
NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;
NSUInteger page = ceilf((CGFloat)count / (CGFloat)(rowCount * columnCount));
contentSize.width = page * canvasSize.width;
}
return contentSize;
}
- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize canvasSize = self.collectionView.frame.size;
NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;
CGFloat pageMarginX = (canvasSize.width - columnCount * self.itemSize.width - (columnCount > 1 ? (columnCount - 1) * self.minimumLineSpacing : 0)) / 2.0f;
CGFloat pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0f;
NSUInteger page = indexPath.row / (rowCount * columnCount);
NSUInteger remainder = indexPath.row - page * (rowCount * columnCount);
NSUInteger row = remainder / columnCount;
NSUInteger column = remainder - row * columnCount;
CGRect cellFrame = CGRectZero;
cellFrame.origin.x = pageMarginX + column * (self.itemSize.width + self.minimumLineSpacing);
cellFrame.origin.y = pageMarginY + row * (self.itemSize.height + self.minimumInteritemSpacing);
cellFrame.size.width = self.itemSize.width;
cellFrame.size.height = self.itemSize.height;
if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
{
cellFrame.origin.x += page * canvasSize.width;
}
return cellFrame;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes * attr = [super layoutAttributesForItemAtIndexPath:indexPath];
attr.frame = [self frameForItemAtIndexPath:indexPath];
return attr;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect];
NSMutableArray * attrs = [NSMutableArray array];
[originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) {
NSIndexPath * idxPath = attr.indexPath;
CGRect itemFrame = [self frameForItemAtIndexPath:idxPath];
if (CGRectIntersectsRect(itemFrame, rect))
{
attr = [self layoutAttributesForItemAtIndexPath:idxPath];
[attrs addObject:attr];
}
}];
return attrs;
}
Notice, above code snippet only supports single section and horizontal scroll direction. But it is not hard to expand.
Also, if you don't have millions of cells. Caching those UICollectionViewLayoutAttributes may be a good idea.

You could disable paging on UICollectionView and implement a custom horizontal scrolling/paging mechanism with a custom page width/offset like this:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
float pageWidth = 210;
float currentOffset = scrollView.contentOffset.x;
float targetOffset = targetContentOffset->x;
float newTargetOffset = 0;
if (targetOffset > currentOffset)
newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth;
else
newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth;
if (newTargetOffset < 0)
newTargetOffset = 0;
else if (newTargetOffset > scrollView.contentSize.width)
newTargetOffset = scrollView.contentSize.width;
targetContentOffset->x = currentOffset;
[scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES];
}

This answer is way late, but I have just been playing with this problem and found that the cause of the drift is the line spacing. If you want the UICollectionView/FlowLayout to page at exact multiples of your cells width, you must set:
UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
flowLayout.minimumLineSpacing = 0.0;
You wouldn't think the line spacing comes into play in horizontal scrolling, but apparently it does.
In my case I was experimenting with paging left to right, one cell at a time, with no space between cells. Every turn of the page introduced a tiny bit of drift from the desired position, and it seemed to accumulate linearly. ~10.0 pts per turn. I realized 10.0 is the default value of minimumLineSpacing in the flow layout. When I set it to 0.0, no drift, when I set it to half the bounds width, each page drifted an extra half of the bounds.
Changing the minimumInteritemSpacing had no effect.
edit -- from the documentation for UICollectionViewFlowLayout:
#property (nonatomic) CGFloat minimumLineSpacing;
Discussion
...
For a vertically scrolling grid, this value represents the minimum
spacing between successive rows. For a horizontally scrolling grid,
this value represents the minimum spacing between successive columns.
This spacing is not applied to the space between the header and the
first line or between the last line and the footer.
The default value of this property is 10.0.

The solution from the following article is elegant and simple. The main idea is creation the scrollView on top of your collectionView with passing all contentOffset values.
http://b2cloud.com.au/tutorial/uiscrollview-paging-size/
It should be said by implementing this method:
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
I didn't achieve a smooth animation like it's happening with pagingEnabled = YES.

I know this question is old, but for anyone who happens to stumble upon this.
All you have to do to correct this is set the MinimumInterItemSpacing to 0 and decrease the content's frame.

#devdavid was spot on on the flowLayout.minimumLineSpacing to zero.
It can also be done in the layout editor, setting the Min Spacing for Lines to 0:

I think I understand the problem. I'll try and make you understand it too.
If you look closely, then you will see that this issue happens only gradually and not just on the first page swipe.
If I understand correctly, in your app, currently, every UICollectionView item are those rounded boxes which we see, and you have some offset/margin between all of them which is constant. This is what is causing the issue.
Instead, what you should do, is make a UICollectionView item which is 1/3rd of the width of the whole view, and then add that rounded image view inside it. To refer to the image, the green colour should be your UICollectionViewItem and not the black one.

Do you roll your own UICollectionViewFlowLayout?
If so, adding -(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
withScrollingVelocity:(CGPoint)velocity will help you to calculate where the scrollview should stop.
This might work (NB: UNTESTED!):
-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
withScrollingVelocity:(CGPoint)velocity
{
CGFloat offsetAdjustment = MAXFLOAT;
CGFloat targetX = proposedContentOffset.x + self.minimumInteritemSpacing + self.sectionInset.left;
CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
for(UICollectionViewLayoutAttributes *layoutAttributes in array) {
if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemX = layoutAttributes.frame.origin.x;
if (ABS(itemX - targetX) < ABS(offsetAdjustment)) {
offsetAdjustment = itemX - targetX;
}
}
}
return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}

My answer is based on answer https://stackoverflow.com/a/27242179/440168 but is more simple.
You should place UIScrollView above UICollectionView and give them equal sizes:
#property (nonatomic, weak) IBOutlet UICollectionView *collectionView;
#property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
Then configure contentInset of collection view, for example:
CGFloat inset = self.view.bounds.size.width*2/9;
self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset);
And contentSize of scroll view:
self.scrollView.contentSize = CGSizeMake(self.placesCollectionView.bounds.size.width*[self.collectionView numberOfItemsInSection:0],0);
Do not forget to set delegate of scroll view:
self.scrollView.delegate = self;
And implement main magic:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == self.scrollView) {
CGFloat inset = self.view.bounds.size.width*2/9;
CGFloat scale = (self.placesCollectionView.bounds.size.width-2*inset)/scrollView.bounds.size.width;
self.collectionView.contentOffset = CGPointMake(scrollView.contentOffset.x*scale - inset, 0);
}
}

your UICollectionView's width should be an exact multiplication of the cell size width + the left and right insets. In your example, if the cell width is 96, then the UICollectionView's width should be (96 + 5 + 5) * 3 = 318.
Or, if you wish to keep UICollectionView's 320 width, your cell size width should be 320 / 3 - 5 - 5 = 96.666.
If this does not help, your UICollectionView's width might be different than what is set in the xib file, when the application runs. To check this - add an NSLog statement to printout the view's size in runtime:
NSLog(#"%#", NSStringFromCGRect(uiContentViewController.view.frame));

This is the same problem that I was experiencing and i posted my solution on another post, so I'll post it again here.
I found a solution to it, and it involved subclassing the UICollectionViewFlowLayout.
My CollectionViewCell size is 302 X 457 and i set my minimum line spacing to be 18 (9pix for each cell)
When you extend from that class there are a few methods that need to be over-ridden. One of them is
(CGSize)collectionViewContentSize
In this method, I needed to add up the total width of what was in the UICollectionView. That includes the ([datasource count] * widthOfCollectionViewCell) + ([datasource count] * 18)
Here is my custom UICollectionViewFlowLayout methods....
-(id)init
{
if((self = [super init])){
self.itemSize = CGSizeMake(302, 457);
self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
self.minimumInteritemSpacing = 0.0f;
self.minimumLineSpacing = 18.0f;
[self setScrollDirection:UICollectionViewScrollDirectionHorizontal];
}
return self;
}
-(CGSize)collectionViewContentSize{
return CGSizeMake((numCellsCount * 302)+(numCellsCount * 18), 457);
}
This worked for me, so I hope someone else finds it useful!

you also can set view's width to '320+spacing', and then set page enable to yes. it will scroll '320+spacing' for every time. i think it because page enable will scroll view's width but not screen's width.

I think I do have a solution for this issue. But I do not if it's the best.
UICollectionViewFlowLayout does contain a property called sectionInset. So you could set the section Inset to whatever your need is and make 1 page equalling one section. Therefore your scrolling should automatically fit properly in the pages ( = sections)

I had a similar problem with paging. Even though the cell insets were all 0 and the cell was exactly the same size in width and height as the UICollectionView, the paging wasn't proper.
What I noticed sounds like a bug in this version (UICollectionView, iOS 6): I could see that if I worked with a UICollectionView with width = 310px or above, and a height = 538px, I was in trouble. However, if I decreased the width to, say, 300px (same height) I got things working perfectly!
For some future reference, I hope it helps!

I encountered a similar issue when trying to get horizontal paging working on a 3 x 3 grid of cells with section insets and cell & line spacing.
The answer for me (after trying many of the suggestions - including subclassing UICollectionViewFlowLayout and various UIScrollView delegate solutions) was simple. I simply used sections in the UICollectionView by breaking my dataset up into sections of 9 items (or fewer), and utilising the numberOfSectionsInCollectionView and numberOfItemsInSection UICollectionView datasource methods.
The UICollectionView's horizontal paging now works beautifully. I recommend this approach to anyone currently tearing their hair out over a similar scenario.

If you're using the default flow-layout for your UICollectionView and do NOT want any space between each cell, you can set its miniumumLineSpacing property to 0 via:
((UICollectionViewFlowLayout *) self.collectionView.collectionViewLayout).minimumLineSpacing = 0;

Related

iOS: Rows of images in ScrollView

I'm just getting started with iOS development. I would like to create a view that would contain 2 rows of image thumbnails as a preview. It would scroll horizontally. I'm wondering if the best approach would be to use 2 scrollviews or place them in a tableview with 2 rows.
If your thumbnail images and rows are essentially static, your best bet might be to drop your thumbnail image views directly into your scrollView. You can layout your thumbnail subviews into two rows and as many columns as necessary with some arbitrary calculations and avoid the need to use a UITableView (which works very well for scrolling rows, but doesn't natively support columns, and as a tool isn't imo the best for this particular job).
If you do elect to use a UITableView, I would put it into a single UIScrollview.... Unless you specifically seek two discretely scrolling rows, I wouldn't implement this with two UIScrollViews.
Here is a code snippet that suggests an approach. Consider 1)All subviews should be the same size 2)The subviews will "grid" themselves according to the bounds of the containing view. I wrote this snippet for a regular UIView (not a UIScrollView), but the concept will be the same: Consider size of scrollContent. Consider how many subviews will fit horizontally, and how many will fit vertically (hence, if you want 2 rows, the scroll view height should be just high enough to fully encompass the height of a single subview * 2):
- (void)layoutSubviews
{
//Lays out subviews in a grid to fill view.
float myWidth = self.bounds.size.width;
float myHeight = self.bounds.size.height;
if ([[self subviews] count] < 1)
{
return; //no subviews, must be added before layoutSubviews is called.
}
CGRect aSubviewRect = [[[self subviews] objectAtIndex:0] frame];
int numberOfColumns = (int)(myWidth / aSubviewRect.size.width);
float actualColumnWidth = myWidth / (float)numberOfColumns;
CGFloat paddingPerColumn = (actualColumnWidth - aSubviewRect.size.width);
int maxRows = (int)(myHeight / aSubviewRect.size.height);
int qtyOfViews = [[self subviews] count];
int numberOfRows = (qtyOfViews / numberOfColumns);
if ((qtyOfViews % numberOfColumns) > 0) //we need remainder row
{
++numberOfRows;
}
if (numberOfRows > maxRows)
{
numberOfRows = maxRows;
NSLog(#"More rows required than fit.");
}
float actualRowHeight = myHeight / (float)numberOfRows;
CGFloat paddingPerRow = (actualRowHeight - aSubviewRect.size.height);
for (UIView *aSubview in [self subviews])
{
int viewIndex = [[self subviews] indexOfObject:aSubview];
int rowIndex = (viewIndex / numberOfColumns);
CGFloat yOrigin = (roundf(((float)rowIndex * aSubviewRect.size.height) + (((rowIndex + 1) * paddingPerRow) / 2)));
int columnIndex = (viewIndex % numberOfColumns);
CGFloat xOrigin = (roundf(((float)columnIndex * aSubviewRect.size.width) + (((columnIndex + 1) * paddingPerColumn) / 2)));
CGRect frame = [aSubview frame];
frame.origin.y = yOrigin;
frame.origin.x = xOrigin;
[aSubview setFrame:frame];
}
}

Resize UIImageView or other control in interfacebuilder using percentage

I have an UIImageView in interface builder and its current size is 100px x 100px.
I know how to resize this by using resize handles at corners and by attribute inspector.
What I want it to resize it exact to a fix percent for eg. 50% so that the new size would automatically 50px x 50px.
I have many other images and don't want to calculate pixel percentage manually hence I need some way to get it done automatically.
Is there a way to do this?
Thanks,
I don't think there is a framework provided API for this. You can use categories to deal with this.
#interface UIImageView (Resizing)
- (void)resizeToPercentSizeOfOriginal:(CGFloat)percentage; // any value between 0 and 100
#end
#implementation UIImageView (Resizing)
- (void)resizeToPercentSizeOfOriginal:(CGFloat)percentage {
if ( percentage < 0 || percentage > 100.0 ) {
// Deal with it.
}
CGSize currentSize = self.frame.size;
CGSize expectedSize = CGSizeMake(currentSize.width * percentage, currentSize.height * percentage);
CGRect theFrame = self.frame;
frame.size = expectedSize;
self.frame = theFrame;
}
#end
You can put this in UIImageView+Resizing.h and UIImageView+Resizing.m and import the header to use the method.

How to fade the content of cell of table view which reaches at the top while scrolling?

Hi everyone i need to implement this functionality.I need to fade the content of the cell while its going to disappear, i mean while it reaches at the top of table view.I am not getting how to do that.Please help me.I tried to use the scrollview's method but not getting how to do that.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
For anyone who wants it, here's some ready-to-go copy/paste-able code that is fully working:
Best Part: This code is only reliant on ONE outside property: self.tableView, so just make sure that's set up and you're good to go!
Just stick this method in your view controller somewhere:
#pragma mark - Scroll View Delegate Methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// Fades out top and bottom cells in table view as they leave the screen
NSArray *visibleCells = [self.tableView visibleCells];
if (visibleCells != nil && [visibleCells count] != 0) { // Don't do anything for empty table view
/* Get top and bottom cells */
UITableViewCell *topCell = [visibleCells objectAtIndex:0];
UITableViewCell *bottomCell = [visibleCells lastObject];
/* Make sure other cells stay opaque */
// Avoids issues with skipped method calls during rapid scrolling
for (UITableViewCell *cell in visibleCells) {
cell.contentView.alpha = 1.0;
}
/* Set necessary constants */
NSInteger cellHeight = topCell.frame.size.height - 1; // -1 To allow for typical separator line height
NSInteger tableViewTopPosition = self.tableView.frame.origin.y;
NSInteger tableViewBottomPosition = self.tableView.frame.origin.y + self.tableView.frame.size.height;
/* Get content offset to set opacity */
CGRect topCellPositionInTableView = [self.tableView rectForRowAtIndexPath:[self.tableView indexPathForCell:topCell]];
CGRect bottomCellPositionInTableView = [self.tableView rectForRowAtIndexPath:[self.tableView indexPathForCell:bottomCell]];
CGFloat topCellPosition = [self.tableView convertRect:topCellPositionInTableView toView:[self.tableView superview]].origin.y;
CGFloat bottomCellPosition = ([self.tableView convertRect:bottomCellPositionInTableView toView:[self.tableView superview]].origin.y + cellHeight);
/* Set opacity based on amount of cell that is outside of view */
CGFloat modifier = 2.5; /* Increases the speed of fading (1.0 for fully transparent when the cell is entirely off the screen,
2.0 for fully transparent when the cell is half off the screen, etc) */
CGFloat topCellOpacity = (1.0f - ((tableViewTopPosition - topCellPosition) / cellHeight) * modifier);
CGFloat bottomCellOpacity = (1.0f - ((bottomCellPosition - tableViewBottomPosition) / cellHeight) * modifier);
/* Set cell opacity */
if (topCell) {
topCell.contentView.alpha = topCellOpacity;
}
if (bottomCell) {
bottomCell.contentView.alpha = bottomCellOpacity;
}
}
}
Don't forget to add <UIScrollViewDelegate> to your class's '.h' file!
You may also want to put a call to this method somewhere in your viewDidLoad method like this: [self scrollViewDidScroll:self.tableView]; so that the bottom cell will start out faded (since it's normally cut off by the table view edge).
TIP: Set your table view separator style to none (self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;), or create your own separators as images and add them as a subview to your cells, so that you don't get the unpleasant effect of the separators disappearing without fading.
Works just as well with smaller than full-screen table views.
Here is Fateh Khalsa's solution in Swift
func scrollViewDidScroll(scrollView: UIScrollView)
{
let visibleCells = tableView.visibleCells
if visibleCells.count == 0 {
return
}
guard let bottomCell = visibleCells.last else {
return
}
guard let topCell = visibleCells.first else {
return
}
for cell in visibleCells {
cell.contentView.alpha = 1.0
}
let cellHeight = topCell.frame.size.height - 1
let tableViewTopPosition = tableView.frame.origin.y
let tableViewBottomPosition = tableView.frame.origin.y + tableView.frame.size.height
let topCellPositionInTableView = tableView.rectForRowAtIndexPath(tableView.indexPathForCell(topCell)!)
let bottomCellPositionInTableView = tableView.rectForRowAtIndexPath(tableView.indexPathForCell(bottomCell)!)
let topCellPosition = tableView.convertRect(topCellPositionInTableView, toView: tableView.superview).origin.y
let bottomCellPosition = tableView.convertRect(bottomCellPositionInTableView, toView: tableView.superview).origin.y + cellHeight
let modifier: CGFloat = 2.5
let topCellOpacity = 1.0 - ((tableViewTopPosition - topCellPosition) / cellHeight) * modifier
let bottomCellOpacity = 1.0 - ((bottomCellPosition - tableViewBottomPosition) / cellHeight) * modifier
topCell.contentView.alpha = topCellOpacity
bottomCell.contentView.alpha = bottomCellOpacity
}
I hope i understand your question correctly: You need to fade the content of the cell depending on how much that cell is out of the screen?
I don't know what cells you have in the table, but IF they have the same height, you can do something like this:
// Let's say you have a variable called cellHeight
int cellHeight = 80;
// Get the location of the top of the table
int topPosition = (int)tableView.cotentOffset.y;
// Get the index of the cell
int cellIndex = topPosition / cellHeight;
// Determine how much the cell is outside the view
float opacity = 1.0f - ((topPosition % cellHeight) / cellHeight);
You can now use opacity to control the transparency level. 0.0f means completely outside the view, 1.0f means completely inside.
To get the actual UITableViewCell which you need to change, use
- (NSArray *)indexPathsForVisibleRows
and then search for the cell that cellIndex.
You can create a gradient image and place it above the top of your scrollview. If you would like the "fade" to only be visible during scrolling, you can animate the image fading in and out on scrollViewBegin/DidEndScrollingAnimation or combine that with scrollViewDidScroll, you can decide when it's appropriate to fade out (i.e. when you're scrolled to the top).

Scroll a background in a different speed on a UIScrollView

When somebody does a wipe gesture to scroll the content from left to right, I would like to have a background image scrolling into the same direction, but at a different speed. Much like what these classic games did do 20 years ago (remember that, anybody????)
I accomplished this by using two UIScrollView instances. The first is where the actual content is displayed, and the second (which is behind the first in z-order) is where I have my slower-moving background. From there the top UIScrollView has a delegate attached to it that gets notified when the contentOffset changes. That delegate, in turn, programatically sets the contentOffset of the background scroller, multiplied against a constant to slow the scroll down relative to the foreground. So, for instance, you might have something like:
// Defined as part of the delegate for the foreground UIScrollView
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UIScrollView* scroll_view(static_cast<UIScrollView*>(bkg_scroller_m.view));
CGPoint offset(scrollView.contentOffset);
offset.x = offset.x / 3;
offset.y = offset.y / 3;
// Scroll the background scroll view by some smaller offset
scroll_view.contentOffset = offset;
}
You can easily do this by implementing scroll view did scroll with a UIImageView under it...
You'll end up with something like this... with the backgroundImageView being a UIImageView added to the view before the subview... you can layer as much image views as you want without performance issues
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
float factor = scrollView.contentOffset.x / (scrollView.contentSize.width - 320);
if (factor < 0) factor = 0;
if (factor > 1) factor = 1;
CGRect frame = backgroundImageView.frame;
frame.origin.x = factor * (320 - backgroundImageView.frame.size.width);
backgroundImageView.frame = frame;
}
You can do it with CoreAnimation. You'll want to hook into the scrollViewDidEndDragging:willDecelerate: and scrollViewWillBeginDecelerating: UIScrollViewDelegate methods. Then begin an Animation on your image by changing the center position. See this SO article for more on animations.
For example you have multiple scrollviews, want them scroll difference speed. here is the modification code base on Salamatizm answer:
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float factor = scrollView.contentOffset.x / (scrollView.contentSize.width - screenSize.width);
if (factor < 0) factor = 0;
if (factor > 1) factor = 1;
CGSize parralaxSize = self.parralaxBackgroundView.contentSize;
CGPoint parallaxOffset = CGPointMake(-(factor * (screenSize.width - parralaxSize.width)), 0);
[self.parralaxBackgroundView setContentOffset:parallaxOffset animated:NO];

iphone UitextView Text cut off

I have a Uitextview that is populated with a text file. I have a control on the page that allows the user to enable and disable paging. I am having a problem where the top and/or bottom line of the text is sometimes "split in half" so you can only see the top or bottom half of the line. I believe the code below should fix it. The code gets the line height of the text and the frame height, figures out the number of lines that are visible on the screen, and creates a new frame height so it will fit. While the frame does get resized, it still "cuts off" the top and/or bottom line. Anyone one have any suggestions? Is my math wrong?
Thanks!!!
- (void)fitText
{
CGFloat maximumLabelHeight = 338;
CGFloat minimumLabelHeight = 280;
CGSize lineSize = [theUiTextView.text sizeWithFont:theUiTextView.font];
CGFloat lineSizeHeight = lineSize.height;
CGFloat theNumberOfLinesThatShow = theUiTextView.frame.size.height/lineSize.height;
//adjust the label the the new height
theNumberOfLinesThatShow = round(theNumberOfLinesThatShow);
CGFloat theNewHeight = lineSizeHeight * theNumberOfLinesThatShow;
if (theNewHeight > maximumLabelHeight)
{
theNumberOfLinesThatShow = theNumberOfLinesThatShow - 1;
theNewHeight = lineSizeHeight * theNumberOfLinesThatShow;
}
if (theNewHeight < minimumLabelHeight)
{
theNumberOfLinesThatShow = theNumberOfLinesThatShow + 1;
theNewHeight = lineSizeHeight * theNumberOfLinesThatShow;
}
//adjust the label the the new height.
CGRect newFrame = theUiTextView.frame;
newFrame.size.height = theNewHeight;
theUiTextView.frame = newFrame;
}
UIScrollView (and UITextView is a UIScrollView) seems to use a fixed 8-pixel inset on both sides. This seems to be independent of alignment or font size.
So, I think what you're missing here is the fudge factor of 16.0 - see this question.