UIScrollView Swift - Adding Images - ios

I'm trying to get a simple color picker by adding the colors as Images into an UIScrollView.
I've used UIScrollViews before and never encountered any issues. This time nothing gets displayed no matter what I do. Double checked if the colors get picked right and everything seems to be fine. For some reason the colors don't get added to the UIScrollView.
func fillColorPicker(colors: Array<String>){
for i in 0..<colors.count{
let imageView = UIImageView()
imageView.image = UIImage(named: colors[i])
imageView.contentMode = .scaleAspectFit
let xPosition = CGFloat(i) * imageView.frame.width
imageView.frame = CGRect(x: xPosition, y: 0, width: imageView.frame.width, height: self.colorPicker.frame.height)
colorPicker.contentSize.width = imageView.frame.width * CGFloat(i+1)
colorPicker.addSubview(imageView)
}
}
Found something. Somehow the imageView.frame.width is always 0. I assumed it would take the width from the image file?
Solution:
func fillColorPicker(colors: Array<String>){
for i in 0..<colors.count{
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 75, height: 75))
imageView.image = UIImage(named: colors[i])
imageView.contentMode = .scaleAspectFit
let xPosition = CGFloat(i) * imageView.frame.width
imageView.frame = CGRect(x: xPosition, y: 0, width: imageView.frame.width, height: self.colorPicker.frame.height)
colorPicker.contentSize.width = imageView.frame.width * CGFloat(i+1)
colorPicker.addSubview(imageView)
}
}

Related

How can I transition a UIImage slowly from top to bottom for applying filter to the image?

I want to make it appear as if my image is slowly getting filtered from top to bottom. I am adding two image views. My processed image is in the background and non-processed in the front. I am making the height of non-processed image 0. Here is my code.
imageView.frame = CGRect(x: 0, y: 100, width: self.view.bounds.size.width, height: 400)
imageView.image = processedImage
let nonProcessedImageView = UIImageView()
nonProcessedImageView.frame = CGRect(x: 0, y: 100, width: self.view.bounds.size.width, height: 400)
nonProcessedImageView.image = nonProcessedImage
view.addSubview(nonProcessedImageView)
UIView.transition(with: nonProcessedImageView,
duration: 5.0,
animations: {
nonProcessedImageView.frame = CGRect(x: 0, y: 500, width: self.view.bounds.size.width, height: 0)
},
completion: {_ in
})
The non processed image does not even appear on top of the processed.
The issue seems to be that changing the y coordinate of the frame in the animation block leads to issues when using the UIView.Animate function.
See this answer
To quote the most essential part:
You should change the center property (to move the view) and bounds
property (to change its size) instead. Those properties behave as
expected.
Since you want to just reduce the height, you don't need to do anything to the y coordinate
let nonProcessedImageView = UIImageView()
var newImageFrame = imageView.frame
nonProcessedImageView.frame = newImageFrame
nonProcessedImageView.clipsToBounds = true
nonProcessedImageView.contentMode = .scaleAspectFit
nonProcessedImageView.image = imageView.image
view.addSubview(nonProcessedImageView)
// I set this to 1 instead of 0 as 0 does not show the image
// for some reason
newImageFrame.size.height = 1
// Update your processed image
imageView.image = processedImage
UIView.animate(withDuration: 5.0) {
nonProcessedImageView.frame = newImageFrame
}
completion: { (isComplete) in
if isComplete {
nonProcessedImageView.removeFromSuperview()
}
}
This gives some results but as you can see, the animation is not so good because as you reduce the height, the image view's contentMode kicks in and gives the seen effect.
For best results, add the new image view to a UIView and reduce the height of the UIView instead of the UIImageView
var newImageFrame = imageView.frame
let containerView = UIView(frame: newImageFrame)
containerView.clipsToBounds = true
let nonProcessedImageView = UIImageView()
nonProcessedImageView.frame = containerView.bounds
nonProcessedImageView.clipsToBounds = true
nonProcessedImageView.contentMode = .scaleAspectFit // same as original
nonProcessedImageView.image = imageView.image
containerView.addSubview(nonProcessedImageView)
view.addSubview(containerView)
newImageFrame.size.height = 1
imageView.image = processedImage
UIView.animate(withDuration: 3.0) {
containerView.frame = newImageFrame
}
completion: { (isComplete) in
if isComplete {
containerView.removeFromSuperview()
}
}
This should give you what you want:
This works for top to bottom transition.
imageView.frame = CGRect(x: 0, y: 100, width: self.view.bounds.width, height: 400)
imageView.image = nonProcessedImage
view.addSubview(imageView)
let frontView = UIView(frame: CGRect(x: 0, y: 100, width: self.view.frame.width, height: 0))
frontView.clipsToBounds = true
view.addSubview(frontView)
let nonProcessedImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 400))
nonProcessedImageView.image = processedImage
nonProcessedImageView.clipsToBounds = true
frontView.addSubview(nonProcessedImageView)
UIView.transition(with: frontView, duration: 5, options: [.allowAnimatedContent], animations: {
frontView.frame = CGRect(x: 0, y: 100, width: self.view.frame.width, height: 400)
}, completion: nil)

Image size error while rendering UIView to UIImage

I would like to convert two images into one image with custom design.
The expected image is a snapshot of my UICollectionViewCell, not a UIImage actually.
I copied the layout codes from my custom UICVCell.swift file and tried to render the view into UIImage, but the result image is what you can see below.
I searched through a lot of questions in SOF, but most of it was about 'How you can render a UIView into a UIImage.'
I've tried drawing too, but had the same messed up result.
Can anybody tell me what's the problem?
I would really appreciate your help, it's my first question in SOF.
I might cry in a minute or two, literally...
class ViewController: UIViewController {
private var imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.clipsToBounds = true
return iv
}()
func createBubbleImage(images: [UIImage?]) -> UIImage? {
switch images.count {
case 1:
return images[0]
case 2:
let newView = UIView(frame: .init(x: 0, y: 0, width: 300, height: 300))
let size = newView.frame.width
let iv0 = UIImageView(image: images[0])
iv0.contentMode = .scaleAspectFit
iv0.clipsToBounds = true
let iv1 = UIImageView(image: images[1])
iv1.contentMode = .scaleAspectFit
iv1.clipsToBounds = true
newView.addSubview(iv0)
iv0.anchor(top: newView.topAnchor, left: newView.leftAnchor, paddingTop: size * 0.04, paddingLeft: size * 0.04, width: size * 0.56, height: size * 0.56)
newView.addSubview(iv1)
iv1.anchor(bottom: newView.bottomAnchor, right: newView.rightAnchor, paddingBottom: size * 0.04, paddingRight: size * 0.04, width: size * 0.56, height: size * 0.56)
iv0.layer.cornerRadius = size * 0.28
iv1.layer.cornerRadius = size * 0.28
let renderer = UIGraphicsImageRenderer(bounds: newView.bounds)
return renderer.image { ctx in
newView.layer.render(in: ctx.cgContext)
}
default:
return UIImage(named: "logo")
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(imageView)
imageView.center(inView: view)
imageView.setDimensions(width: 300, height: 300)
imageView.image = createBubbleImage(images: [UIImage(named: "0"), UIImage(named: "1")])
}
}
Expected Image
Result Image
Do the following:
Remove the code lines that have the anchor method.
Initiate the iv0 and iv1 with UIImageView(frame: ...)
Add iv0.image = images[0] and iv1.image = images[1]
I also increased the radius a little bit because in my test device the images were not completely circular.
The code should look like this:
func createBubbleImage(images: [UIImage?]) -> UIImage? {
switch images.count {
case 1:
return images[0]
case 2:
let newView = UIView(frame: .init(x: 0, y: 0, width: 300, height: 300))
let size = newView.frame.width
let iv0 = UIImageView(frame: .init(x: 0, y: 0, width: 200, height: 200))
iv0.image = images[0]
iv0.contentMode = .scaleAspectFit
iv0.clipsToBounds = true
let iv1 = UIImageView(frame: .init(x: 100, y: 100, width: 200, height: 200))
iv1.image = images[1]
iv1.contentMode = .scaleAspectFit
iv1.clipsToBounds = true
newView.addSubview(iv0)
newView.addSubview(iv1)
iv0.layer.cornerRadius = size * 0.35
iv1.layer.cornerRadius = size * 0.35
let renderer = UIGraphicsImageRenderer(bounds: newView.bounds)
return renderer.image { ctx in
newView.layer.render(in: ctx.cgContext)
}
default:
return UIImage(named: "logo")
}
}
With it, the result is the following:
I had to take a screenshot from your "expected image", that's why the images look like zoomed in. You can play with the UIImageView(frame: ...) part to adjust the two images as you want (I didn't played enough to avoid that cut in the edges, but it is possible with the right measures).
Remark: the x and y values in the UIImageView frame are the horizontal and vertical distances from the top-left corner of newView to the top-left corner of your UIImageView, respectively.

Centre image in navigation bar

I'm calling a JSQMessageViewController and adding an image as the title but it's not centred due to the offset caused by the Back left-button.
Here's my code for adding the image:
let imageView = UIImageView()
imageView.frame.size.width = 40
imageView.frame.size.height = 40
imageView.contentMode = .scaleAspectFit
let image = UIImage(named: "avatar_example")
imageView.image = image
navigationItem.titleView = imageView
Thanks :)
Are you sure that the problem is in JSQMessageViewController? Maybe you just need to use standard sizes from title view (44*44) for alignment.
let imageView = UIImageView(image: UIImage(named: "avatar_example"))
imageView.contentMode = .scaleAspectFit
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
imageView.frame = titleView.bounds
titleView.addSubview(imageView)
self.navigationItem.titleView = titleView
You need to actually get the width and height of the UINavigationBar and center the image accordingly. Try this
guard let bar = navigationController.navigationBar else { return }
let bannerWidth = bar.frame.size.width
let bannerHeight = bar.frame.size.height
// centers image vertically & horizontally
let bannerX = bannerWidth / 2 - imageView.frame.width / 2
let bannerY = bannerHeight / 2 - imageView.frame.height / 2
imageView.frame = CGRect(x: bannerX, y: bannerY, width: bannerWidth, height: bannerHeight)
imageView.contentMode = .scaleAspectFit
navigationItem.titleView = logoImageView

Adding imageview as a subview in scrollview swift ios

I am adding images to scrollview but just getting one image in the scrollview, I dont know why I am not seing any other images but just empty scroll except one image
This is what I have tried
in viewdidload
imageScroll = UIScrollView(frame: CGRect(x: 10, y: 320, width: 230, height: 250))
imageScroll.contentSize = CGSize(width: 250, height: 2000)
imageScroll.backgroundColor = .white
in function
for (b,c) in zip(photoGotArray, 0..<totalPhotosGot) {
photoDataVarOk = UserDefaults.standard.object(forKey: b) as? NSData
newImageView = UIImageView(frame: CGRect(x: 10, y: 50, width: 230, height: 200))
newImageView.viewWithTag(c)
newImageView.image = UIImage(data: photoDataVarOk! as Data)
self.imageScroll.addSubview(newImageView)
}
here is the image with just one image and rest of the empty scrollview
You need to change the Y to be incrementing as according to your code all images have the same frame
let newImageView = UIImageView(frame: CGRect(x: 10, y: 50 + ( 200 * i ) , width: 230, height: 200))
set i as you want or from the loop parameters
//
for (c,b) in photoGotArray.enumerated() {
photoDataVarOk = UserDefaults.standard.data(forKey: b)
let newImageView = UIImageView(frame: CGRect(x: 10, y: 50 + ( 200 * c), width: 230, height: 200))
newImageView.viewWithTag(c)
newImageView.image = UIImage(data: photoDataVarOk!)
self.imageScroll.addSubview(newImageView)
}
let newImageView = UIImageView()
newImageView = UIImageView(frame: CGRect(x: 10, y: yourImageHight * (indexLoop), width: 230, height: 200))
in your loop

My scrollView cut my last picture Swift 3

I have an horizontal scrollView, where I add my array of image, but it alway cut the picture, my content mode is scaleToFill. I printed the size of my imageView and my scrollView and gave me the same size, so why can't I see my picture filling all my scrollView
My first Image and
My last image of my array
Here is my code
func getFavoriteSalon()
{
arrayOfDataScrollView = [#imageLiteral(resourceName: "large"), #imageLiteral(resourceName: "Kristoff-image-kristoff-36081750-500-266"), #imageLiteral(resourceName: "image-battle-for-dream-island-39780938-500-266")]
mainScrollView.contentSize.width = (mainScrollView.frame.width) * CGFloat(arrayOfDataScrollView.count)
for i in 0..<arrayOfDataScrollView.count
{
let imageView = UIImageView()
let xPosition = self.mainScrollView.frame.width * CGFloat(i)
imageView.frame = CGRect(x: xPosition, y: 0, width: self.mainScrollView.frame.width , height: self.mainScrollView.frame.height)
imageView.image = arrayOfDataScrollView[i]
imageView.contentMode = .scaleToFill
print(self.mainScrollView.frame.width) =>Give me 375
print(self.mainScrollView.frame.height) =>Give me 200
print("Width => \(imageView.frame.width)") =>Give me 375
print("height => \(imageView.frame.height)") =>Give me 200
mainScrollView.addSubview(imageView)
}
}
I found a solution, for me it's a bug xcode, i work with an emulateur of Iphone7+, but I got the value of an Iphone 7 when i print my variables, Be sure to have the preview, and the emulateur looking the same device
Use this and set content size according image
var xPosition:CGFloat = 0
for i in 0..<arrayOfDataScrollView.count{
var frame: CGRect = CGRect(x: 0, y: 0, width: self.mainScrollView.frame.width, height: self.mainScrollView.frame.height)
frame.origin.x = CGFloat(xPosition)
frame.size = mainScrollView.frame.size
let imageView = UIImageView(frame: frame)
imageView.contentMode = .scaleToFill
imageView.frame.size.width = imageWidth
imageView.frame.size.height = imageHeight
imageView.frame.origin.x = xPosition
imageView.frame.origin.y = 0
mainScrollView.addSubview(imageView)
xPosition += imageView.frame.size.width + 5; (5 you can change this value)
mainScrollView.contentSize = CGSize(width: CGFloat(i) * imageView.frame.size.width, height:
mainScrollView.frame.size.height)
}

Resources