How to change alpha value along with scrolling - ios

I could not found any where for this kind sticky issue.My issue is when the user started scrolling i need to change the alpha value.At starting of scrolling alpha value should be 1, then at middle of scrolling alpha value should be 0.5, at end it must be 0.This what i need to do.i could not find with googling. help me plz

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
/* This is the offset at the bottom of the scroll view. */
CGFloat totalScroll = scrollView.contentSize.height - scrollView.bounds.size.height;
/* This is the current offset. */
CGFloat offset = - scrollView.contentOffset.y;
/* This is the percentage of the current offset / bottom offset. */
CGFloat percentage = offset / totalScroll;
/* When percentage = 0, the alpha should be 1 so we should flip the percentage. */
scrollView.alpha = (1.f - percentage);
}

Here is how to do it in Swift, i have 2 UILabel in my controller, and i need to increase alpha for the first UILabel and decrease alpha for the second :
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
// Bottom
}
if (scrollView.contentOffset.y < 0){
// Top
lblTitleHeader.alpha = 0
lblTitleBody.alpha = 1
}
if (scrollView.contentOffset.y >= 0 && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)){
// Middle
let percentage: CGFloat = (scrollView.contentOffset.y) / 20
// This label loses alpha when you scroll down (or slide up)
lblTitleHeader.alpha = (percentage)
// This label gets more alpha when you scroll up (or slide down)
lblTitleBody.alpha = (1 - percentage)
}
}

Related

Edit the alpha of navigation bar when scrolls tableview

I wanna ask if its possible to change the alpha value of a navigation bar when the user is scrolling a tableview.
I have the algorithm, but i need something help to get changes on real time.
/* This is the offset at the bottom of the scroll view. */
CGFloat totalScroll = scrollView.contentSize.height - scrollView.bounds.size.height;
/* This is the current offset. */
CGFloat offset = - scrollView.contentOffset.y;
/* This is the percentage of the current offset / bottom offset. */
CGFloat percentage = offset / totalScroll;
/* When percentage = 0, the alpha should be 1 so we should flip the percentage. */
scrollView.alpha = (1.f - percentage);
It's probably too late, but for future reference, you could do something like this:
func scrollViewDidScroll(scrollView: UIScrollView) {
self.navigationController!.navigationBar.alpha = 1 - (self.tableView.contentOffset.y / (self.tableView.contentSize.height - self.tableView.frame.size.height));
}
On this delegate you have the values of contentOffset of scrollview or tableView, and you can observe the value of this property to make the behavior you desire.
Hope it helps!

How to detect scrolling to an end of an horizontal UICollectionView

do you know a way in order to detect when a user has scrolled to the end (or the beginning) of an UICollectionView (in order to load new content). Since the UICollectionView scrolls horizontally and not vertically, I am not interested to the scrolling to top/bottom but to leftmost/rightmost.
The only way I found so far is to subclass the UICollectionView and then register the view controller as a delegate that is informed of when the collection view willLayoutSubviews and perform calculations accordingly.
But let's say I don't want to subclass UICollectionView, is there a way to detect the scrolling to the end/beginning of UICollectionView?
EDIT:
since UICollectionView inherits from UIScrollView, I can use its delegate methods. How does it work with with horizontal scrolling?
Thank you
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetX = scrollView.contentOffset.x;
CGFloat contentWidth = scrollView.frame.size.width;
NSLog(#"offset X %.0f", offsetX);
// If your UICollectionView has 3 cell, the contentWidth is 320,
// When you scroll from beginning to end of the UICollectionView, it will print:
// offset X 0
// offset X 1
// offset X 2
// ......
// offset X 320
// offset X 640
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if ([scrollView isKindOfClass:[UICollectionView class]] == YES) {
CGFloat threshold = 100.0 ;
CGFloat contentOffset = scrollView.contentOffset.x;
CGFloat maximumOffset = scrollView.contentSize.width - scrollView.frame.size.width;
if ((maximumOffset - contentOffset <= threshold) && (maximumOffset - contentOffset != -5.0) ){
//Your code
}
}
}

How to Calculate Scrollview width and height on every scroll in iOS

