Enabling Touch Animations for JJCollectionViewRoundFlowLayout Decoration Views: Implementation Guide

To enable touch animations for decoration views in JJCollectionViewRoundFlowLayout, set the isDecorationViewTouchAnimationEnable property to YES on your layout instance, or implement the delegate methods isDecorationViewShowAnimationAtIndex: and animationConfigModelForSection: to control animations per section with custom scaling and duration parameters.

JJCollectionViewRoundFlowLayout is an iOS library that adds rounded background decoration views behind collection view sections. According to the source code in kingjiajie/jjcollectionviewroundflowlayout, these decoration views support a built-in touch animation system that scales the background (and optionally the cells) when the user interacts with them. This guide explains the complete animation pipeline and provides production-ready implementation patterns.

Understanding the Touch Animation Architecture

The touch animation system consists of three core components that work together to provide both global and per-section control.

isDecorationViewTouchAnimationEnable is a Boolean property defined in JJCollectionViewRoundFlowLayout.h that acts as a master switch. When set to YES, all decoration views in the collection view become eligible for touch animations using default parameters.

JJCollectionViewTouchAnimationConfigModel (defined in JJCollectionViewTouchAnimationConfigModel.h) stores the animation parameters including transformScaleSx, transformScaleSy, startDuration, endDuration, and isCellsAnimationEnable. This model allows you to customize the scale factor and timing for individual sections.

Delegate callbacks in the JJCollectionViewDelegateRoundFlowLayout protocol provide granular control. The isDecorationViewShowAnimationAtIndex: method determines whether a specific section should animate, while animationConfigModelForSection: returns a custom configuration model for that section.

How Touch Animations Work Internally

The animation pipeline executes across three distinct phases within the library's source files.

Layout Preparation Phase

During prepareLayout in JJCollectionViewRoundFlowLayout.m (lines 99-121), the layout creates JJCollectionViewRoundLayoutAttributes for each section's decoration view. If isDecorationViewTouchAnimationEnable is YES, the layout sets attr.isTouchAnimationEnable = YES and attaches a configuration model. When the global flag is NO, the layout checks the delegate method isDecorationViewShowAnimationAtIndex: to determine eligibility per section.

Touch Event Handling

The actual animation logic resides in JJCollectionReusableView.m. When a touch begins, touchesBegan: triggers touchAnimationEventWithScaleSxPoint:scaleSyPoint:duration:isCellsAnimationEnable: using the start values from the configuration model. When the touch ends or cancels (touchesEnded: or touchesCancelled:), the method executes again with end values (typically restoring scale to 1.0).

According to lines 88-115 of the implementation, this method performs a UIView animation on the decoration view itself. When isCellsAnimationEnable is set to YES in the configuration model, the animation concurrently scales every visible cell belonging to the same section.

Selection Callback

After a tap completes, decorationViewUserDidSelectEvent forwards the event to the optional delegate method collectionView:didSelectDecorationViewAtIndexPath: (lines 23-30 in JJCollectionReusableView.m), allowing you to respond to user interaction after the animation finishes.

Global Enablement with Default Animations

For simple implementations where all sections should use identical animation behavior, enable the feature globally on the layout instance.

// In your view controller setup
JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
layout.isDecorationViewTouchAnimationEnable = YES;

// The layout uses default JJCollectionViewTouchAnimationConfigModel 
// values (scale 0.98, 0.3s duration) automatically
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds
                                                    collectionViewLayout:layout];

This approach requires no delegate implementation. The layout automatically applies a subtle scale-down effect (0.98x) with 0.3-second animation durations to all section backgrounds when touched.

Per-Section Control with Custom Parameters

For advanced use cases requiring different animation styles per section, implement the JJCollectionViewDelegateRoundFlowLayout protocol methods.

First, adopt the protocol in your view controller:

@interface MyViewController () <JJCollectionViewDelegateRoundFlowLayout>
@end

Then implement the delegate methods to conditionally enable animations and return custom configuration models:

- (BOOL)collectionView:(UICollectionView *)cv
                layout:(UICollectionViewLayout *)layout
isDecorationViewShowAnimationAtIndex:(NSInteger)section {
    // Enable animation only for even sections
    return (section % 2 == 0);
}

