#swift #uiscrollview #uiimageview
#swift #uiscrollview #uiimageview
Вопрос:
Я пытаюсь отобразить imageView
в центре по осям X и Y на scrollView
, которое хорошо вписывается в ширину устройства, когда я запускаю приложение. Я бы также хотел панорамировать и масштабировать imageView
. Я перепробовал почти все решения, опубликованные на SO, а также следовал этому руководству, но почему-то это просто не решает мою проблему. Изображение сгенерировано из PDF.
Я делаю свой макет программно. Моя реализация до сих пор:
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.backgroundColor = .lightGray
return sv
}()
let imageView: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFill
return iv
}()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
view.addSubview(scrollView)
scrollView.addSubview(imageView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
imageView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10),
imageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 10),
imageView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -10),
imageView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -10),
])
imageView.image = obtainThumbnail()
}
fileprivate func updateMinZoomScaleForSize(_ size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let minScale = min(widthScale, heightScale)
scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
updateMinZoomScaleForSize(view.bounds.size)
}
func obtainThumbnail() -> UIImage? {
guard let url = Bundle.main.url(forResource: "drawings", withExtension: "pdf") else {return nil}
guard
let data = try? Data(contentsOf: url),
let page = PDFDocument(data: data)?.page(at: 0) else {
return nil
}
let pageSize = page.bounds(for: .mediaBox)
return page.thumbnail(of: CGSize(width: pageSize.width, height: pageSize.height), for: .mediaBox)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
Это мои желаемые результаты при запуске приложения.
И это результаты, когда я запускаю приложение сейчас, перегруженное.
Кто-нибудь посоветует, чего мне не хватает?
Комментарии:
1. Попробуйте изменить
contentMode = .scaleAspectFill
наscaleAspectFit
2. @Magnas попробовал, тот же результат, что и выше
3. При вычислении
minScale
вupdateMinZoomScaleForSize
кадрах обоихscrollView
иimageView
равны нулю.4. @Magnas если это так, где я должен вычислять?
Ответ №1:
Я думаю, что представления загружаются лениво в UIViewController
s, поэтому выполнение вычисления позже в жизненном цикле пользовательского интерфейса должно решить проблему. Удаляем вызов в viewWillLayoutSubviews
и вместо этого используем:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateMinZoomScaleForSize(view.bounds.size)
}
кажется, работает.
Ответ №2:
Чтобы это работало хорошо, нужно исправить два места:
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
view.addSubview(scrollView)
scrollView.addSubview(imageView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
//First place.
// scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
// scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0),
scrollView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0),
imageView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10),
imageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 10),
imageView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -10),
imageView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -10),
])
imageView.backgroundColor = UIColor.red
imageView.image = UIImage.init(named: "temp2.png")
//second place.
imageView.sizeToFit()
Надеюсь, это хорошо решило вашу проблему.
Если вам нужен вид посередине, попробуйте следующий метод:
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.backgroundColor = .lightGray
sv.contentMode = .center
return sv
}()
let imageView: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = true
iv.contentMode = .scaleAspectFill
return iv
}()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
view.addSubview(scrollView)
scrollView.addSubview(imageView)
NSLayoutConstraint.activate([
scrollView.centerYAnchor.constraint(equalTo: view.centerYAnchor ),
scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor ),
scrollView.contentLayoutGuide.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
scrollView.contentLayoutGuide.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor),
])
imageView.backgroundColor = UIColor.red
imageView.image = UIImage.init(named: "temp2.png")
imageView.sizeToFit()
updateMinZoomScaleForSize(view.bounds.size)
}
var constantHeight : CGFloat{
return min(view.bounds.height, imageView.bounds.height * scrollView.zoomScale)
}
var constantWidth : CGFloat{
return min( view.bounds.width, imageView.bounds.width * scrollView.zoomScale)
}
lazy var constraintHeight: NSLayoutConstraint = {
return scrollView.contentLayoutGuide.heightAnchor.constraint(equalToConstant: constantHeight)
}()
lazy var constraintWeight: NSLayoutConstraint = {
return
scrollView.contentLayoutGuide.widthAnchor.constraint(equalToConstant: constantWidth)
}()
fileprivate func updateMinZoomScaleForSize(_ size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let minScale = min(widthScale, heightScale)
imageView.frame = CGRect.init(x: 0, y: 0, width: minScale * imageView.bounds.width, height: minScale*imageView.bounds.height)
scrollView.maximumZoomScale = 10.0
scrollView.zoomScale = 1.0
constraintHeight.isActive = true
constraintWeight.isActive = true
}
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat){
constraintHeight.constant = constantHeight
constraintWeight.constant = constantWidth
scrollView.clipsToBounds = true
}
func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
scrollView.clipsToBounds = false
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
Комментарии:
1. ваше решение вроде бы сработало, но изображение все еще не подходит по ширине. Более того, hard coding 200 от topAnchor не является масштабируемым решением. Мне понадобится эта работа для всех устройств.