Showing posts with label UIScrollView. Show all posts
Showing posts with label UIScrollView. Show all posts

Friday, July 6, 2012

UIScrollview scrolling in a non linear fashion!



If you want to implement scrolling something like in the link http://joelb.me/scrollpath/ its not possible using UIScrollView because the contentOffset of the scrollview will increase linearly. Don't worry you can modify the standard scrolling behavior by applying logic something like below code.
In the post I have implemented the UIScrollView in such a way that it scrolls like bazier path and there is a commented code for sine wave testing also. If you comment the bazier code and uncomment the sine wave code… Then the scollview scrolls like sine wave. Cool and simple isn't it :):):)


#Define POINT_A CGPointMake(0, 0)
#Define POINT_B CGPointMake(500, 1024*2)
#Define POINT_C CGPointMake(1000, 1024*1.5)
#Define POINT_D CGPointMake(1800, 0))

#define SCROLLVIEW_HEIGHT (768*3.0)

// simple linear interpolation between two points
CGPoint lerp(CGPoint dest, const CGPoint a, const CGPoint b, const float t)
{
    CGPoint outPoint;
    outPoint.x = a.x + (b.x-a.x)*t;
    outPoint.y = a.y + (b.y-a.y)*t;
    return outPoint;
}

// evaluate a point on a bezier-curve. t goes from 0 to 1.0
CGPoint bezier(CGPoint dest, const CGPoint a, const CGPoint b, const CGPoint c, const CGPoint d, const float t)
{
    CGPoint ab,bc,cd,abbc,bccd;
    ab = lerp(ab, a,b,t);           // point between a and b (green)
    bc = lerp(bc, b,c,t);           // point between b and c (green)
    cd = lerp(cd, c,d,t);           // point between c and d (green)
    abbc = lerp(abbc, ab,bc,t);       // point between ab and bc (blue)
    bccd = lerp(bccd, bc,cd,t);       // point between bc and cd (blue)
    dest = lerp(dest, abbc,bccd,t);   // point on the bezier-curve (black)

    return dest;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    float x = [scrollView contentOffset].x;  

    //Sin wave Testing
    //float y = 90 - sin((x / (768*3))*10)*80;

    //Bazier path
    // 4 points define the bezier-curve. These are the points used
    // for the example-images on this page.
    // Will work for n Points also
    CGPoint a = POINT_A;
    CGPoint b = POINT_B;
    CGPoint c = POINT_C;
    CGPoint d = POINT_D;


    CGPoint p = bezier(p, POINT_A, POINT_B, POINT_C, POINT_D,([scrollView contentOffset].x/SCROLLVIEW_HEIGHT));
    x = [scrollView contentOffset].x;
    y = p.y;

    scrollView.contentOffset = CGPointMake(x, y);
}

Restricting diagonal scrolling in UIScrollview


#Restricting diagonal scrolling

enum EGRIDVIEW_SCROLLDIRECTION {
    eScrollLeft = 0,
    eScrollRight = 1,
    eScrollTop = 2,
    eScrollBottom = 3,
    eScrollNone = 4
    };

-(EGRIDVIEW_SCROLLDIRECTION) getScrollDirection : (CGPoint) startPoint endPoint:(CGPoint) endPoint
{
    EGRIDVIEW_SCROLLDIRECTION direction = eScrollNone;
   
    EGRIDVIEW_SCROLLDIRECTION xDirection;
    EGRIDVIEW_SCROLLDIRECTION yDirection;
   
    int xDirectionOffset = startPoint.x - endPoint.x;
    if(xDirectionOffset > 0)
        xDirection = eScrollLeft;
    else
        xDirection = eScrollRight;
   
    int yDirectionOffset = startPoint.y - endPoint.y;
    if(yDirectionOffset > 0)
        yDirection = eScrollTop;
    else
        yDirection = eScrollBottom;
   
    if(abs(xDirectionOffset) > abs(yDirectionOffset))
        direction = xDirection;
    else
        direction = yDirection;

    return direction;
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    mPreviousTouchPoint = scrollView.contentOffset;
}

- (void)scrollViewDidScroll:(UIScrollView *)sender
{
    CGPoint offset = self.scrollView.contentOffset;
   
    //Cool... Restricting diagonal scrolling
    mSwipeDirection = [self getScrollDirection:mPreviousTouchPoint endPoint:self.scrollView.contentOffset];
    switch (mSwipeDirection) {
        case eScrollLeft:
            self.scrollView.contentOffset = CGPointMake(offset.x, mPreviousTouchPoint.y);
            break;
           
        case eScrollRight:
            self.scrollView.contentOffset = CGPointMake(offset.x, mPreviousTouchPoint.y);
            break;
           
        case eScrollTop:
            self.scrollView.contentOffset = CGPointMake(mPreviousTouchPoint.x, offset.y);
            break;
           
        case eScrollBottom:
            self.scrollView.contentOffset = CGPointMake(mPreviousTouchPoint.x, offset.y);
            break;
           
        default:
            break;
    }
}

Adding fade Animation to the scrollview


Here is the simple usage of mapping the values to get fade effect while scrolling, I am not going to write whole code. Here is the logic...


- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    mPreviousTouchPoint = scrollView.contentOffset;
}


- (void)scrollViewDidScroll:(UIScrollView *)sender
{
if(animation == fadeIn)
{
        pageWidth = self.pageSize.size.width;
        page = floor((self.scrollView.contentOffset.x - pageWidth) / pageWidth) + 1;
     
                 //Mapping values from 0-1024(subview frame) to 0-1(alpha range)
        float NewMax = 1;
        float NewMin = 0;
        float OldMax = pageWidth*(page+1);
        float OldMin = pageWidth*page;
     
        int OldValue = mScrollView.contentOffset.x;//doubth
        float newValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin;
     
               //If it is scrolling to right applying animation to next page
        page = page+1;
     
                 //If it is scrolling to left applying animation to previous page
        if(mPreviousTouchPoint.x > mScrollView.contentOffset.x)
            page = page - 1;
     
        if(page < 0 || page >= mNoOfPages)
           return;
     
                //Applying alpha to the subview, where mSubviewsArray contains all the subviews of a       //scrollview
         UIView *nextPage = [mSubviewsArray objectAtIndex:page];
        if(nextPage)
        {
          if(mPreviousTouchPoint.x > mScrollView.contentOffset.x)
                nextPage.alpha = 1-newValue;
            else
                nextPage.alpha = newValue;
        }
}
}