This is driving me nuts!
I'm basing my UIScrollView on http://koreyhinton.com/blog/uiscrollview-crud.html to make it programatic, so have set up a container view inside my scrollview. But it pans, but won't zoom.
class BinaryTreeViewController: UIViewController, UIScrollViewDelegate {
var scrollView: UIScrollView!
var containerView : UIView!
override func viewDidLoad() {
super.viewDidLoad()
let width:CGFloat = self.view.bounds.width
let height:CGFloat = self.view.bounds.height
scrollView = UIScrollView()
scrollView.delegate = self
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 2.0
scrollView.contentSize = CGSize(width: width*2, height: 2000)
scrollView.backgroundColor = .red
containerView = UIView()
scrollView.addSubview(containerView)
view.addSubview(scrollView)
containerView.isUserInteractionEnabled = true
scrollView.isUserInteractionEnabled = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
containerView.frame = CGRect(x: 0, y: 0, width: scrollView.contentSize.width, height: scrollView.contentSize.height)
}
override func viewWillLayoutSubviews() {
//I create a view called "theView"
containerView.addSubview(theView)
}
The following functions do not fire at any point
func update(zoomScale: CGFloat, offSet: CGPoint) {
scrollView.zoomScale = zoomScale
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return containerView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
NSLog("scroll")
}
You really don't need to do so much code for that purpose.
You can set up all you need for scrollView in storyboard, and you only need outlet for the view you wish to zoom.
Set up a controller, add scrollview, connect delegate property to view controller, add zooming view as subview in IB.
In the class, conform controller to UIScrollViewDelegate, and use viewForZooming, a scrollView delegate method.
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var zoomer: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return zoomer
}
}
P.S. Use newer resources for learning, Ray Wenderlich, AppCoda, etc - its a big web full of good sources, and Swift is in constant change.
Related
I'm doing official iOS development tutorial from Apple. There is a task to make a zoomable image in a scrollView.
I believe that did it right. There is mistake, since I cant zoom image in.
The task is below in screenshots.
Task part 1
Task part 2
Here is my code:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//set the scroll view's deligate to be the viewcontroller instance
self.scrollView.delegate = self
viewForZooming(in: scrollView)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
override func viewDidAppear(_ animated: Bool) {
updateZoomFor(size: view.bounds.size)
}
func updateZoomFor(size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let scale = min(widthScale, heightScale)
scrollView.minimumZoomScale = scale
scrollView.zoomScale = scale
}
}
Mainscroll is scrollview which was added into another internal UIView and i have UISlider to change internal view scale.
But, MainScroll.setZoomScale(CGFloat(sender.value), animated: true) this line is not work.
==> Here is my code.
override func viewDidLoad() {
super.viewDidLoad()
MainScroll.maximumZoomScale = 1
MainScroll.minimumZoomScale = 10
MainScroll.delegate = self
MainScroll.zoomScale = 5
}
#IBAction func Scrolling(_ sender: UISlider) {
MainScroll.setZoomScale(CGFloat(sender.value), animated: true)
}
Here is a minimal example for getting a UIScrollView to zoom.
The key is that you have to implement func viewForZooming(in scrollView: UIScrollView) -> UIView? and return a view (that is inside your scrollView) that is to be scaled (think of it like your 'document' or 'canvas' view).
Also, notice that zoom is working for the default pinch gestures on the scrollView as well.
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
// Assume that outlets exist on a storyboard
#IBOutlet var scrollView: UIScrollView!
#IBOutlet var canvas: UIView! // A view that is added in the scrollView
#IBOutlet var slider: UISlider!
let minScale: CGFloat = 1
let maxScale: CGFloat = 10
let initialScale: CGFloat = 1
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
scrollView.minimumZoomScale = minScale
scrollView.maximumZoomScale = maxScale
scrollView.zoomScale = initialScale
slider.minimumValue = Float(minScale)
slider.maximumValue = Float(maxScale)
slider.value = Float(initialScale)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return canvas
}
#IBAction func sliderValueChanged(_ sender: UISlider) {
scrollView.zoomScale = CGFloat(sender.value)
}
}
When I instantiate and add a scroll view to my self.view in my ViewController class and set the scroll view's delegate to self, the delegate functions get called. As written below:
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var smallView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let width = Double(view.frame.width)
let height = Double(view.frame.height)
let frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
let scrollView = UIScrollView(frame: frame)
//scrollView.backgroundColor = UIColor.blue
let size = CGSize(width: width + 300, height:1000)
scrollView.contentSize = size
smallView.addSubview(scrollView)
scrollView.delegate = self
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("Gets called.")
}
}
However, when I create a custom class, in this case called, PhotoBooth, and call try to call the delegate function in this custom class, the functions do not get called. Here is my custom class:
import Foundation
import UIKit
class PhotoBooth: NSObject, UIScrollViewDelegate {
private var boothView: UIView
//private var scrollView: UIScrollView
init(view: UIView) {
boothView = view
}
func startSession() {
let width = Double(boothView.frame.width)
let height = Double(boothView.frame.height)
let frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
let scrollView = UIScrollView(frame: frame)
//scrollView.backgroundColor = UIColor.blue
let size = CGSize(width: width + 300, height:1000)
scrollView.contentSize = size
boothView.addSubview(scrollView)
scrollView.delegate = self
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("paisdjfij")
}
}
And I instantiate the class in my ViewController like so:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var smallView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let photoBooth = PhotoBooth(view: self.view)
photoBooth.startSession()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Any solutions to the problem? Please let me know and thank you so much for your help in advance.
Instead of trying this You should use protocols to call scroll view in custom class.It will look somewhat like this.
CustomClass.h
#protocol CustomDelegate <NSObject>
-(void)customDelegateMethod;
#end
#interface CustomClass : UIScrollView <UIScrollViewDelegate>
{
id<CustomDelegate> delegate
}
CustomClass.m
-(void) methodScrollView
{
[self.delegate customDelegateMethod];
}
ViewController.h
#interface ViewController: UIViewController <CustomDelegate>
{
}
ViewController.m
-(void)makeCustomScrollView
{
CustomClass *objCustom = [[CustomClass alloc] init];
objCustom.delegate = self;
//other stuff
}
-(void)customDelegateMethod
{
}
I have two UIScrollViews in my UIViewController both of them have different properties such as pagingEnabled, contentSize & contentInset also i need them to behave separately when scrolling so i create two separate custom classes like below.
class NavigationScrollView: UIScrollView{
}
class ContentScrollView: UIScrollView{
}
also delegates
extension NavigationScrollView: UIScrollViewDelegate{
// this method not triggers
func scrollViewDidScroll(scrollView: UIScrollView) {
}
}
extension ContentScrollView: UIScrollViewDelegate{
// this method not triggers
func scrollViewDidScroll(scrollView: UIScrollView) {
}
}
In main viewController viewDidLoad() i do
navigationScroller = NavigationScrollView(frame: CGRectMake(0.0, 0.0, frameWidth, 40.0))
contentScroller = ContentScrollView(frame: CGRectMake(0.0, 0.0, frameWidth, frameHeight))
how about you assign the delegate this way?
class NavigationScrollView: UIScrollView{
override func didMoveToSuperview() {
super.didMoveToSuperview()
self.delegate = self
}
}
class ContentScrollView: UIScrollView{
override func didMoveToSuperview() {
super.didMoveToSuperview()
self.delegate = self
}
}
I'm trying to make a scroll view on iOS with Swift and Autolayout, but the screen crop the content instead of resizing it.
My layout and constraints
How can i fix this ?
EDIT : Tried with UITextView it doesn't work too
EDIT 2 : I'm trying to make a screen like that and my problem is that i can't implements this screen for all screens resolution and rotation with AutoLayout
I found a solution !
Use Interface Builder only to add a UIScrollView and add constraints to fit superview, and create all subviews programatically.
Override updateViewConstraints()and for each view in the ScrollView set translatesAutoresizingMaskIntoConstraints to false and add a width constraint to keep scrollview width. Dont forget to call super.updateViewConstraint().
Override didRotateFromInterfaceOrientation() and viewDidAppear() and set scrollView.contentSize.height to wrap all items (if you don't do that, you can't scroll).
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
var constraintsUpdated = false;
var label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
label.numberOfLines = 0
label.textColor = UIColor.blackColor()
scrollView.addSubview(label)
}
override func updateViewConstraints() {
if(constraintsUpdated){
//Rotate, just update view and keep constraints
super.updateViewConstraints()
scrollView.layoutSubviews()
return;
}
var viewsDictionary = ["label": label, "scrollView": scrollView]
let screenWidth = self.view.frame.width
label.setTranslatesAutoresizingMaskIntoConstraints(false)
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(String(format: "H:[label(==scrollView)]", screenWidth), options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary))
constraintsUpdated = true
super.updateViewConstraints()
//Update subviews
scrollView.layoutSubviews()
}
override func viewDidAppear(animated: Bool) {
scrollView.contentSize.height = label.bounds.height
}
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
scrollView.contentSize.height = label.bounds.height
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I found another solution with FLKAutoLayout library, that's work great with less code!
class ViewController: UIViewController {
var labelTitle: UILabel = UILabel()
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
//TITLE
scrollView.addSubview(labelTitle)
labelTitle.textColor = UIColor.blackColor()
labelTitle.numberOfLines = 0
//constraints
labelTitle.constrainWidthToView(self.view, predicate: nil)
labelTitle.numberOfLines = 0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidLayoutSubviews() {
scrollView.contentSize.height = labelTitle.frame.height
}
}
I don't know if it's a UIScrollView bug with AutoLayout or a feature