Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add shimmer view modifier and SkeletonLoading component #54

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

NikolaiMadlener
Copy link

@NikolaiMadlener NikolaiMadlener commented Jan 13, 2025

Add shimmer view modifier and SkeletonLoading component

♻️ Current situation & Problem

This PR addresses issue #52 by introducing a shimmer modifier that can be applied to a view, enabling it to shimmer periodically. When used in combination with the ProcessingOverlay, this modifier can now facilitate the implementation of a skeleton loading view.

For more convenience, a SkeletonLoading view has been introduced to automatically render shimmering cells vertically.

⚙️ Release Notes

For instance, if you have a custom skeleton view (e.g. a shape you want to display as the loading indicator), you can implement a skeleton loading like so:

ExampleAsyncView()
    .processingOverlay(isProcessing: loading) {
        CustomSkeletonView()
            .shimmer(repeatInterval: 1)
    }

You could also use the provided SkeletonLoading view if you don't need the full customizability of above's solution. You can just pass your custom skeleton cell and the SkeletonLoading will take care of shimmering and vertically displaying the cells. You can also optionally pass the amount of cells that should be rendered as well as the repeat interval of the shimmer effect.

ExampleAsyncView()
    .processingOverlay(isProcessing: loading) {
        SkeletonLoading(cellCount: 5, shimmerRepeatInterval: 1.5) {
            CustomSkeletonCell()
        }
    }

📚 Documentation

Two new sections "Loading Indicators" and "Animations and Visual Effects" has been added to the docc that features the SkeletonLoading view and Shimmer modifier.

📝 Code of Conduct & Contributing Guidelines

By submitting creating this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

@NikolaiMadlener NikolaiMadlener linked an issue Jan 13, 2025 that may be closed by this pull request
1 task
@NikolaiMadlener NikolaiMadlener changed the title Add blinking view modifier Add shimmer view modifier Jan 14, 2025
@NikolaiMadlener NikolaiMadlener self-assigned this Jan 14, 2025
@NikolaiMadlener NikolaiMadlener added the enhancement New feature or request label Jan 14, 2025
@NikolaiMadlener NikolaiMadlener changed the title Add shimmer view modifier Add shimmer view modifier and SkeletonLoading component Jan 14, 2025
Copy link
Member

@Supereg Supereg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR. Thanks for spending the effort of integrating the new components into the DocC and providing all the detailed code examples.

Just had a few comments here and there. Nothing major that should you stop from merging. I had one more "explorative" comment that aims to see how this API would differentiate itself from e.g. the SwiftUI redaction API.

import SwiftUI


public struct SkeletonLoading<SkeletonCell: View>: View {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can get a least maybe a short "Overview" description such that something shows up in the DocC section.
Maybe it is worth moving the detailed example to the here just because it might be more discoverable for people?

/// - cellCount: The number of skeleton cells to display.
/// - shimmerRepeatInterval: The repeat interval for the shimmer animation.
/// - skeletonCell: A closure returning the skeleton cell view.
public init(cellCount: Int = 3, shimmerRepeatInterval: Double = 1, skeletonCell: @escaping () -> SkeletonCell) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a default of 1 make more sense? Just thought about the use case where you might want to have e.g. multiple different Cells with different width (e.g., one shorter one for the header. You would probably achieve this by place multiple "SkeletonLoading" views each with a different configuration. In this setting y default cellCount value of 1 just feels more natural to me? But also not a a strong opinion here.


public var body: some View {
VStack(spacing: 16) {
ForEach(0..<cellCount, id: \.self) { _ in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we might want to make sure that we do not allow cellCount values below 0 and automatically correct them to zero. Otherwise this ends up crashing the application in the range expression above.

Comment on lines +47 to +51
/// SkeletonLoading(cellCount: 5, shimmerRepeatInterval: 1.5) {
/// RoundedRectangle(cornerRadius: 10)
/// .fill(secondaryColor)
/// .frame(height: 100)
/// }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, how is this API different to the redaction API provided by SwiftUI natively? E.g., https://developer.apple.com/documentation/swiftui/view/redacted(reason:). Just out of interest to understand where your use is coming from. I know that the redaction API doesn't support any "shimmering" effects out of the box. Not sure how SwiftUI redaction handles accessibility as well and what traits it might add. I assume the SkeletonLoading view would not be visible to VoiceOver at all, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Skeleton Loading View
2 participants