Skip to content

Commit d45d28c

Browse files
committed
Fix Channel List shimmering effect and improve shimmering animation
1 parent adc9c61 commit d45d28c

File tree

2 files changed

+23
-51
lines changed

2 files changed

+23
-51
lines changed

Sources/StreamChatSwiftUI/CommonViews/LoadingView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ public struct RedactedLoadingView<Factory: ViewFactory>: View {
2828
searchText: .constant("")
2929
)
3030

31-
VStack(spacing: 0) {
31+
LazyVStack(spacing: 0) {
3232
ForEach(0..<20) { _ in
3333
RedactedChannelCell()
34+
.shimmering()
3435
Divider()
3536
}
3637
}
37-
.shimmering()
3838
}
3939
}
4040
.accessibilityIdentifier("RedactedLoadingView")
@@ -52,7 +52,7 @@ struct RedactedChannelCell: View {
5252
}
5353

5454
public var body: some View {
55-
HStack {
55+
HStack(alignment: .center) {
5656
Circle()
5757
.fill(redactedColor)
5858
.frame(width: circleSize, height: circleSize)

Sources/StreamChatSwiftUI/CommonViews/Shimmer.swift

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,63 +5,35 @@
55
import SwiftUI
66

77
struct Shimmer: ViewModifier {
8-
@State private var phase: CGFloat = 0
9-
var duration = 1.5
10-
var delay = 0.25
8+
/// The duration of a shimmer cycle in seconds. Default: `1.5`.
9+
var duration: Double = 1.5
10+
/// The delay until the animation re-starts.
11+
var delay: Double = 0.25
12+
13+
@State private var isInitialState = true
1114

1215
public func body(content: Content) -> some View {
1316
content
14-
.modifier(AnimatedMask(phase: phase))
15-
.animation(
16-
.linear(
17-
duration: duration
17+
.mask(
18+
LinearGradient(
19+
gradient: .init(colors: [.black.opacity(0.4), .black, .black.opacity(0.4)]),
20+
startPoint: (isInitialState ? .init(x: -0.3, y: -0.3) : .init(x: 1, y: 1)),
21+
endPoint: (isInitialState ? .init(x: 0, y: 0) : .init(x: 1.3, y: 1.3))
1822
)
19-
.delay(delay)
20-
.repeatForever(
21-
autoreverses: false
22-
),
23-
value: phase == 0.0
2423
)
25-
.onAppear { phase = 0.8 }
26-
}
27-
28-
/// An animatable modifier to interpolate between `phase` values.
29-
struct AnimatedMask: AnimatableModifier {
30-
var phase: CGFloat = 0
31-
32-
var animatableData: CGFloat {
33-
get { phase }
34-
set { phase = newValue }
35-
}
36-
37-
func body(content: Content) -> some View {
38-
content
39-
.mask(GradientMask(phase: phase).scaleEffect(3))
40-
}
41-
}
42-
43-
/// A slanted, animatable gradient between transparent and opaque to use as mask.
44-
/// The `phase` parameter shifts the gradient, moving the opaque band.
45-
struct GradientMask: View {
46-
let phase: CGFloat
47-
let centerColor = Color.black
48-
let edgeColor = Color.black.opacity(0.3)
49-
50-
var body: some View {
51-
LinearGradient(
52-
gradient:
53-
Gradient(stops: [
54-
.init(color: edgeColor, location: phase),
55-
.init(color: centerColor, location: phase + 0.1),
56-
.init(color: edgeColor, location: phase + 0.2)
57-
]),
58-
startPoint: .topLeading,
59-
endPoint: .bottomTrailing
24+
.animation(
25+
.linear(duration: duration)
26+
.delay(delay)
27+
.repeatForever(autoreverses: false),
28+
value: isInitialState
6029
)
61-
}
30+
.onAppear {
31+
isInitialState = false
32+
}
6233
}
6334
}
6435

36+
6537
extension View {
6638
/// Adds an animated shimmering effect to any view, typically to show that
6739
/// an operation is in progress.

0 commit comments

Comments
 (0)