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)
So I added a UIImageView to the right of my UITextField, but I need to add a little bit of padding to the right side so that it doesn't anchor all the way to the right. I tried adding a custom frame but that didn't work, so I'm not too sure how to go about getting that padding. Any help would be much appreaciated.
See TextField Example Here
let titleField : UITextField = {
let titleField = UITextField()
titleField.placeholder = "Title"
titleField.textAlignment = .center
titleField.backgroundColor = .white
titleField.addDoneCancelToolbar()
var imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
let image = UIImage(systemName: "exclamationmark.circle")?.withTintColor(.systemRed, renderingMode: .alwaysOriginal)
imageView.image = image
titleField.rightView = imageView
titleField.rightViewMode = .always
// titleField.rightView?.isHidden = true
return titleField
}()
Subclass UITextField and override https://developer.apple.com/documentation/uikit/uitextfield/1619638-rightviewrect.
Just add the extension :
extension UITextField {
func rightImage(_ image: UIImage?, imageWidth: CGFloat, padding: CGFloat) {
let imageView = UIImageView()
imageView.frame = CGRect(x: padding + 2, y: 0, width: imageWidth, height: frame.height)
imageView.contentMode = .scaleAspectFit
imageView.image = image
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: imageWidth + padding , height: frame.height))
containerView.addSubview(imageView)
rightView = containerView
rightViewMode = .always
}
}
To use it :
if let image = UIImage(named: imagename + ".png") {
titlefield.rightImage(image, imageWidth: 30, padding: 5)
}
So I have this code:
override func viewDidLoad() {
super.viewDidLoad()
let imageView = UIImageView()
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.layer.borderWidth = 5
imageView.layer.borderColor = UIColor.green.cgColor
NSLayoutConstraint.activate([
imageView.heightAnchor.constraint(equalToConstant: 200),
imageView.widthAnchor.constraint(equalToConstant: 200),
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0),
])
let image = UIImage(named: "3")
//let image = UIImage(named: "3")?.resizeImageWith(newSize: CGSize(width: 5,height: 5))
imageView.image = image
}
That looks like this:
Im trying to resize just the image ( so like from the green border there is a margin) with this extension:
func resizeImageWith(newSize: CGSize) -> UIImage {
let horizontalRatio = newSize.width / size.width
let verticalRatio = newSize.height / size.height
let ratio = min(horizontalRatio, verticalRatio)
let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
But when I use that like this:
let image = UIImage(named: "3")?.resizeImageWith(newSize: CGSize(width: 60,height: 60))
I get the following result:
And same with this:
let image = UIImage(named: "3")?.resizeImageWith(newSize: CGSize(width: 5,height: 5))
The image just get worst.
Is it possible to just resize the image in order to have a margin from the imageView? Thank you!
Change the image view content mode to Center:
imageView.contentMode = .center
I was able to produce what you wanted, but doing away with constraints. Using a container view that holds the imageView as a subview, you can use the container like a frame and set its border width and color.
With the frame in place, you can then resize the image as per your needs by just setting the frame of the imageView. The last 2 lines of the code are commented out, but if you uncomment them, you will see that the image will shrink to fit the new imageView frame size set to (50, 50).
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let containerView = UIView()
containerView.layer.borderWidth = 5
containerView.layer.borderColor = UIColor.green.cgColor
containerView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
containerView.center = view.center
let imageView = UIImageView()
view.addSubview(containerView)
containerView.addSubview(imageView)
let image = UIImage(named: "3")!
imageView.frame = CGRect(origin: imageView.frame.origin, size: CGSize(width: 200, height: 200))
imageView.image = image
imageView.contentMode = .scaleAspectFit
imageView.center = view.convert(containerView.center, to: containerView)
print("Image Width: \(image.size.width)")
print("Image Height: \(image.size.height)")
print("ImageView Width: \(imageView.frame.width)")
print("ImageView Height: \(imageView.frame.height)")
print("Container Width: \(containerView.frame.width)")
print("Container Height: \(containerView.frame.height)")
print("View Center: \(view.center.x),\(view.center.y)")
print("Container Center: \(containerView.center.x),\(containerView.center.y)")
//imageView.frame.size = CGSize(width: 50, height: 50)
//imageView.center = view.convert(containerView.center, to: containerView)
}
}
I used .scaleAspectFit so that the image will be forced to fit whatever size you set the imageView to, while maintaining its original aspect ratio. You can of course change this to suit your needs as well. If you need to set the size of your image in different ways, you'll need to change the imageView's contentMode property as appropriate. More info here:
https://developer.apple.com/documentation/uikit/uiimageview
The convert function just helps to layout the imageView where you want it, within its parent view.
The print debug statements are helpful for checking your layout, but of course, unnecessary.
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)
}
}
I want to customize my app's look by using a logo image as the navigation bar's title, instead of plain text. When I use this code
let logo = UIImage(named: "logo.png")
self.navigationItem.titleView = logo;
I get the error "UIImage is not convertible to UIView". How can I do this correctly?
Put it inside an UIImageView
let logo = UIImage(named: "logo.png")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
I use this. It works in iOS 8
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let image = UIImage(named: "YOURIMAGE")
navigationItem.titleView = UIImageView(image: image)
}
And here is an example how you can do it with CGRect.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 38, height: 38))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "YOURIMAGE")
imageView.image = image
navigationItem.titleView = imageView
}
Hope this will help.
For swift 4 and you can adjust imageView size
let logoContainer = UIView(frame: CGRect(x: 0, y: 0, width: 270, height: 30))
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 270, height: 30))
imageView.contentMode = .scaleAspectFit
let image = UIImage(named: "your_image")
imageView.image = image
logoContainer.addSubview(imageView)
navigationItem.titleView = logoContainer
I tried #Jack's answer above, the logo did appear however the image occupied the whole Navigation Bar. I wanted it to fit.
Swift 4, Xcode 9.2
1.Assign value to navigation controller, UIImage. Adjust size by dividing frame and Image size.
func addNavBarImage() {
let navController = navigationController!
let image = UIImage(named: "logo-signIn6.png") //Your logo url here
let imageView = UIImageView(image: image)
let bannerWidth = navController.navigationBar.frame.size.width
let bannerHeight = navController.navigationBar.frame.size.height
let bannerX = bannerWidth / 2 - (image?.size.width)! / 2
let bannerY = bannerHeight / 2 - (image?.size.height)! / 2
imageView.frame = CGRect(x: bannerX, y: bannerY, width: bannerWidth, height: bannerHeight)
imageView.contentMode = .scaleAspectFit
navigationItem.titleView = imageView
}
Add the function right under viewDidLoad()
addNavBarImage()
Note on the image asset. Before uploading, I adjusted the logo with extra margins rather than cropped at the edges.
Final result:
You can use custom UINavigationItem so, you only need to change "Navigation Item" as YourCustomClass on the Main.storyboard.
In Swift 3
class FixedImageNavigationItem: UINavigationItem {
private let fixedImage : UIImage = UIImage(named: "your-header-logo.png")!
private let imageView : UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 37.5))
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
imageView.contentMode = .scaleAspectFit
imageView.image = fixedImage
self.titleView = imageView
}
}
Here is a handy function for Swift 4.2, shows an image with title text:-
override func viewDidLoad() {
super.viewDidLoad()
//Sets the navigation title with text and image
self.navigationItem.titleView = navTitleWithImageAndText(titleText: "Dean Stanley", imageName: "online")
}
func navTitleWithImageAndText(titleText: String, imageName: String) -> UIView {
// Creates a new UIView
let titleView = UIView()
// Creates a new text label
let label = UILabel()
label.text = titleText
label.sizeToFit()
label.center = titleView.center
label.textAlignment = NSTextAlignment.center
// Creates the image view
let image = UIImageView()
image.image = UIImage(named: imageName)
// Maintains the image's aspect ratio:
let imageAspect = image.image!.size.width / image.image!.size.height
// Sets the image frame so that it's immediately before the text:
let imageX = label.frame.origin.x - label.frame.size.height * imageAspect
let imageY = label.frame.origin.y
let imageWidth = label.frame.size.height * imageAspect
let imageHeight = label.frame.size.height
image.frame = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
image.contentMode = UIView.ContentMode.scaleAspectFit
// Adds both the label and image view to the titleView
titleView.addSubview(label)
titleView.addSubview(image)
// Sets the titleView frame to fit within the UINavigation Title
titleView.sizeToFit()
return titleView
}
this worked for me in Sept 2015 - Hope this helps someone out there.
// 1
var nav = self.navigationController?.navigationBar
// 2 set the style
nav?.barStyle = UIBarStyle.Black
nav?.tintColor = UIColor.yellowColor()
// 3
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
imageView.contentMode = .ScaleAspectFit
// 4
let image = UIImage(named: "logo.png")
imageView.image = image
// 5
navigationItem.titleView = imageView
I have written this for iOS 10 & iOS 11 and it worked for me:
extension UINavigationBar {
func setupNavigationBar() {
let titleImageWidth = frame.size.width * 0.32
let titleImageHeight = frame.size.height * 0.64
var navigationBarIconimageView = UIImageView()
if #available(iOS 11.0, *) {
navigationBarIconimageView.widthAnchor.constraint(equalToConstant: titleImageWidth).isActive = true
navigationBarIconimageView.heightAnchor.constraint(equalToConstant: titleImageHeight).isActive = true
} else {
navigationBarIconimageView = UIImageView(frame: CGRect(x: 0, y: 0, width: titleImageWidth, height: titleImageHeight))
}
navigationBarIconimageView.contentMode = .scaleAspectFit
navigationBarIconimageView.image = UIImage(named: "image")
topItem?.titleView = navigationBarIconimageView
}
}
Swift 5.1+, Xcode 13+
Sometimes if your image is in high resolution then, imageView shifts from centre, I would suggest using this method
lazy var navigationTitleImageView = UIImageView()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationTitleImageView.image = logo
self.navigationTitleImageView.contentMode = .scaleAspectFit
self.navigationTitleImageView.translatesAutoresizingMaskIntoConstraints = false
if let navC = self.navigationController{
navC.navigationBar.addSubview(self.navigationTitleImageView)
self.navigationTitleImageView.centerXAnchor.constraint(equalTo: navC.navigationBar.centerXAnchor).isActive = true
self.navigationTitleImageView.centerYAnchor.constraint(equalTo: navC.navigationBar.centerYAnchor, constant: 0).isActive = true
self.navigationTitleImageView.widthAnchor.constraint(equalTo: navC.navigationBar.widthAnchor, multiplier: 0.2).isActive = true
self.navigationTitleImageView.heightAnchor.constraint(equalTo: navC.navigationBar.widthAnchor, multiplier: 0.088).isActive = true
}
}
and viewWillDisappear()
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationTitleImageView.removeFromSuperview()
}
or else just reduce the image size
If you'd prefer to use autolayout, and want a permanent fixed image in the navigation bar, that doesn't animate in with each screen, this solution works well:
class CustomTitleNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
let logo = UIImage(named: "MyHeaderImage")
let imageView = UIImageView(image:logo)
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
navigationBar.addSubview(imageView)
navigationBar.addConstraint (navigationBar.leftAnchor.constraint(equalTo: imageView.leftAnchor, constant: 0))
navigationBar.addConstraint (navigationBar.rightAnchor.constraint(equalTo: imageView.rightAnchor, constant: 0))
navigationBar.addConstraint (navigationBar.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 0))
navigationBar.addConstraint (navigationBar.bottomAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 0))
}
Programmatically could be done like this.
private var imageView: UIView {
let bannerWidth = navigationBar.frame.size.width * 0.5 // 0.5 its multiplier to get correct image width
let bannerHeight = navigationBar.frame.size.height
let view = UIView()
view.backgroundColor = .clear
view.frame = CGRect(x: 0, y: 0, width: bannerWidth, height: bannerHeight)
let image = UIImage(named: "your_image_name")
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
imageView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
view.addSubview(imageView)
return view
}
The just change titleView
navigationItem.titleView = imageView
let's do try and checkout
let image = UIImage(named: "Navbar_bg.png")
navigationItem.titleView = UIImageView(image: image)
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
imageView.contentMode = .ScaleAspectFit
let imageView = UIImageView(frame: (CGRect(x: 0, y: 0, width: 40, height:
40)))
imageView.contentMode = .scaleAspectFit
let image = UIImage (named: "logo") // logo is your NPG asset
imageView.image = image
self.navigationItem.titleView = imageView
Works for me in swift 4 (square image 40x40)
let imageView = UIImageView()
imageView.frame.size.width = 40
imageView.frame.size.height = 40
imageView.contentMode = .scaleAspectFit
let image = UIImage(named: "YOUR_IMAGE_NAME")
imageView.image = image
navigationItem.titleView = imageView
If you want other measures, try
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 100.5)))
imageView.contentMode = .scaleAspectFit
let image = UIImage(named: "YOUR_IMAGE_NAME")
imageView.image = image
navigationItem.titleView = imageView
I hope it serves you. It works for me.
Objective-C version:
//create the space for the image
UIImageView *myImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 256, 144)];
//bind the image with the ImageView allocated
myImage.image = [UIImage imageNamed:#"logo.png"];
//add image into imageview
_myNavigationItem.titleView = myImage;
Just in case someone (like me) had arrived here looking for the answer in Objective-C.
This worked for me... try it
let image : UIImage = UIImage(named: "LogoName")
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 25, height: 25))
imageView.contentMode = .scaleAspectFit
imageView.image = image
navigationItem.titleView = imageView
In order to get the image view with the proper size and in the center, you should use the following approach:
let width = 120 // choose the image width
let height = 20 // choose the image height
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 44)) //44 is the standard size of the top bar
let imageView = UIImageView(frame: CGRect(x: (view.bounds.width - width)/2, y: (44 - height)/2, width: width, height: height))
imageView.contentMode = .scaleAspectFit //choose other if it makes sense
imageView.image = UIImage(named: "your_image_name")
titleView.addSubview(imageView)
navigationItem.titleView = titleView