Commits

p2 committed 06d674b

Better algorithm, bubble keeps the same size no matter how many entries.

Comments (0)

Files changed (3)

ThumbScrolling/PPTSRowView.h

 - (void)setupWithCell:(UITableViewCell *)aCell reference:(PPTSRowView *)aReference;
 - (void)showText:(NSString *)aString withFont:(UIFont *)aFont at:(CGRect)aRect;
 
-- (void)foldWithFocusAt:(CGFloat)focusY bubbleSize:(CGFloat)bubble slowAnim:(BOOL)slow;
+- (void)foldWithFocusAt:(CGFloat)focusY inBubble:(CGFloat)bubbleSize withDensity:(CGFloat)density slowAnim:(BOOL)slow;
 - (void)foldUp:(void (^)(BOOL finished))completion;
 
-- (CGFloat)yForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize;
-- (CATransform3D)transformForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize;
+- (CGFloat)yForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize withDensity:(CGFloat)density;
+- (CATransform3D)transformForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize withDensity:(CGFloat)density;
+- (CGFloat)fractionForFocusY:(CGFloat)focusY withDensity:(CGFloat)density;
 
 
 @end

ThumbScrolling/PPTSRowView.m

 /**
  *	Folds down the receiver to align to y as focal point
  */
-- (void)foldWithFocusAt:(CGFloat)focusY bubbleSize:(CGFloat)bubble slowAnim:(BOOL)slow
+- (void)foldWithFocusAt:(CGFloat)focusY inBubble:(CGFloat)bubbleSize withDensity:(CGFloat)density slowAnim:(BOOL)slow
 {
-	CGFloat y = [self yForFocusY:focusY inBubble:bubble];
-	CATransform3D t = [self transformForFocusY:focusY inBubble:bubble];
+	CGFloat y = [self yForFocusY:focusY inBubble:bubbleSize withDensity:density];
+	CATransform3D t = [self transformForFocusY:focusY inBubble:bubbleSize withDensity:density];
 	
 	// animate transformation
 	[UIView animateWithDuration:(slow ? 0.3 : 0.05)
  *	Given a focus Y returns our corresponding y position, calculated from our targetY
  *	@attention targetY must have been set when calling this method
  */
-- (CGFloat)yForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize
+- (CGFloat)yForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize withDensity:(CGFloat)density
 {
-	CGFloat distance = targetY - focusY;
+	CGFloat expFraction = [self fractionForFocusY:focusY withDensity:density];
 	
 	// calculate position
-	CGFloat frac = fminf(1.f, fmaxf(0.f, 0.5f - (0.5f * distance / bubbleSize)));
-	CGFloat amount = exponentialEaseInOut(frac);
-	distance += 0.5f * bubbleSize - amount * bubbleSize;
+	CGFloat distance = 0.5f * bubbleSize - (expFraction * bubbleSize);
 	
 	focusY += distance;
 	return roundf(focusY);
  *	Returns the transformation suitable for the given focus y position. Do NOT use the transformed focusY!
  *	@attention targetY must have been set when calling this method
  */
-- (CATransform3D)transformForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize
+- (CATransform3D)transformForFocusY:(CGFloat)focusY inBubble:(CGFloat)bubbleSize withDensity:(CGFloat)density
 {
-	CGFloat distance = targetY - focusY;
+	CGFloat expFraction = [self fractionForFocusY:focusY withDensity:density];
 	
-	// calculate fold amount
-	CGFloat foldAmount = 0.4f;
-	if (distance > 0.f) {
-		foldAmount += fminf(1.f, fabs(distance / bubbleSize)) * 0.5f;				// to smooth between 0.4f and 0.9f
-	}
+	// calculate fold amount (smooth between 0.1 and 0.9)
+	CGFloat foldAmount = 0.9f;
+	foldAmount -= expFraction * 0.8f;
 	
 	// create a transformation
 	CATransform3D t = CATransform3DIdentity;
 	t.m34 = 1.f / (-3 * [self bounds].size.height);
 	t = CATransform3DRotate(t, -M_PI_2 * foldAmount, 1.f, 0.f, 0.f);
-	t = CATransform3DScale(t, 0.9f, 0.9f, 1.f);
+	CGFloat scale = 0.89f + (expFraction * 0.07f);
+	t = CATransform3DScale(t, scale, scale, 1.f);
 	
 	return t;
 }
 
 
+- (CGFloat)fractionForFocusY:(CGFloat)focusY withDensity:(CGFloat)density
+{
+	NSUInteger num = 10;
+	CGFloat distIndex = (targetY - focusY) / density;
+	CGFloat fraction = fminf(1.f, fmaxf(0.f, (num/2 - distIndex) / num));
+	
+	return exponentialEaseInOut(fraction);
+}
+
+
 
 #pragma mark - Drawing
 - (void)drawRect:(CGRect)rect
 CGFloat exponentialEaseInOut(CGFloat t)
 {
 	t = fminf(fmaxf(t, 0.f), 1.f);
+	CGFloat strength = 5.f;
 	
 	t *= 2.f;
 	if (t < 1.f) {
-		return 1.f / 2.f * powf(2.f, 20.f * (t - 1.f) );
+		return 1.f / 2.f * powf(2.f, strength * (t - 1.f) );
 	}
 	t--;
-	return 1.f / 2.f * ( -powf(2.f, -20.f * t) + 2.f );
+	return 1.f / 2.f * ( -powf(2.f, -strength * t) + 2.f );
 }
 

ThumbScrolling/PPTSView.m

 {
     if ((self = [super initWithFrame:aFrame])) {
 		self.backgroundColor = [UIColor colorWithWhite:0.f alpha:0.25f];
-		bubbleSize = 40.f;
+		bubbleSize = 80.f;
     }
     return self;
 }
 		active.frame = rowFrame;
 		active.targetY = newY;			/// @todo use density and offset to determine the correct target location
 		active.center = CGPointMake(rowFrame.size.width / 2, newY);
-		active.layer.transform = [active transformForFocusY:newY inBubble:bubbleSize];
+		active.layer.transform = [active transformForFocusY:newY inBubble:bubbleSize withDensity:density];
 		
 		[self addSubview:active];
 	}
-	[active foldWithFocusAt:newY bubbleSize:bubbleSize slowAnim:beginning];
+	[active foldWithFocusAt:newY inBubble:bubbleSize withDensity:density slowAnim:beginning];
 	
 	
 	// update later cell values
 					next.center = CGPointMake(rowFrame.size.width / 2, active.center.y + dist * rowFrame.size.height);
 				}
 				else {
-					next.center = CGPointMake(rowFrame.size.width / 2, [next yForFocusY:newY inBubble:bubbleSize]);
-					next.layer.transform = [next transformForFocusY:newY inBubble:bubbleSize];
+					next.center = CGPointMake(rowFrame.size.width / 2, [next yForFocusY:newY inBubble:bubbleSize withDensity:density]);
+					next.layer.transform = [next transformForFocusY:newY inBubble:bubbleSize withDensity:density];
 				}
 				next.prev = lastValid;
 				
 				next.indexPath = indexPath;
 				[next setupWithCell:[mapping objectForKey:indexPath] reference:active];
 			}
