How to Make a Uiimage Scrollable Inside a Uiscrollview

How to make a UIImage Scrollable inside a UIScrollView?

Solution 1. Updating Frames

Firstly, make sure the views hierarchy is correctly setup (the imageView is added to the scrollView):

scrollView.addSubview(imageView)

Then I'd suggest rewriting this code as something like:

let image = UIImage(named: "myImg")
imageView.image = image // setup image to imageView
imageView.frame.size = image?.size ?? .zero // setup image size or zero to imageView
scrollView.contentSize = image.size ?? .zero // setup image size or zero as a content size

Solution 2. Using constraints

There is also another solution using constraints instead of manually setting up the sizes. This takes a bit more code but doesn't require sizes recomputing when you change the image.

scrollView.addSubview(imageView)                            // Setup the views hierarchy
imageView.translatesAutoresizingMaskIntoConstraints = false // Make sure constraints won't interfere with autoresizing mask
NSLayoutConstraint.activate(
[
imageView.leftAnchor.constraint(equalTo: scrollView.leftAnchor), // attaching to the left
imageView.topAnchor.constraint(equalTo: scrollView.topAnchor), // attaching to the top
imageView.rightAnchor.constraint(equalTo: scrollView.rightAnchor), // attaching to the right
imageView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor) // attaching to the bottom
]
)

Then we replace existing image with a new one like this:

imageView.image = UIImage(named: "myImg") 

Both approaches work for me in Playground. So, if these still won't work for you, please share more information about how you set up the hierarchy and additional parameters of the scroll view.

Adding UIImage to new Scroll View

You need to add the UIImageView containing the image of your lights to the UIView that is the contentView of the UIScrollView.

An easy way to do this is to create an @IBOutlet for the UIView in your scrollView. control-drag from the View under the ScrollView in the Document Outline to your ViewController code. Give the @IBOutlet a name such as:

@IBOutlet weak var scrollViewsView: UIView!

Then, use it to add your adornments:

@IBAction func btnAddColorfulLights1(_ sender: Any) {

let image = UIImage(named: "ColorfulLights.png")!
let imageView = UIImageView(image: image)
self.scrollViewsView.addSubview(imageView)
imageView.tag = 10

imageView.frame = CGRect(x: 67, y: 39, width: 240, height: 338)

}

Scrolling a UIImage using UIScrollView

The issue here was that scrollView.contentSize was not large enough so when attempting to scroll it wasn't picking up the movements.

Changing the values to fill the frame as well as implementing the delegate protocol allowed me to use the scroll view.

UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds];

UIImageView cuts inside UIScrollView

You want to make use of the scroll view's Content and Frame Layout Guides...

  • constrain all 4 sides of the stack view to the scroll view's Content Layout Guide
  • constrain the stack view's Height to the scroll view's Frame Layout Guide

for each image view you add to the stack view:

  • constrain the image view's Width to the scroll view's Frame Layout Guide

Here is a complete example:

class ViewController: UIViewController, UIScrollViewDelegate {

override func viewDidLoad() {
super.viewDidLoad()

// just trying to include what you've shown
let textSV = UILabel()
textSV.backgroundColor = .yellow
textSV.text = "textSV"
textSV.textAlignment = .center

let anotherView = UILabel()
anotherView.backgroundColor = .cyan
anotherView.text = "anotherView"
anotherView.textAlignment = .center

[textSV, anotherView].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
}

// respect safe area
let safeG = view.safeAreaLayoutGuide

NSLayoutConstraint.activate([
textSV.topAnchor.constraint(equalTo: safeG.topAnchor),
textSV.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
textSV.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
textSV.heightAnchor.constraint(equalToConstant: 60.0),

anotherView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
anotherView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
anotherView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor),
anotherView.heightAnchor.constraint(equalToConstant: 60.0),
])

let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .green
scrollView.showsHorizontalScrollIndicator = false
scrollView.delegate = self

view.addSubview(scrollView)

// use a stack view to hold and arrange the scrollView's subviews
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false

// add the stackView to the scrollView
scrollView.addSubview(stackView)

// use scrollView's Content Layout Guide to define scrollable content
let layoutG = scrollView.contentLayoutGuide

// use scrollView's Frame Layout Guide to define content height (since you want horizontal scrolling)
let frameG = scrollView.frameLayoutGuide

NSLayoutConstraint.activate([

// constrain scrollView Top to textSV Bottom
scrollView.topAnchor.constraint(equalTo: textSV.bottomAnchor),

// constrain scrollView Leading/Trailing to safe area
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),

// constrain scrollView Bottom to anotherView Top
scrollView.bottomAnchor.constraint(equalTo: anotherView.topAnchor),

// constrain all 4 sides of the stackView to scrollView's Content Layout Guide
stackView.topAnchor.constraint(equalTo: layoutG.topAnchor),
stackView.bottomAnchor.constraint(equalTo: layoutG.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: layoutG.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: layoutG.trailingAnchor),

// constrain stackView's height to scrollView's Frame Layout Guide height
stackView.heightAnchor.constraint(equalTo: frameG.heightAnchor),

])

// add imageViews to the stack view
for _ in 1...8 {
let pageView = UIImageView(image: UIImage(named: "iphone12mockup"))
//let pageView = UIImageView(image: UIImage(named: "sample"))
// set image view background color so you can
// see its frame (since the image will be aspect-fit scaled)
pageView.backgroundColor = .systemYellow
pageView.contentMode = .scaleAspectFit
// add it to the stack view
stackView.addArrangedSubview(pageView)
// constrain its Width to scrollView's Frame Layout Guide Width
pageView.widthAnchor.constraint(equalTo: frameG.widthAnchor).isActive = true
}

}

}

