0

I am trying to implement Uber trip like screen, and I have used the code below

public struct OverlappingPanView<BGView, PanContentView>: View
where BGView: View, PanContentView: View {
    public var backgroundView: () -> BGView
    public var panContentView: () -> PanContentView
    public init(backgroundView: @escaping () -> BGView, panContentView: @escaping () -> PanContentView) {
        self.backgroundView = backgroundView
        self.panContentView = panContentView
    }
    enum OffsetError : Error{
        case TopBoundExceded
        case BottomBoundExceded
    }

//MARK: - State Property Variables
@GestureState private var dragOffset: CGFloat = 0
@State private var lastEndedOffset: CGFloat = 0
@State private var panFrame: CGSize = .zero

//MARK: - Getters
var staticTopPadding: CGFloat{
    let screenPadding = UIScreen.main.bounds.height * 0.4
    let actualFrame = (panFrame.height - screenPadding)
    let extraCorrection = actualFrame * 0.5
    return screenPadding + extraCorrection
}
private var currentPaddingValue: CGFloat{
    return dragOffset + lastEndedOffset + staticTopPadding
}
private var difference: CGFloat{
    return 200
}

//MARK: - Body
public var body: some View {
    ZStack {
        backgroundView()
            .edgesIgnoringSafeArea(.all)
        
            panControllerView()
    }
}
func panControllerView() -> some View{
    panContentView()
        .background(
            GeometryReader { geo -> Color in
                DispatchQueue.main.async {
                    self.panFrame = geo.size
                }
                return Color.clear
            }
        )
        .frame(minHeight: 0, maxHeight: .infinity)
        .offset(y: dragOffset + lastEndedOffset + staticTopPadding)
        .animation(.interactiveSpring())
        .highPriorityGesture(
            DragGesture(coordinateSpace: CoordinateSpace.global)
                .updating($dragOffset) { (value, state, _) in
                    if let endValue = try? self.canDrag(value.translation.height){
                        state = endValue
                    }
                    
                }
                .onEnded { value in
                    self.onDragEnd(value.translation.height)
                }
        )
    
}
func onDragEnd(_ value: CGFloat){
    withAnimation {
        do{
            let endValue = try self.canDrag(value)
            self.lastEndedOffset = lastEndedOffset + endValue
        }catch OffsetError.BottomBoundExceded{
            self.lastEndedOffset = 0
        }catch OffsetError.TopBoundExceded{
            
            self.lastEndedOffset = -(self.panFrame.height - difference)
        }catch{
            self.lastEndedOffset = 0
        }
    }
}
func canDrag(_ value: CGFloat) throws -> CGFloat{
    let newValue = value + lastEndedOffset + staticTopPadding
    // stop going below
    guard newValue <= staticTopPadding else{
        throw OffsetError.BottomBoundExceded
    }
    let topCalculation = (self.panFrame.height + (value + self.lastEndedOffset)) - difference

    // stop going top
    guard topCalculation >= 0 else{
        throw OffsetError.TopBoundExceded
    }
    return value
    
}
  
}

and Used the above code to show mapview in the background and ForEach content on the front.

OverlappingPanView {
     GoogleMapView(delegate: presenter)
} panContentView: {
   contentView() // ForEach looped data Views
}

The list that I have provided in content View is leaking memory and uses high CPU (above 100%) when dragging leading to UI Performance issues.

AlbinMrngStar
  • 289
  • 2
  • 13

0 Answers0