I need help to design a button which attached to imageView - ios

I am trying to build a imageview with a button that attached to itself for settings page. I want to tell users to click to image if they want to change it. So what I wanna to do is similar to : this
I was designin my app with storyboard but I couldn't find a way to do it.
So I tried to set constraints programmatically.
For example,
`
editButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
editButton.trailingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: -66),
editButton.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: -60)
])
`
This constraints works for iPad screen but not for any iPhones. There must be another way to design such things. How can I do it?

All of this can be done with storyboards or using constraints in code. Should be the same for iPhone or iPad. For example:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let myImageView = UIImageView()
let myImageViewCornerRadius: CGFloat = 40.0
// Just using a color for the example...
myImageView.backgroundColor = .blue
myImageView.layer.cornerRadius = myImageViewCornerRadius
myImageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myImageView)
let myEditButton = UIButton()
// Again using a color...
myEditButton.backgroundColor = .red
myEditButton.translatesAutoresizingMaskIntoConstraints = false
myEditButton.layer.cornerRadius = 10.0
view.addSubview(myEditButton)
NSLayoutConstraint.activate([
myImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
myImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
myImageView.widthAnchor.constraint(equalToConstant: 80.0),
myImageView.heightAnchor.constraint(equalToConstant: 80.0),
myEditButton.centerYAnchor.constraint(equalTo: myImageView.bottomAnchor,
constant: -myImageViewCornerRadius / 4.0),
myEditButton.centerXAnchor.constraint(equalTo: myImageView.trailingAnchor,
constant: -myImageViewCornerRadius / 4.0),
myEditButton.widthAnchor.constraint(equalToConstant: 20.0),
myEditButton.heightAnchor.constraint(equalToConstant: 20.0)
])
self.view = view
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

I would make the origin of the frame of the button reference the frame of the profile photo. So the button is rendered in the same place relative to the photo no matter the size of the photo. Maybe something like this:
editButton.frame = CGRect(x: profileImageView.width - 60, y: profileImageView.height - 66, width: 50, height: 50)
You could also consider adding a tapGestureRecognizer to the photo to trigger the edit option.

Related

Constraints Issues On UI button