-			[next foldWithFocusAt:newY bubbleSize:bubbleSize slowAnim:beginning];
+			[next foldWithFocusAt:newY inBubble:bubbleSize withDensity:density slowAnim:beginning];
 			
 			lastValid = next;
 			next = next.next;
 					previous.center = CGPointMake(rowFrame.size.width / 2, active.center.y - dist * rowFrame.size.height);
 				}
 				else {
-					previous.center = CGPointMake(rowFrame.size.width / 2, [previous yForFocusY:newY inBubble:bubbleSize]);
-					previous.layer.transform = [previous transformForFocusY:newY inBubble:bubbleSize];
+					previous.center = CGPointMake(rowFrame.size.width / 2, [previous yForFocusY:newY inBubble:bubbleSize withDensity:density]);
+					previous.layer.transform = [previous transformForFocusY:newY inBubble:bubbleSize withDensity:density];
 				}
 				previous.next = lastValid;
 				
 				previous.indexPath = indexPath;
 				[previous setupWithCell:[mapping objectForKey:indexPath] reference:active];
 			}
-			[previous foldWithFocusAt:newY bubbleSize:bubbleSize slowAnim:beginning];
+			[previous foldWithFocusAt:newY inBubble:bubbleSize withDensity:density slowAnim:beginning];
 			
 			lastValid = previous;
 			previous = previous.prev;