如何修改ScrollableUIView实现内容尺寸变更后重置缩放平移状态?
修复ScrollableUIView在内容尺寸变化时的状态重置问题
直接修改ScrollableUIView的display方法,在传入新的size或containerSize时手动重置滚动视图的缩放、偏移及内容布局状态,无需重建整个组件。以下是具体实现:
class ScrollableUIView: UIView, UIScrollViewDelegate { private let scrollView = UIScrollView() private var contentView: UIView? // 记录当前的内容尺寸和容器尺寸,用于判断是否需要重置 private var lastContentSize: CGSize = .zero private var lastContainerSize: CGSize = .zero override init(frame: CGRect) { super.init(frame: frame) setupScrollView() } required init?(coder: NSCoder) { super.init(coder: coder) setupScrollView() } private func setupScrollView() { scrollView.delegate = self scrollView.showsVerticalScrollIndicator = false scrollView.showsHorizontalScrollIndicator = false scrollView.translatesAutoresizingMaskIntoConstraints = false addSubview(scrollView) NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: topAnchor), scrollView.leadingAnchor.constraint(equalTo: leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } func display(_ view: UIView, size: CGSize, containerSize: CGSize) { // 仅当尺寸发生变化时执行重置逻辑 guard size != lastContentSize || containerSize != lastContainerSize else { return } // 更新记录的尺寸 lastContentSize = size lastContainerSize = containerSize // 替换内容视图 contentView?.removeFromSuperview() contentView = view view.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(view) // 计算Aspect Fit的初始缩放比例 let widthScale = containerSize.width / size.width let heightScale = containerSize.height / size.height let initialScale = min(widthScale, heightScale) // 重置内容视图的缩放和布局 view.transform = .identity view.frame = CGRect(origin: .zero, size: size) view.transform = CGAffineTransform(scaleX: initialScale, y: initialScale) // 重置滚动视图的缩放参数 scrollView.minimumZoomScale = initialScale scrollView.maximumZoomScale = 3.0 // 根据业务需求调整最大缩放值 scrollView.zoomScale = initialScale // 更新滚动视图的contentSize let scaledContentSize = CGSize( width: size.width * initialScale, height: size.height * initialScale ) scrollView.contentSize = scaledContentSize // 重置内容偏移,让视图居中显示 let offsetX = max(0, (containerSize.width - scaledContentSize.width) / 2) let offsetY = max(0, (containerSize.height - scaledContentSize.height) / 2) scrollView.contentOffset = CGPoint(x: offsetX, y: offsetY) // 更新滚动视图自身的尺寸 scrollView.frame = CGRect(origin: .zero, size: containerSize) } // 实现UIScrollViewDelegate的缩放代理方法 func viewForZooming(in scrollView: UIScrollView) -> UIView? { return contentView } }
关键修改点说明:
- 尺寸变化判断:通过记录
lastContentSize和lastContainerSize,避免重复执行重置逻辑,提升性能。 - 内容视图重置:移除旧的内容视图并添加新视图,同时重置其transform为初始状态。
- Aspect Fit计算:重新计算初始缩放比例,确保内容按适配容器的方式显示。
- 滚动视图状态重置:更新最小/最大缩放比例、当前缩放值、contentSize,同时重置contentOffset让内容居中。
这种方式相当于在同一个组件实例内模拟了“重建”时的初始化逻辑,不需要销毁重建整个组件,就能回到默认的Aspect Fit显示状态,同时保留缩放平移功能。
内容的提问来源于stack exchange,提问作者jnpdx
相关产品推荐
相关产品推荐