While practicing programmatic constraints using anchors ,I came across a problem that hides the visibility of the button when using an iPhone 8 or 8 plus simulator as shown in the image below. This is due to the current coordinate values I set for the button. However the button becomes visible when I switch to an iPhone 12. How do I set the co-ordinate values in a way that makes the button visible and in same positions on the iPhone 8 or 8 plus ?
let iosImageView: UIImageView = {
let imageview = UIImageView(image: #imageLiteral(resourceName: "icons8-ios-logo-128"))
imageview.translatesAutoresizingMaskIntoConstraints = false
return imageview
}()
let press: UIButton = {
let buttonPress = UIButton.init(type: .roundedRect)
buttonPress.setTitle("Tap Me", for: .normal)
buttonPress.backgroundColor = .black
buttonPress.frame = CGRect(x: 110, y: 700, width: 200, height: 50)
return buttonPress
}()
override func viewDidLoad() {
super.viewDidLoad()
addSubviews()
setConstraints()
// Do any additional setup after loading the view.
}
func addSubviews(){
view.addSubview(iosImageView)
view.addSubview(press)
}
func setConstraints(){
NSLayoutConstraint.activate([
iosImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
iosImageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
iosImageView.widthAnchor.constraint(equalToConstant: 200),
iosImageView.heightAnchor.constraint(equalToConstant: 200),
press.centerXAnchor.constraint(equalTo: view.centerXAnchor),
press.leadingAnchor.constraint(equalTo: view.leadingAnchor),
press.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
Your constraints for press are invalid. You failed to specify a vertical position. And you forgot to set translatesAutoresizingMaskIntoConstraints to be false. I’m surprised the button ever appears.
(Also cut the line about buttonPress.frame. Frame and constraints are opposites; use one or the other.)

Programatically creating constraints in a view isn't account for navigation controller despite using safeAreaLayoutGuide

I have created a UINavigationController class which allows users to Log out and displays the title of the app. I then added a UITabController as its only viewController in its viewControllers array:
let homeController = HomeController()
viewControllers = [homeController]
This UITabController (HomeController()) is then populated with a few UIViewControllers - one of which will display a Profile page. This is my first project in which I won't be using the storyboard so things have been a great challenge!
I have created a UIImageView object within the class and within my viewDidLoad for my profile page, I have used:self.view.addSubview(imageView)to add to view and then:imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true in an attempt to anchor the image to the bottom of the UINavigationController bar at the top of the screen.However the result places the image at the very top of the screen, as if the Navigation Bar isn't recognised as being visible. I read in this article: https://medium.com/#amlcurran/a-quick-guide-to-laying-out-views-in-ios-471e92deb74, that '.topLayoutGuide.bottomAnchor' represents the bottom of the navigation bar, but this has now been depreciated to my example above.
Does anyone have any ideas as to what is wrong?And also any good resources for me to fully understand programmatically constraining my elements!Thanks all!!
https://gist.github.com/JoeMcGeever/a5ce3be94fc49a8f27b1a2867bd9495b
That link shows some of the code so far - I am aware the other elements are also pinned to the top; I am just trying to fix this error regarding the navigation bar first.
Image showing what the view displays at the moment
You should really go through several auto-layout tutorials. There are many, many of them out there. After you've worked through a dozen or so, you should have a good idea of what needs to be done.
In the meantime, here is your ProfileViewController edited to give you an idea of what you were doing wrong:
class ProfileViewController : UIViewController {
let imageView : UIImageView = { //creates an image view with the name "imageView"
let image = UIImage(named: "logo")
let imageView = UIImageView(image: image)
return imageView
}()
let usernameLabel = UILabel()
// if you're addint a target referring to "self", this must be a lazy var
lazy var editProfileButton : UIButton = {
let editButton = UIButton()
editButton.backgroundColor = .orange
editButton.setTitle("Edit Profile", for: .normal)
editButton.setTitleColor(.white, for: .normal)
editButton.addTarget(self, action: #selector(handleEdit), for: .touchUpInside)
return editButton
}()
#objc func handleEdit(){
//edit handle button
print("Edit profile")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.title = "Profile"
usernameLabel.text = "Username Here"
// we're going to use auto-layout
[imageView, usernameLabel, editProfileButton].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
}
self.view.addSubview(imageView)
self.view.addSubview(usernameLabel)
self.view.addSubview(editProfileButton)
// need FULL sets of constraints, not just TOP anchors
// respect safe-area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// image view at upper-left
// image view 8-pts from top of safe area
imageView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
// and 8-pts from left
imageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
// give it a width of, for example, one-quarter the view width
imageView.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.25),
// give it a 1:1 ratio (square)
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor),
// button at upper-right
editProfileButton.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
editProfileButton.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
// no width or height... let the button size itself
// label below the image view
usernameLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 8.0),
usernameLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
// no width or height... let the label size itself
])
// give the name label a background color so we can see its frame
usernameLabel.backgroundColor = .cyan
}
}
Review the comments in the code to understand what I did.
Result will look about like this (I used a random image for the logo):
If you want to anchor your imageView to the top of safeArea, you have to constraint it to the topAnchor like this:
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true

Align UIButton and UILabel text with different font sizes

I have a UIButton and a UILabel displayed inline. They have different size fonts, however I would like to align them so they appear on the same line.
At the moment the UILabel is slight above the baseline of the UIButton.
I was hoping to avoid manually setting a content offset as I want this to scale correctly where possible. I worry manual calculations may have unexpected side effects on changing font sizes etc.
I have created a playground that should show the 2 elements:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
lazy var nameButton = configure(UIButton(type: .system), using: {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.titleLabel?.font = .systemFont(ofSize: 18)
$0.setTitleColor(.darkGray, for: .normal)
$0.contentHorizontalAlignment = .leading
$0.setContentHuggingPriority(UILayoutPriority.defaultHigh, for: .horizontal)
$0.backgroundColor = .lightGray
$0.setTitle("This is a button", for: .normal)
})
lazy var publishedDateLabel = configure(UILabel(frame: .zero), using: {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.font = .systemFont(ofSize: 14)
$0.textColor = .darkGray
$0.setContentHuggingPriority(UILayoutPriority.defaultLow, for: .horizontal)
$0.backgroundColor = .lightGray
$0.text = "and this is a label"
})
override func loadView() {
let view = UIView()
view.backgroundColor = .white
[nameButton, publishedDateLabel].forEach(view.addSubview(_:))
NSLayoutConstraint.activate([
nameButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
nameButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
publishedDateLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
publishedDateLabel.leadingAnchor.constraint(equalTo: nameButton.trailingAnchor),
publishedDateLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8)
])
self.view = view
}
// setup helper method
func configure<T>(_ value: T, using closure: (inout T) throws -> Void) rethrows -> T {
var value = value
try closure(&value)
return value
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
I have tried making the label and button the same height by adding publishedDateLabel.heightAnchor.constraint(equalTo: nameButton.heightAnchor)
This didn't change the alignment however.
I also tried using publishedDateLabel.lastBaselineAnchor.constraint(equalTo: nameButton.lastBaselineAnchor)
to align the anchors however this aligned the top of the elements
How can align the bottom of the text in the button to the bottom of the text in the label?
Just comment out the heightAnchor use the lastBaselineAnchor:
NSLayoutConstraint.activate([
nameButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
nameButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
publishedDateLabel.lastBaselineAnchor.constraint(equalTo: nameButton.lastBaselineAnchor),
publishedDateLabel.leadingAnchor.constraint(equalTo: nameButton.trailingAnchor),
publishedDateLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8)
])

MGLMapView does not show any object added to the view controller

I have properly set up an Viewcontroller containing an UIView with class "MGLMapView", what I am trying add an button to the Viewcontroller, but when I run the app the button does not show.
Same if I do an external Viewcontroller and overlay the MapViewController, it runs, but it does not show.
Why is that? have anybody had a similar problem? and how do I solve it?
Thanks in advance!
I don't know about the MGLMapView but it should adhere to same rules as any other UIView object.
This example is based on a MKMapView but it should be analog for MGMapView. Put this code in your VC and add setUpViews() to your viewDidLoad() method.
Note: this code should put the MKMapView at the bottom of the view stack and the map view should take up the entire view (except the top 64 pts--I assumed a UINavigationView might be in use--if not just change 64.0 to 0.0 in the constraints). Then it adds a UIButton on top of the MKMapView centered in the x direction with a width of 150 a height of 40 and 20 from the bottom of the view.
let map: MKMapView = {
let view = MKMapView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let button: UIButton = {
let view = UIButton()
// Add or change attributes as you need
view.backgroundColor = UIColor.green
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
fileprivate func setUpViews(){
// Add the map first
self.view.addSubview(map)
// Add the button now it will be on top of the map view
self.view.addSubview(button)
map.delegate = self;
NSLayoutConstraint.activate([
map.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 64.0),
map.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
map.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
map.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
])
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0.0),
button.heightAnchor.constraint(equalToConstant: 40.0),
button.widthAnchor.constraint(equalToConstant: 150.0),
button.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -20.0),
])
}

Dynamic font resizing in collectionview [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
for my app I implemented a collectionview showing cards, that are rotated in a carousel-like animation. My problem is that the cards themselves resize correctly when swiped, but the fonts stay the same size or resize incorrectly. To be specific, the answers (bottommost 5 labels) are in a stackview.
Things I tried:
AutoLayout
Autoshrink
adjustsFontSizeToFitWidth
any number of different constraints
I attached a few screenshots below, where I colored the labels for better visibility.
To change the size of a view and have all of it's subviews / buttons / labels / etc scale with it - including label fonts, you are better off using CGAffineTransform for scaling.
Here is a simple example. It can be pasted into a Playground page to see the effect:
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let theStackView: UIStackView = {
let sv = UIStackView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.axis = .vertical
sv.distribution = .equalCentering
sv.alignment = .center
return sv
}()
let theContainerView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .green
return v
}()
let btn: UIButton = {
let b = UIButton()
b.setTitle("Tap to Scale", for: .normal)
b.backgroundColor = .red
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
// on button tap, scale the Container view by 50% both ways
// note that Container view's subviews also scale
func btnTapped(_ sender: Any) {
theContainerView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
}
override func viewDidLoad() {
super.viewDidLoad()
// add the button to self.view
self.view.addSubview(btn)
// button position
btn.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
btn.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 20.0).isActive = true
// add a target for the button tap
btn.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
// add our "Container" view
view.addSubview(theContainerView)
// add our Stack view to the Container view
theContainerView.addSubview(theStackView)
// add 5 labels to the Stack view
for i in 1...5 {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 20.0)
label.text = "This is Label \(i)"
label.backgroundColor = .cyan
label.translatesAutoresizingMaskIntoConstraints = false
theStackView.addArrangedSubview(label)
}
// pin Container view 20-pts from the bottom of the button, and 8-pts from left, right and bottom
theContainerView.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 20.0).isActive = true
theContainerView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
theContainerView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
theContainerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
// pin Stack view 8-pts from top, left, right and bottom of the Container view
theStackView.topAnchor.constraint(equalTo: theContainerView.topAnchor, constant: 8.0).isActive = true
theStackView.leftAnchor.constraint(equalTo: theContainerView.leftAnchor, constant: 8.0).isActive = true
theStackView.rightAnchor.constraint(equalTo: theContainerView.rightAnchor, constant: -8.0).isActive = true
theStackView.bottomAnchor.constraint(equalTo: theContainerView.bottomAnchor, constant: -8.0).isActive = true
}
}
let vc = TestViewController()
vc.view.backgroundColor = .yellow
PlaygroundPage.current.liveView = vc

Resources