Home > Software engineering >  Swift UI - UltraThinMaterial Glitch on Moving Views
Swift UI - UltraThinMaterial Glitch on Moving Views

Time:05-29

When I move a view with ultra thin material background, it turns black. Is it a bug or am I doing something wrong?

Is there a workaround to achieve this view on a moving view?

I noticed only happens when there is angular motion. If I delete rotation effect the problem goes away.

Testable code:

struct Test: View {
    
    @State var offset: CGFloat = 0
    @GestureState var isDragging: Bool = false
    
    var body: some View {
        GeometryReader { reader in
            ZStack {
                Image(systemName: "circle.fill")
                    .font(.largeTitle)
                    .frame(width: 300, height: 300)
                    .background(.red)
                    .overlay(alignment: .bottom) {
                        Rectangle()
                            .frame(height: 75)
                            .background(.ultraThinMaterial)
                    }
                    .clipShape(
                        RoundedRectangle(cornerRadius: 15, style: .continuous)
                    )
                    .compositingGroup()
                    .offset(x: offset)
                    .rotationEffect(.degrees(getRotation(angle: 8)))
                    .compositingGroup()
                    .gesture(
                        DragGesture()
                            .updating($isDragging) { _, state, _ in
                                state = true
                            }
                            .onChanged { value in
                                let translation = value.translation.width
                                offset = (isDragging ? translation : .zero)
                            }
                            .onEnded { value in
                                let width = getRect().width
                                let translation = value.translation.width

                                let checkingStatus = translation > 0 ? translation : -translation

                                withAnimation {
                                    if checkingStatus > (width / 2) {
                                        offset = (translation > 0 ? width : -width) * 2
                                    } else {
                                        offset = 0
                                    }
                                }
                            }
                    )
                    
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
    
    private func getRotation(angle: Double) -> Double {
        let rotation = (offset / getRect().width) * angle
        return rotation
    }
}

enter image description here

CodePudding user response:

Code is not testable so hard to say definitely, but

  1. try to move all that image with modifiers into separated standalone view

  2. try composite it

     .clipShape(
         RoundedRectangle(cornerRadius: 15, style: .continuous)
     )
     .compositingGroup()       // << here !!
     .offset(y: -topOffset)
    
  • Related