首页 > 解决方案 > 如何在 SwiftUI 中的动态可滚动路径中设置最后一个元素的偏移量

问题描述

我正在尝试构建一个具有连续路径的视图作为滚动视图中的图形。

我正在从 BLE 设备接收数据并将它们转换为基于时间戳的向量。虽然矢量在宽度上随时间增长,但我想在 scrollView 中跟随它。我厌倦了 ScrollViewReader 的实现,但没有运气,因为如果我理解得很好,我应该有我想要滚动到的元素的 id。据我所知,这是不可能的,因为整个信号是一次绘制的一条路径。

我试图根据最后一个元素宽度设置 uiScrollView 的偏移量,但我无法让 scrollView 增长,因为带有图表的路径是......

我使用了 uiScrollView 包装器的实现:https ://gist.github.com/jfuellert/67e91df63394d7c9b713419ed8e2beb7

在其中,我正在绘制基于值和常量值的路径作为 xStep

结构线图:形状{

let geoProxy: GeometryProxy
@Binding var lead: ECGLead
@Binding var timestamps: [Int]
var n: vDSP_Length{
    return vDSP_Length(lead.channelVector.count)
}


let stride = vDSP_Stride(1)
var xPosition: Binding<CGFloat>
func path(in rect: CGRect) -> Path {
    
    Path { path in
        
        let xStep = 0.00015 * geoProxy.size.width
        var currentX: CGFloat = xStep
        let signal = transformIntoSignal(lead: lead , timestamps: timestamps)
        
        
        path.move(to: .zero)
        //if signal.count
        signal.forEach{ signalValue in
            //let yStep = CGFloat($0) * geoProxy.frame(in: .local).height
            //print("X: \(currentX) Y: \($0)")
            path.addLine(to: CGPoint(x: currentX, y: CGFloat(signalValue)))
            currentX += xStep
            print("Last x: \(currentX)")
            
            //print("Checking xStep = \(currentX)")
        }
    }
}
func transformIntoSignal(lead: ECGLead, timestamps: [Int]) -> [Float] {
    var outputSignal = [Float](repeating: 0,
                               count: Int(n))
    
    let time = timestamps.map{Float($0)}
    
    
    vDSP_vgenp(lead.channelVector, stride,
               time, stride,
               &outputSignal, stride,
               vDSP_Length(lead.channelVector.count),
               vDSP_Length(timestamps.count))
    
    return outputSignal
    
}

}

有了这条路径,我试图给它 maxWidth = .inifity 以便能够在 scrollView 中增长

       ZStack(){
            
            
            RoundedRectangle(cornerRadius: 8)
                .frame(minWidth: 120, idealWidth: 170, maxWidth: .infinity, minHeight: 60, idealHeight: 90, maxHeight: 90, alignment: .center)
                .foregroundColor(.white)
            
                .overlay(
                    ScrollableView($lineOffset, animationDuration: TimeInterval(1), content: {
                            //HStack{
                        LineChart(vector: animatableVector, geoProxy: geoProxy,lead: $ecgLead,timestamps: $timeStamps, xPosition: $lastPointX)
                                    .stroke(appGreen, lineWidth: 1)
                                    .frame(minWidth: 120, idealWidth: 170, maxWidth: .infinity, minHeight: 35, idealHeight: 40, maxHeight: 50,alignment: Alignment(horizontal: .leading, vertical: .center))
                        
                        })//.frame(minWidth: 120, idealWidth: 170, maxWidth: .infinity, minHeight: 35, idealHeight: 50, maxHeight: 60,alignment: Alignment(horizontal: .leading, vertical: .center))

                )

使用 uiScrollView 包装器,我尝试以编程方式滚动到内容偏移量,但每次我看到围绕某个中间值的跳转视图并连续结束。

这是上面提到的 UIkit 包装器的更新方法:

 func updateUIViewController(_ viewController: UIViewControllerType, context: UIViewControllerRepresentableContext<Self>) {
    
    viewController.scrollView.showsVerticalScrollIndicator   = self.showsScrollIndicator
    viewController.scrollView.showsHorizontalScrollIndicator = self.showsScrollIndicator
    viewController.updateContent(self.content)
    viewController.scrollView.invalidateIntrinsicContentSize()
    let lastPoint = viewController.scrollView.contentSize.width
    let lastPointOffset = viewController.scrollView.contentOffset.x
    let tmp = viewController.scrollView.visibleSize.width
    let contentWidth = viewController.scrollView.bounds.width
    print("Check last point: \(lastPoint)")
    print("Check last point offset: \(lastPointOffset)")
    print("Check tmp: \(contentWidth)")
    viewController.scrollView.setContentOffset(CGPoint(x: lastPoint, y: 0), animated: true)
    viewController.scrollView.bounds.width
    
    let duration: TimeInterval                = self.duration(viewController)
    let newValue: CGPoint                     = self.offset.wrappedValue
    viewController.scrollView.isScrollEnabled = !self.disableScroll
    
    if self.stopScrolling.wrappedValue {
        viewController.scrollView.setContentOffset(viewController.scrollView.contentOffset, animated:true)
        return
    }
    
    guard duration != .zero else {
        viewController.scrollView.contentOffset = newValue
        return
    }
    
    UIView.animate(withDuration: duration, delay: 0, options: [.allowUserInteraction, .curveEaseInOut, .beginFromCurrentState], animations: {
        viewController.scrollView.contentOffset = newValue
    }, completion: nil)
}

我的问题是如何使滚动始终专注于滚动视图中此信号的增长数组的最后一个元素。它不工作是因为某处宽度没有正确增长吗?还是我在某个地方误解了?现在我不知道从哪里继续

提前感谢您回答我的问题。任何帮助都会非常感激:)

标签: swiftswiftuiuiscrollviewuikitinfinite-scroll

解决方案


推荐阅读