It will look like this on startup (on an iPhone 8):

Sample Image

and after scrolling a little to the right:

Sample Image

Note that since you want the image view set to Aspect Fit, I gave the "pageView" image views a background color of .systemYellow so you can see that the imageView frame fills the scroll view frame width and height.


Edit -- if you want the images to be proportional to their height, without "empty space on the sides," you need to set the image view width constraint proportional to its height, based on the image size.

Replace the "add image views" loop with this:

    // add imageViews to the stack view
for _ in 1...8 {
guard let img = UIImage(named: "iphone12mockup") else {
fatalError("Could not load image!")
}
let pageView = UIImageView()
pageView.image = img
pageView.contentMode = .scaleToFill
// add it to the stack view
stackView.addArrangedSubview(pageView)
// constrain its Width proportional to the image height
pageView.widthAnchor.constraint(equalTo: pageView.heightAnchor, multiplier: img.size.width / img.size.height).isActive = true
}

and the output will be:

Sample Image

and after scrolling a little to the right:

Sample Image

Ever scrolling UIScrollView with UIImage

I've never seen the “Behance” app, but I guess you're asking how to animate a seamlessly tiled background image across the screen indefinitely, like this:

demo

(Pattern image by Evan Eckard.)

I used an animation duration of 1 second for the demo, but you probably want a much longer duration in a real app.

You shouldn't use a timer for this. Core Animation can perform the animation for you, and letting it perform the animation smoother and more efficient. (You might think Core Animation is performing your animation since you're using UIView animation, but I believe animating a scroll view's contentOffset does not use Core Animation because the scroll view has to call its delegate's scrollViewDidScroll on every animation step.)

You also shouldn't use a scroll view for this. UIScrollView exists to allow the user to scroll. Since you're not letting the user scroll, you shouldn't use UIScrollView.

Here's how you should set up your background:

  1. Create two identical image views (numbered 0 and 1), showing the same image. Make sure the image views are each big enough to fill the screen.

  2. Put the left edge of image view 0 at the left edge of your root view. Put the left edge of image view 1 at the right edge of image view 0. Since each image view is big enough to fill the screen, image view 1 will start out entirely off the right edge of the screen.

  3. Animate image view 0's transform.translation.x from 0 to -imageView.bounds.size.width. This will make it slide to the left by precisely its own width, so when the animation reaches its end, image view 0's right edge is at the left edge of the screen (and thus image view 0 is entirely off the left edge of the screen). Set the animation's repeatCount to .infinity.

  4. Add the same animation to image view 1. Thus image view 1 comes onto the screen as image view 0 is leaving it, exactly covering the pixels revealed by image view 0's animation.

The two animations end at exactly the same time. When they end, image view 1 is exactly where image view 0 was at the start. Since both animations are set to repeat infinitely, they both immediately start over. When image view 0's animation starts over, image view 0 instantly jumps back to its starting position, which is where image view 1 ended up. Since both image views show the same image, the pixels on screen don't change. This makes the animation loop seamless.

Here's my code:

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

for imageView in imageViews {
imageView.image = patternImage
imageView.contentMode = .scaleToFill
view.addSubview(imageView)
}
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

let bounds = view.bounds

let patternSize = patternImage.size
// Scale the image up if necessary to be at least as big as the screen on both axes.
// But make sure scale is at least 1 so I don't shrink the image if it's larger than the screen.
let scale = max(1 as CGFloat, bounds.size.width / patternSize.width, bounds.size.height / patternSize.height)
let imageFrame = CGRect(x: 0, y: 0, width: scale * patternSize.width, height: scale * patternSize.height)

for (i, imageView) in imageViews.enumerated() {
imageView.frame = imageFrame.offsetBy(dx: CGFloat(i) * imageFrame.size.width, dy: 0)

let animation = CABasicAnimation(keyPath: "transform.translation.x")
animation.fromValue = 0
animation.toValue = -imageFrame.size.width
animation.duration = 1
animation.repeatCount = .infinity
animation.timingFunction = CAMediaTimingFunction(name: .linear)

// The following line prevents iOS from removing the animation when the app goes to the background.
animation.isRemovedOnCompletion = false

imageView.layer.add(animation, forKey: animation.keyPath)
}
}

private let imageViews: [UIImageView] = [.init(), .init()]
private let patternImage = #imageLiteral(resourceName: "pattern")

}

UIImageView and UIScrollView zooming

All you need to do is add your UIImageView (or any view you want to zoom) inside your UIScrollView.

Set your maximumZoomScale on your UIScrollView to any value higher than 1.0f.

Set yourself as the delegate of your UIScrollView and return the UIImageView in the viewForZooming delegate method.

That's it. No pinch gesture needed, no nothing. UIScrollView handles pinch zooming for you.

IOS: add imageview in a scrollview to have zoom

  1. Set your view controller up as a <UIScrollViewDelegate>
  2. Draw your UIScrollView the size you want for the rectangle at the center of the view. Set the max zoom in the inspector to something bigger than 1. Like 4 or 10.
  3. Right click on the scroll view and connect the delegate to your view controller.
  4. Draw your UIImageView in the UIScrollView and set it up with whatever image you want. Make it the same size as the UIScrollView.
  5. Ctrl + drag form you UIImageView to the .h of your View controller to create an IBOutlet for the UIImageView, call it something clever like imageView.
  6. Add this code:

    -(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
    return self.imageView;
    }
  7. Run the app and pinch and pan til your heart's content.



Related Topics



Leave a reply



Submit