I've got a ViewController class and a View class. The ViewController has a UIScrollView and the View has a UITableView, and both are delegates of UIScrollViewDelegate.
Both the View and the ViewController make use of the scrollViewDidScroll:
delegate method, and both have the same code in it. It's clearly a duplication so I'd like to fix this.
The problem is I've no idea how.
I can't extract the functionality into a base class and I also don't think I can have a separate class implementing the method, whose instances I could then use (it's possible in Android but not in iOS). I was thinking of using blocks but don't see how they'd work here.
The method itself performs some changes on the UI of the ViewController/View; here's its body:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float multiplierYAnimationStop = [Utilities getFloatValueFromPlistFile:@"layout_values" forDictionaryKey:@"scroll_background_y_stop_multiplier"];
float currentScrollOffsetY = scrollView.contentOffset.y;
// No case for further back than the bottom of the screen (lower than 0)
// and if it's higher than where it should stop, keep it at that point
if (currentScrollOffsetY > screenHeight * multiplierYAnimationStop) {
currentScrollOffsetY = screenHeight * multiplierYAnimationStop;
}
// Scale the background
float newBackgroundScale = 1 - currentScrollOffsetY / screenHeight;
if (newBackgroundScale < 0.75f) {
newBackgroundScale = 0.75f;
}
[self scaleBackgroundToNewScale:newBackgroundScale];
// Move the UILabel with the title and the Button
float newLabelCenterY = originalLabelTitleCentreY - currentScrollOffsetY;
float newButtonCenterY = originalButtonDownArrowCentreY - currentScrollOffsetY;
self.labelHeadline.center = CGPointMake(self.labelHeadline.center.x, newLabelCenterY);
self.buttonDownArrow.center = CGPointMake(self.buttonDownArrow.center.x, newButtonCenterY);
// Blur the UILabel with the title and the Button
float newHeadlineAlpha = 1 - currentScrollOffsetY / 100.0f;
if (newHeadlineAlpha < 0.0f) {
newHeadlineAlpha = 0.0f;
}
[self.labelHeadline setAlpha:newHeadlineAlpha];
[self.buttonDownArrow setAlpha:newHeadlineAlpha];
if (newHeadlineAlpha < 0.95f) {
[self.buttonDownArrow setEnabled:NO];
}
else {
[self.buttonDownArrow setEnabled:YES];
}
// Set the new alpha for the background overlay
// (no bigger than scroll_overlay_max_opacity, should be scroll_overlay_max_opacity once the offset hits the stop point)
float maxOpacity = [Utilities getFloatValueFromPlistFile:@"layout_values" forDictionaryKey:@"scroll_overlay_max_opacity"];
float subtractionFactor = 1.0f - maxOpacity;
float newOverlayAlpha = currentScrollOffsetY / screenHeight / multiplierYAnimationStop - subtractionFactor;
if (newOverlayAlpha > maxOpacity) {
newOverlayAlpha = maxOpacity;
}
[self.viewOverlay setAlpha:newOverlayAlpha];
// If set, move the background vertically on scroll
if ([Utilities getBoolValueFromPlistFile:@"layout_values" forDictionaryKey:@"is_scroll_background_movable"]) {
if (newBackgroundScale == 0.75f) {
self.imageBackground.center = CGPointMake(self.imageBackground.center.x, self.imageBackground.center.y - (currentScrollOffsetY - 0.25f * screenHeight));
}
}
}
Create a function that encapsulates what you want, and pass any needed variables (possibly including self
) to it.
If you have more duplicated logic between your objects, you can pull that together into a strategy object that both object have an instance of (rather than inheriting from). Essentially this would be a delegate for your delegate (which is fine). Or if you have a collection of related shared functions you could make them class methods of some strategy class. But if it's just a single method like this, a function is fine.