- (JJCollectionViewTouchAnimationConfigModel *)collectionView:(UICollectionView *)cv
                                                       layout:(UICollectionViewLayout *)layout
                                   animationConfigModelForSection:(NSInteger)section {
    JJCollectionViewTouchAnimationConfigModel *model = [JJCollectionViewTouchAnimationConfigModel createDefaultModel];
    
    // Create a "bouncy" press effect
    model.transformScaleSx = 0.92;
    model.transformScaleSy = 0.92;
    model.startDuration = 0.15;
    model.endDuration = 0.25;
    model.isCellsAnimationEnable = YES;  // Animate cells along with background
    
    return model;
}

The createDefaultModel class method provides a baseline configuration that you can modify before returning. When isCellsAnimationEnable is YES, the entire section including all visible cells scales together, creating a cohesive pressed state.

Handling Decoration View Selection

To receive callbacks when users tap the decoration view background, implement the selection delegate method:

- (void)collectionView:(UICollectionView *)cv
   didSelectDecorationViewAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"User tapped decoration view in section %ld", (long)indexPath.section);
    // Navigate to detail view or update UI state
}

This method fires after the touch animation completes, ensuring the visual feedback finishes before your logic executes.

Creating Reusable Animation Configurations

For applications using consistent animation styles across multiple view controllers, factory methods provide clean code reuse:

@implementation JJCollectionViewTouchAnimationConfigModel (CustomConfigs)

+ (instancetype)heavyPressConfig {
    JJCollectionViewTouchAnimationConfigModel *model = [self createDefaultModel];
    model.transformScaleSx = 0.90;
    model.transformScaleSy = 0.90;
    model.startDuration = 0.1;
    model.endDuration = 0.2;
    model.isCellsAnimationEnable = NO;
    return model;
}

@end

Return this custom instance from your delegate's animationConfigModelForSection: method whenever you need the "heavy press" effect.

Summary

  • Global activation requires only setting isDecorationViewTouchAnimationEnable = YES on the JJCollectionViewRoundFlowLayout instance.
  • Per-section customization implements isDecorationViewShowAnimationAtIndex: and animationConfigModelForSection: in the delegate protocol.
  • Animation parameters including scale factors, durations, and cell participation are controlled via JJCollectionViewTouchAnimationConfigModel.
  • Touch handling occurs in JJCollectionReusableView.m using UIView animations triggered by touchesBegan: and touchesEnded:.
  • Selection detection uses the collectionView:didSelectDecorationViewAtIndexPath: delegate callback defined in JJCollectionViewRoundFlowLayout.h.

Frequently Asked Questions

How do I disable touch animations for specific sections while keeping them enabled globally?

Set layout.isDecorationViewTouchAnimationEnable = YES to enable the feature globally, then implement the delegate method isDecorationViewShowAnimationAtIndex: and return NO for sections that should not animate. This method is checked in JJCollectionViewRoundFlowLayout.m (lines 99-121) when the global flag is disabled or when determining per-section eligibility.

Can I animate the cells inside the section when touching the decoration view?

Yes. Set the isCellsAnimationEnable property to YES on your JJCollectionViewTouchAnimationConfigModel before returning it from the delegate. When this flag is enabled, the touchAnimationEventWithScaleSxPoint:… method in JJCollectionReusableView.m (lines 88-115) applies the same scale transform to all visible cells in the section simultaneously with the decoration view.

What are the default animation values if I don't provide a custom configuration model?

If you enable touch animations globally without implementing animationConfigModelForSection:, the layout uses the default model created by [JJCollectionViewTouchAnimationConfigModel createDefaultModel]. This typically applies a subtle scale of 0.98x with 0.3-second animation durations for both the start (press down) and end (release) states.

Why isn't my didSelectDecorationViewAtIndexPath: delegate method being called?

Ensure your view controller conforms to JJCollectionViewDelegateRoundFlowLayout and that you have set the collection view's delegate property. The callback originates from decorationViewUserDidSelectEvent in JJCollectionReusableView.m (lines 23-30), which only executes if the delegate responds to the selector after the touch animation sequence completes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →