Peculiar top margin in the ImageView added from ChildViewController - ios

I have created a child view controller as below. It has a UIImageView. I added the UIImageView to the view as below.
class SampleChildViewController : UIViewController {
let imageView : UIImageView = {
let imageview = UIImageView()
imageview.translatesAutoresizingMaskIntoConstraints = false
imageview.clipsToBounds = true
imageview.contentMode = .scaleAspectFit
imageview.image = UIImage(named: "cat")
return imageview
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(imageView)
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: view.topAnchor),
imageView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10),
imageView.widthAnchor.constraint(equalToConstant: 150),
imageView.heightAnchor.constraint(equalToConstant: 150)
])
}
}
This is how the parent view controller looks like.
class ViewController: UIViewController {
let child : SampleChildViewController = SampleChildViewController()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
child.view.translatesAutoresizingMaskIntoConstraints = false
addChild(child)
child.didMove(toParent: self)
view.addSubview(child.view)
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
child.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 8),
child.view.leftAnchor.constraint(equalTo: view.leftAnchor),
child.view.rightAnchor.constraint(equalTo: view.rightAnchor),
])
}
}
Now the problem is I have a strange top margin to the imageview as shown below. How to fix it?

problem is with imageview.contentMode = .scaleAspectFit. The boundary you see for the image is not the real boundary. Set the content mode as imageview.contentMode = .scaleAspectFill as it'll fill the whole view.
It should look something below
let imageView : UIImageView = {
let imageview = UIImageView()
imageview.translatesAutoresizingMaskIntoConstraints = false
imageview.clipsToBounds = true
imageview.contentMode = .scaleAspectFill
imageview.image = UIImage(named: "cat")
return imageview
}()

Related

add ui label to ui imageview on collectionview

I am new to swift - I want to add a label ONTO the ui image view image in a collectionview, however i am having some issues. The text sits below the image view, how can i adjust it so it stays in the middle of the image. I want to do this in code and not use storyboards or a nib file. I believe it may be due to my frames i have set:
import UIKit
class ExploreCollectionViewCell: UICollectionViewCell {
static let identifier = "ExploreCollectionViewCell"
private let label: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 13)
return label
}()
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 0
imageView.contentMode = .scaleAspectFill
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(label)
contentView.addSubview(imageView)
}
required init?(coder: NSCoder) {
fatalError()
}
override func layoutSubviews() {
super.layoutSubviews()
label.frame = CGRect(x: 5, y: 0, width: contentView.frame.size.width-10, height: 50)
//imageView.frame = contentView.bounds
imageView.frame = CGRect(x: 0, y: 0, width: 250, height: 250)
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
}
func configure(with urlString: String, label: String) {
guard let url = URL(string: urlString) else {
return
}
let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let data = data, error == nil else {
return
}
DispatchQueue.main.async {
self?.label.text = label
let image = UIImage(data: data)
self?.imageView.image = image
}
}
task.resume()
}
}
First, add the imageView before adding the label, so that it will be shown behind the label:
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(imageView) // behind
contentView.addSubview(label) // front
}
Second, it would be easier to use auto layout:
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.widthAnchor.constraint(equalToConstant: 250).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 250).isActive = true
label.translatesAutoresizingMaskIntoConstraints = false
label.centerYAnchor.constraint(equalTo: imageView.centerYAnchor).isActive = true
label.widthAnchor.constraint(equalTo: imageView.widthAnchor).isActive = true
private let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .white
label.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 13)
return label
}()
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 0
imageView.contentMode = .scaleAspectFill
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(label)
contentView.addSubview(imageView)
imageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true
label.heightAnchor.constraint(equalToConstant: 50).isActive = true
label.centerYAnchor.constraint(contentView.centerYAnchor).isActive = true
label.centerXAnchor.constraint(contentView.centerXAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true
}
required init?(coder: NSCoder) {
fatalError()
}

displaying images in a stack view

Is it possible to display an image from the assets folder to a uistackview programmatically? If so, how would you go about doing it?
I already know how to create a stack view filled with labels.
fileprivate lazy var stack: UIStackView = {
let stack = UIStackView(arrangedSubviews: [goalCompleteLabel, completeMoreGoalsLabel])
stack.translatesAutoresizingMaskIntoConstraints = false
stack.axis = .vertical
return stack
} ()
First set your image in imageView (set in it its constraints for more control of image dimension) and your label under your class controller:
let image: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "yourImage")?.withRenderingMode(.alwaysOriginal)
imageView.backgroundColor = .gray
imageView.layer.cornerRadius = 8
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
return imageView
}()
let completeMoreGoalsLabel: UILabel = {
let label = UILabel()
label.text = "Dummytext"
label.textAlignment = .center
return label
}()
now set your stack view with distribution fillProportionally:
lazy var stack: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [image, completeMoreGoalsLabel])
stackView.axis = .vertical
stackView.distribution = .fillProportionally
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
in viewDidLoad present your stack and add constraints:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .darkGray
view.addSubview(stack)
stack.widthAnchor.constraint(equalToConstant: 200).isActive = true
stack.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stack.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
stack.heightAnchor.constraint(equalToConstant: 250).isActive = true //200 imageHeight + 50 label height
}
I add corner radius on image to make it more cute...
Yes. You simply need to add an ImageView as an arranged subview of your stackview. Just like the labels. Here's the code -
class StackViewController: UIViewController {
var stackView = UIStackView()
var label = UILabel()
var imageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
configStackView()
}
func configStackView() -> Void {
// Add StackView as SubView
view.addSubview(stackView)
// Set StackView properties
stackView.axis = .vertical
stackView.alignment = .center
stackView.distribution = .equalSpacing
// Set imageView as 1st arranged subview of stackview
stackView.addArrangedSubview(imageView)
configImageView()
// Set Label as 2nd arranged subview of stackview
stackView.addArrangedSubview(label)
configLabel()
// Set StackView Constraints
setStackViewCostraints()
}
func setStackViewCostraints() -> Void {
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 200).isActive = true
}
func configImageView() -> Void {
imageView.image = UIImage(named: "bolt")
imageView.contentMode = .scaleAspectFit
// Set Constraints (ideally in a separate function)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
}
func configLabel() -> Void {
label.text = "Label"
}
}
Here's the how it renders -

Swift ios how to set nav bar image not stretch

