我在 UIScrollView 中有一個 UIImageView,影像的大小為 2000x3000。我可以捏縮放并拖動以在螢屏上平移。(我關注了這個視頻
如果我們所做的只是將.contentOffset#3設定為“目標點”,我們會得到:

所以,我們需要減去滾動視圖框架的寬度和高度的二分之一:
scrollView.contentOffset.x = points[2].x - (scrollView.frame.width * 0.5)
scrollView.contentOffset.y = points[2].y - (scrollView.frame.height * 0.5)
這將我們的“目標點”放在滾動視圖的中心,但是......
如果我們縮小到 90% ( scrollView.zoomScale = 0.9),我們會得到:

因此,我們需要將“目標點”轉換為縮放比例:
// translate target point to zoomScale
var x: CGFloat = points[2].x * scrollView.zoomScale
var y: CGFloat = points[2].y * scrollView.zoomScale
x = x - (scrollView.frame.width * 0.5)
y = y - (scrollView.frame.height * 0.5)
scrollView.contentOffset.x = x
scrollView.contentOffset.y = y
而且,嗚呼,我們有這個:

但是,下一個問題是,如果“目標點”超出滾動視圖限制,我們不想將其居中。
例如,如果我們嘗試以“1”或“5”為中心,我們會得到:

和:

點在滾動視圖中居中,但只要我們觸摸它進行滾動或縮放,它就會捕捉到角落。
我們需要限制.contentOffset以避免這種情況。
因此,對于點“1” ( points[0]):
// translate target point to zoomScale
var x: CGFloat = points[0].x * scrollView.zoomScale
var y: CGFloat = points[0].y * scrollView.zoomScale
// don't want to set offset below Zero
let minOffset: CGPoint = .zero
// don't want to set offset greater than what will fit in the scroll view
let maxOffset: CGPoint = CGPoint(x: imgView.frame.width - scrollView.frame.width, y: imgView.frame.height - scrollView.frame.height)
// this prevents x and from being negative
x = max(minOffset.x, x - (scrollView.frame.width * 0.5))
y = max(minOffset.y, y - (scrollView.frame.height * 0.5))
// this prevents x and y from exceeding the frame of the scroll view
x = min(maxOffset.x, x)
y = min(maxOffset.y, y)
scrollView.contentOffset.x = x
scrollView.contentOffset.y = y
這是一個完整的示例……如上圖所示,點擊“數字按鈕”會將中心點滾動到滾動視圖的中心(或盡可能靠近,如果它超出限制)。您只需要添加 2000x3000 影像(名為“img2000x3000”)......不需要@IBOutlet或@IBAction需要連接:
class ScrollPosViewController: UIViewController, UIScrollViewDelegate {
let points: [CGPoint] = [
CGPoint(x: 100, y: 100),
CGPoint(x: 800, y: 600),
CGPoint(x: 1600, y: 1200),
CGPoint(x: 600, y: 2000),
CGPoint(x: 1900, y: 2900),
]
let scrollView: UIScrollView = {
let v = UIScrollView()
v.backgroundColor = .yellow
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let imgView: UIImageView = {
let v = UIImageView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGreen
// make sure we can load the image
guard let img = UIImage(named: "img2000x3000") else {
print("Could not load image!!!")
return
}
// assing image to image view
imgView.image = img
// create a buttons stack view
let stack: UIStackView = {
let v = UIStackView()
v.distribution = .fillEqually
v.spacing = 20
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
for i in 0..<points.count {
let b = UIButton()
b.setTitle("\(i 1)", for: [])
b.setTitleColor(.white, for: .normal)
b.setTitleColor(.lightGray, for: .highlighted)
b.backgroundColor = .systemBlue
b.layer.cornerRadius = 8
b.addTarget(self, action: #selector(centerOn(_:)), for: .touchUpInside)
stack.addArrangedSubview(b)
}
// add image view to scroll view
scrollView.addSubview(imgView)
// add scroll view to view
view.addSubview(scrollView)
// add buttons stack view to view
view.addSubview(stack)
let g = view.safeAreaLayoutGuide
let c = scrollView.contentLayoutGuide
NSLayoutConstraint.activate([
// constrain background image view
// Leading / Trailing at 20-pts
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
// height proportional to image size
scrollView.heightAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: img.size.height / img.size.width),
// centered vertically
scrollView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
// constrain image view to all 4 sides of scroll view's Content Layout Guide
imgView.topAnchor.constraint(equalTo: c.topAnchor),
imgView.leadingAnchor.constraint(equalTo: c.leadingAnchor),
imgView.trailingAnchor.constraint(equalTo: c.trailingAnchor),
imgView.bottomAnchor.constraint(equalTo: c.bottomAnchor),
// constrain image view's width/height to image width/height
imgView.widthAnchor.constraint(equalToConstant: img.size.width),
imgView.heightAnchor.constraint(equalToConstant: img.size.height),
// constrain buttons stack view at bottom
stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
stack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
])
scrollView.delegate = self
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 2.0
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// update min zoom scale so we can only "zoom out" until
// the content view fits the scroll view frame
if scrollView.minimumZoomScale == 1.0 {
let xScale = scrollView.frame.width / imgView.frame.width
let yScale = scrollView.frame.height / imgView.frame.height
scrollView.minimumZoomScale = min(xScale, yScale)
}
}
@objc func centerOn(_ sender: Any?) -> Void {
guard let btn = sender as? UIButton,
let t = btn.currentTitle,
let n = Int(t),
n > 0,
n <= points.count
else {
return
}
// translate target point to zoomScale
var x: CGFloat = points[n - 1].x * scrollView.zoomScale
var y: CGFloat = points[n - 1].y * scrollView.zoomScale
// don't want to set offset below Zero
let minOffset: CGPoint = .zero
// don't want to set offset greater than what will fit in the scroll view
let maxOffset: CGPoint = CGPoint(x: imgView.frame.width - scrollView.frame.width, y: imgView.frame.height - scrollView.frame.height)
// this prevents x and from being negative
x = max(minOffset.x, x - (scrollView.frame.width * 0.5))
y = max(minOffset.y, y - (scrollView.frame.height * 0.5))
// this prevents x and y from exceeding the frame of the scroll view
x = min(maxOffset.x, x)
y = min(maxOffset.y, y)
// if we want to animate the point to the new offset
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.curveEaseInOut], animations: {
// set the new content offset
self.scrollView.contentOffset = CGPoint(x: x, y: y)
}, completion: nil)
// or, without animation
// set the new content offset
//scrollView.contentOffset = CGPoint(x: x, y: y)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imgView
}
}
uj5u.com熱心網友回復:
// Assuming your image is the same width and height of
// the scrollview, the CGPoint for the center of the image will be
let scrollViewCenterX: CGFloat = scrollView.bounds.width / 2
let scrollViewCenterY: CGFloat = scrollView.bounds.height / 2
let imageCenterPoint = CGPoint(x: scrollViewCenterX, y: scrollViewCenterY)
scrollView.setContentOffset(imageCenterPoint)
// if we want to center the scrollview on `point`
let point = CGPoint(x: 600, y: 800)
let newPoint = CGPoint(x: point.x / 2, y: point.y / 2)
scrollView.setContentOffset(newPoint)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/421119.html
標籤:
上一篇:.addSublayer()在Swift5.5中改變了嗎?
下一篇:訪問structswift的資料