I have Scrollview using for displaying images along with two buttons previous and next.
Now my problem is when the user is scrolling the image I want to identify whether it is from right to left scroll or vice versa. For this purpose I have to calculate scrollview contentOffset and scrollview frame size but I don't know how to calculate those values.
Still now I used:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0){}
this method.
need any suggestions.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView1 willDecelerate:(BOOL)decelerate;
{
CGFloat pageWidth = scrollView.frame.size.width;
float fractionalPage = scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
if (previousPage != page){
if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0){
NSLog(#"-1");
} else {
NSLog(#"+1");
}
}
}
Hi if you are scrolling Horizontally you will get to know whether you are going next or previous depending upon velocity.x
velocity.x > 0 ?(int) _currentIndex + 1 :(int) _currentIndex - 1;
-(void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
CGFloat xAxisVisible= self.uiScrollDetails.contentOffset.x;
self.currentIndex=xAxisVisible/320;
NSLog(#"Dragging - You are now on page %i",(int) self.currentIndex);
}

Backward Scroll

Hi I have 10 images in UIScrollview now i can scroll forward like from 1 to 2,3,4,etc but in my project i need to scroll images backward direction also like from 1 to 10 to left hand side
this is my code
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
CGFloat pageWidth = cardsScrollView.frame.size.width;
NSUInteger page = floor((self.cardsScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
if(page + 1 == [flashCardArry count]){
for (NSUInteger i = 0; i < [flashCardArry count]; ++i) {
int nElements = [flashCardArry count] - i;
int n = (arc4random() % nElements) + i;
[flashCardArry exchangeObjectAtIndex:i withObjectAtIndex:n];
}
[self.cardsScrollView scrollRectToVisible:CGRectMake(self.cardsScrollView.frame.size.width * 0 , 0, self.cardsScrollView.frame.size.width, self.cardsScrollView.frame.size.height) animated:NO];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
CGFloat pageWidth = cardsScrollView.frame.size.width;
NSUInteger page = floor((self.cardsScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
You can simply do that by adding the imageViews from 10 to 1 on your scrollView and then you have se the contentOffset of you scrollview to point to the last image which is image 1.
So user wont be able to scroll right at first, he can scroll to left for next images.
So. In case if you want cyclic scrollview you would need next things:
1) hide scrollView indicators
scrl.showsHorizontalScrollIndicator = NO;
scrl.showsVerticalScrollIndicator = NO;
2) Add one item to beginning of the scroll view, and one item at the end
[5'] | [0][1][2][3][4][5] | [0']
| --- full_size--- |
3) Once user scrolls to 5' item we updating content offset by adding full_size
4) Once user scrolls to 0' item we updating content offset by subtracting full_size
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint contentOffset = scrollView.contentOffset;
// First item
if (contentOffset.x < page_size) { // We are now faking last page
scrollView.contentOffset += full_size; // Jumping to actual last page
}
// Last item
if (contentOffset.x > full_size) { // We are now faking first page
scrollView.contentOffset -= full_size; // Jumping to actual first page
}
}
5) To decrease amount of jumps (especially on the borders), you can add more 2 or more fake items from both side

Increasing UIScrollView rubber banding resistance

I've got a scenario I'm trying to implement in my app where I'd like to make a UIScrollView behave more 'stiff' once you start forcing it to scroll past its normal content bounds.
What I mean by this, is when you're either at the top or bottom of a scroll view, if you tap down and keep dragging, you can usually get the scroll view to keep scroling beyond its bounds, but it gradually builds up resistance, until it stops usually about half way in the middle of the view's bounds. When you lift your finger, it snaps back to the bounds of the scroll region.
What I'm trying to achieve, is I'd like to make that 'out-of-bounds' dragging effect a lot more heavy, so instead of the user dragging the scroll view and it 'bottoming-out' mid way through the scroll view bounds, it completely stops around 20% or so past its scrolling bounds instead.
I've been experimenting with overriding the scroll view's contentOffset inside the scrollViewDidScroll: delegate method, but that doesn't seem to work since re-setting the contentOffset in there seems to screw up further delegate calls of the same method.
My next idea was to monitor the UIPanGestureRecognizer associated with the scrollview and try and determine the proper UIScrollView contentOffset based off events coming out of that. That being said, I thought that might start getting on the hacky side, so I thought I'd ask here for any other solutions I hadn't considered before I try something that could potentially be messy.
Thanks!
I am spiking on the following code in Swift. This is for horizontal scrolling and can easily be adapted to vertical one. Solutions differ depending on whether paging is enabled or not. Both are given below.
class ScrollViewDelegate : NSObject, UIScrollViewDelegate
{
let maxOffset: CGFloat // offset of the rightmost content (scrollview contentSize.width - frame.width)
var prevOffset: CGFloat = 0 // previous offset (after adjusting the value)
var totalDistance: CGFloat = 0 // total distance it would have moved (had we not restricted)
let reductionFactor: CGFloat = 0.2 // percent of total distance it will be allowed to move (under restriction)
let scaleFactor: CGFloat = UIScreen.mainScreen().scale // pixels per point, for smooth translation in respective devices
init(maxOffset: CGFloat)
{
self.maxOffset = maxOffset // scrollView.contentSize.width - scrollView.frame.size.width
}
func scrollViewDidScroll(scrollView: UIScrollView)
{
let flipped = scrollView.contentOffset.x >= maxOffset // dealing with left edge or right edge rubber band
let currentOffset = flipped ? maxOffset - scrollView.contentOffset.x : scrollView.contentOffset.x // for right edge, flip the values as if screen is folded in half towards the left
if(currentOffset <= 0) // if dragging/moving beyond the edge
{
if(currentOffset <= prevOffset) // if dragging/moving beyond previous offset
{
totalDistance += currentOffset - prevOffset // add the "proposed delta" move to total distance
prevOffset = round(scaleFactor * totalDistance * reductionFactor) / scaleFactor // set the prevOffset to fraction of total distance
scrollView.contentOffset.x = flipped ? maxOffset - prevOffset : prevOffset // set the target offset, after negating any flipping
}
else // if dragging/moving is reversed, though still beyond the edge
{
totalDistance = currentOffset / reductionFactor // set totalDistance from offset (reverse of prevOffset calculation above)
prevOffset = currentOffset // set prevOffset
}
}
else // if dragging/moving inside the edge
{
totalDistance = 0 // reset the values
prevOffset = 0
}
}
}
When paging is enabled, the bounce back to the resting point doesn't seem to work as expected. Instead of stopping at the page boundary, the rubber band is overshooting it and halting at a non-page offset. This happens if the pull from the edge is with a fast flick such that it continues to move in that direction even after you lift the finger, before reversing the direction and coming back to the resting point. It seems to work fine if you simply pause and leave or even flick it back towards the resting point. To address this, in the below code I try to identify the possibility of overshooting and forcefully stop it while it returns and attempts to cross the expected page boundary.
class PageScrollViewDelegate : NSObject, UIScrollViewDelegate
{
let maxOffset: CGFloat // offset of the rightmost content (scrollview contentSize.width - frame.width)
var prevOffset: CGFloat = 0 // previous offset (after adjusting the value)
var totalDistance: CGFloat = 0 // total distance it would have moved (had we not restricted)
let reductionFactor: CGFloat = 0.2 // percent of total distance it will be allowed to move (under restriction)
let scaleFactor: CGFloat = UIScreen.mainScreen().scale // pixels per point, for smooth translation in respective devices
var draggingOver: Bool = false // finger dragging is over or not
var overshoot: Bool = false // is there a chance for page to overshoot page boundary while falling back
init(maxOffset: CGFloat)
{
self.maxOffset = maxOffset // scrollView.contentSize.width - scrollView.frame.size.width
}
func scrollViewWillBeginDragging(scrollView: UIScrollView)
{
draggingOver = false // reset the flags
overshoot = false
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool)
{
draggingOver = true // finger dragging is over
}
func scrollViewDidScroll(scrollView: UIScrollView)
{
let flipped = scrollView.contentOffset.x >= 0.5 * maxOffset // dealing with left edge or right edge rubber band
let currentOffset = flipped ? maxOffset - scrollView.contentOffset.x : scrollView.contentOffset.x // for right edge, flip the values as if screen is folded in half towards the left
if(currentOffset <= 0) // if dragging/moving beyond the edge
{
if(currentOffset <= prevOffset) // if dragging/moving beyond previous offset
{
overshoot = draggingOver // is content moving farther away even after dragging is over (caused by fast flick, which can cause overshooting page boundary while falling back)
totalDistance += currentOffset - prevOffset // add the "proposed delta" move to total distance
prevOffset = round(scaleFactor * totalDistance * reductionFactor) / scaleFactor // set the prevOffset to fraction of total distance
scrollView.contentOffset.x = flipped ? maxOffset - prevOffset : prevOffset // set the target offset, after negating any flipping
}
else // if dragging/moving is reversed, though still beyond the edge
{
totalDistance = currentOffset / reductionFactor // set totalDistance from offset (reverse of prevOffset calculation above)
prevOffset = currentOffset // set prevOffset
}
}
else // if dragging/moving inside the edge
{
if(overshoot) // if this movement is a result of overshooting
{
scrollView.setContentOffset(CGPointMake(flipped ? maxOffset : 0, scrollView.contentOffset.y), animated: false) // bring it to resting point and stop further scrolling (this is a patch to control overshooting)
}
totalDistance = 0 // reset the values
prevOffset = 0
}
}
}
This isn't going to be easy.
If this is just a one-off scroll view, I might suggest using UIKit Dynamics with some push, attachment, and spring behaviors to get exactly the effect you want.
If you're looking to do this for every table view in your app I think watching the pan gesture recognizer is a reasonable enough approach. Just off the top of my head I would observe the gesture's state, when it ends I would capture the vertical velocity of the view, use the UIScrollView method to calculate it's stopping position and then animate it from its current position to its resting position with a spring animation. You'll have to calculate the duration yourself using the ending velocity of the pan and the remaining distance + the overshoot amount.
I have made a GitHub project that handle this case
Bounce Scroll View
You can control the resistance of the scrolling through it
This Code will stop the scroll at the margin you want
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat margin = scrollView.frame.size.height/4.0;
if (scrollView.contentOffset.y < -margin) {
CGPoint offset = scrollView.contentOffset;
offset.y = -margin;
scrollView.contentOffset = offset;
} else if (scrollView.contentOffset.y > (scrollView.contentSize.height-scrollView.frame.size.height) + margin) {
CGPoint offset = scrollView.contentOffset;
offset.y = (scrollView.contentSize.height-scrollView.frame.size.height) + margin;
scrollView.contentOffset = offset;
}
}
Hope it helps

Resources