I have made it possible to add a background image to a nav bar using the ff code but the image is stretched. Is there any way that it will not be stretched?
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "BG.jpg"), for: .default)
You could try this,
UINavigationBar.appearance().setBackgroundImage(UIImage(named: "BG.jpg")!.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch), for: .default)
Try out other options in the code as well.
UPDATE
You can even try below category for UINavigationBar
extension UINavigationController {
func setBackgroundImage(_ image: UIImage) {
navigationBar.isTranslucent = true
navigationBar.barStyle = .blackTranslucent
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
view.insertSubview(imageView, belowSubview: navigationBar)
NSLayoutConstraint.activate([
imageView.leftAnchor.constraint(equalTo: view.leftAnchor),
imageView.rightAnchor.constraint(equalTo: view.rightAnchor),
imageView.topAnchor.constraint(equalTo: view.topAnchor),
imageView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor)
])
}
}
Above code may be vary depending on your final requirements.
class TutorialViewController: UIViewController {
// This property will set the Image to Navigation Bar
public var navigationBarImage: UIImage? {
get {
return (navigationItem.titleView as? UIImageView)?.image
} set {
if newValue != nil {
let imageView = UIImageView(image: newValue)
imageView.contentMode = .scaleAspectFill
navigationItem.titleView = imageView
} else {
navigationItem.titleView = nil
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
navigationBarImage = #imageLiteral(resourceName: "my_nav_image")
}
for all images you can set the content mode =
.scaleToFill (UIViewContentModeScaleToFill)
.scaleAspectFit (UIViewContentModeScaleAspectFit)
.scaleAspectFill (UIViewContentModeScaleAspectFill)
If you do not want to see the contents that are outside the bounds you need to remember to set clipsToBounds to true on the containing superview
View.clipsToBounds = true

iOS autolayout locating images at the same line with same ration for each views

I am working on studying iOS autolayout
However, which constraints and functions should I use for making those views have the same location.
I mean, I want to locate those two UIImageView at center like the first picture. But, whenever I change the UIView, they go down and down... what should I do?
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
let firstView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "angry").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let secondView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "crying").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let thirdView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "heartEmpty").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let fourthView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "joy").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
func setupViews() {
view.addSubview(firstView)
// setup first view
firstView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
firstView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
firstView.widthAnchor.constraint(equalToConstant: 80).isActive = true
firstView.heightAnchor.constraint(equalToConstant: 80).isActive = true
view.addSubview(secondView)
// setup second view
secondView.leftAnchor.constraint(equalTo: firstView.rightAnchor, constant: 20).isActive = true
secondView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
secondView.widthAnchor.constraint(equalToConstant: 80).isActive = true
secondView.heightAnchor.constraint(equalToConstant: 80).isActive = true
view.addSubview(thirdView)
thirdView.leftAnchor.constraint(equalTo: secondView.rightAnchor, constant: 20).isActive = true
thirdView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
thirdView.widthAnchor.constraint(equalToConstant: 80).isActive = true
thirdView.heightAnchor.constraint(equalToConstant: 80).isActive = true
view.addSubview(fourthView)
fourthView.leftAnchor.constraint(equalTo: thirdView.rightAnchor, constant: 20).isActive = true
fourthView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
fourthView.widthAnchor.constraint(equalToConstant: 80).isActive = true
fourthView.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
}
Hello My Friend You Can Make It By Code Or By Storyboard using stack view i will show you by code below hope this help you
import UIKit
class ViewController: UIViewController {
let firstView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "MyImage").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let secondView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "image").withRenderingMode(.alwaysOriginal)
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func setupViews() {
view.addSubview(firstView)
// setup first view
firstView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
firstView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
firstView.widthAnchor.constraint(equalToConstant: 80).isActive = true
firstView.heightAnchor.constraint(equalToConstant: 80).isActive = true
view.addSubview(secondView)
// setup second view
secondView.leftAnchor.constraint(equalTo: firstView.rightAnchor, constant: 20).isActive = true
secondView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
secondView.widthAnchor.constraint(equalToConstant: 80).isActive = true
secondView.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
}
Follow these Steps, you can do it in Storyboard.
1 - Select first Image, align it horizontally and vertically in container by giving it constraints using the "align" tab which is usually located at the bottom-right corner of the storyboard window.
2 - Now, select the first image and goto Size Inspector.Scroll down to it's constraints and there will be a constraint named as "Align Center X To : SuperView".
3 - There will be an "Edit" label right beside it.Click on it, and a popover will show up.
4 - in the popover , in the first Line it will show Constant = 0.
5 - Now here's the fun part, if you put negative value in it , say "-20" it will move 20 spaces to the left.Similarly, if you put "20", it will move 20 spaces to the right.
Now, do the same for the second image until you have achieved your result. Both the images will now be in the centre of the screen.
I am new to IOS as Well, but this worked for me and I hope it works for u as well. :-)

iOS auto_resizing code for each layouts

Hi I am working on creating a view with code below.
I would like to make this code to auto layout to each iPhone sizes.
Which code should I add more?
There exist four emoticons in this code in the view, so I want to make each of them resizing itself regardless of iPhone layout such as iPhone 8, SE, 8+ and so on.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
let firstView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "angry").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let secondView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "crying").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let thirdView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "heartEmpty").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let fourthView:UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "joy").withRenderingMode(.alwaysOriginal)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
func setupViews() {
view.addSubview(firstView)
// setup first view
firstView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
firstView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
firstView.widthAnchor.constraint(equalToConstant: 80).isActive = true
firstView.heightAnchor.constraint(equalToConstant: 80).isActive = true
view.addSubview(secondView)
// setup second view
secondView.leftAnchor.constraint(equalTo: firstView.rightAnchor, constant: 20).isActive = true
secondView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
secondView.widthAnchor.constraint(equalToConstant: 80).isActive = true
secondView.heightAnchor.constraint(equalToConstant: 80).isActive = true
view.addSubview(thirdView)
thirdView.leftAnchor.constraint(equalTo: secondView.rightAnchor, constant: 20).isActive = true
thirdView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
thirdView.widthAnchor.constraint(equalToConstant: 80).isActive = true
thirdView.heightAnchor.constraint(equalToConstant: 80).isActive = true
view.addSubview(fourthView)
fourthView.leftAnchor.constraint(equalTo: thirdView.rightAnchor, constant: 20).isActive = true
fourthView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
fourthView.widthAnchor.constraint(equalToConstant: 80).isActive = true
fourthView.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
}
It's better to insert them all in a horizontal UIStackView with fill-Equally, by this items will resize according to the current size of the stackview

Resources