how to create button with title under icon and outside frame - ios

I want create button with image like this
and this is my code but it't true with other model iPhone:
extension ButtonWithImage {
func alignVertical(spacing: CGFloat = 6.0) {
guard let imageSize = self.imageView?.image?.size else { return }
guard let titleSize = titleLabel?.intrinsicContentSize else{return}
// Title Edge Insets
let titleEdgeInsets = UIEdgeInsets(top: 0.0 ,
left: -imageSize.width,
bottom: -(self.frame.size.height + 2*spacing),
right: 0.0)
self.titleEdgeInsets = titleEdgeInsets
self.imageEdgeInsets = UIEdgeInsets(top: 0.0,
left: 0.0,
bottom: 0.0,
right: -titleSize.width)
self.contentEdgeInsets = UIEdgeInsets(top: spacing,//edgeOffset,
left: 0.0,
bottom: spacing,//edgeOffset,
right: 0.0)
}
}
what is value of bottom in titleEdgeInsets to working the same with any model iPhone?

please use below extension for simple use
extension UIButton {
func alignCenter(withPadding: CGFloat = 6.0) {
guard
let imageViewSize = self.imageView?.frame.size,
let titleLabelSize = self.titleLabel?.frame.size else {
return
}
let totalHeight = imageViewSize.height + titleLabelSize.height + padding
self.imageEdgeInsets = UIEdgeInsets(
top: -(totalHeight - imageViewSize.height),
left: 0.0,
bottom: 0.0,
right: -titleLabelSize.width
)
self.titleEdgeInsets = UIEdgeInsets(
top: 0.0,
left: -imageViewSize.width,
bottom: -(totalHeight - titleLabelSize.height),
right: 0.0
)
self.contentEdgeInsets = UIEdgeInsets(
top: 0.0,
left: 0.0,
bottom: titleLabelSize.height,
right: 0.0
)
}
}

Related

Programmatic UIButton Constraints Not Working

I'm building a view programmatically where a blue button is supposed to be laid out in the center of the screen under a user image, but it's getting constrained to the top left corner every time. I have self.translatesAutoresizingMaskIntoConstraints set to false in the init method of this view. Here is my code where I restrain this button:
addSubview(continueMessagingButton)
continueMessagingButton.anchor(top: currentUserImage.bottomAnchor, leading: leadingAnchor, bottom: nil, trailing: trailingAnchor, padding: .init(top: 32, left: 48, bottom: 0, right: 48), size: .init(width: 0, height: 60))
continueMessagingButton.layer.cornerRadius = 30
Here is an image of what's happening:
Please help thank you!
full code:
import UIKit
import FirebaseCore
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
import FirebaseAnalytics
class MatchView: UIView {
var userId: String! {
didSet {
API.User.observeCurrentUser { (user) in
self.currentUserImage.sd_setImage(with: URL(string:
user.profileImages!.first!))
self.currentUserImage.alpha = 1
}
API.User.observeUsers(withId: userId) { (user) in
self.otherUserImage.sd_setImage(with: URL(string:
user.profileImages!.first!))
self.otherUserImage.alpha = 1
}
}
}
let partyPopperImage: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName:
"party-popper-emoji"))
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
return imageView
}()
var username: String! {
didSet {
descriptionLabel.text = "Congratulations!\n\(username!) is
interested in you!"
}
}
let descriptionLabel: UILabel = {
let label = UILabel()
label.text = ""
label.lineBreakMode = .byWordWrapping
label.textAlignment = .center
label.textColor = #colorLiteral(red: 0.08732911403, green:
0.7221731267, blue: 1, alpha: 1)
label.font = UIFont(name: "Avenir-Medium", size: 19)
label.numberOfLines = 0
return label
}()
let currentUserImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.borderWidth = 2
imageView.layer.borderColor = #colorLiteral(red: 0.08732911403,
green: 0.7221731267, blue: 1, alpha: 1)
imageView.alpha = 0
return imageView
}()
let otherUserImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.borderWidth = 2
imageView.layer.borderColor = #colorLiteral(red: 0.08732911403,
green: 0.7221731267, blue: 1, alpha: 1)
imageView.alpha = 0
return imageView
}()
let continueMessagingButton: UIButton = {
let button = GlympsGradientButton(type: .system)
button.setTitle("CONTINUE MESSAGING", for: .normal)
button.setTitleColor(#colorLiteral(red: 1, green: 1, blue: 1,
alpha: 1), for: .normal)
button.backgroundColor = #colorLiteral(red: 0.08732911403, green: 0.7221731267, blue: 1, alpha: 1)
button.clipsToBounds = true
return button
}()
let messageLaterButton: UIButton = {
let button = GlympsGradientBorderButton(type: .system)
button.setTitle("Message Later", for: .normal)
button.setTitleColor(#colorLiteral(red: 0.08732911403, green:
0.7221731267, blue: 1, alpha: 1), for: .normal)
button.clipsToBounds = true
button.backgroundColor = .clear
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
continueMessagingButton.translatesAutoresizingMaskIntoConstraints =
true
setupBlurView()
setupLayout()
//setupAnimations()
let tap = UIGestureRecognizer(target: self, action:
#selector(handleDismiss))
self.addGestureRecognizer(tap)
}
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style:
.light))
func setupAnimations() {
let angle = 30 * CGFloat.pi / 180
currentUserImage.transform = CGAffineTransform(rotationAngle: -
angle).concatenating(CGAffineTransform(translationX: 200, y: 0))
otherUserImage.transform = CGAffineTransform(rotationAngle:
angle).concatenating(CGAffineTransform(translationX: -200, y: 0))
continueMessagingButton.transform = CGAffineTransform(translationX:
-500, y: 0)
messageLaterButton.transform = CGAffineTransform(translationX: 500,
y: 0)
UIView.animateKeyframes(withDuration: 1.3, delay: 0, options:
.calculationModeCubic, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration:
0.45, animations: {
self.currentUserImage.transform =
CGAffineTransform(rotationAngle: -angle)
self.otherUserImage.transform =
CGAffineTransform(rotationAngle: angle)
})
UIView.addKeyframe(withRelativeStartTime: 0.8,
relativeDuration: 0.5, animations: {
self.currentUserImage.transform = .identity
self.otherUserImage.transform = .identity
})
}) { (_) in
}
UIView.animate(withDuration: 0.75, delay: 0.6 * 1.3,
usingSpringWithDamping: 0.5, initialSpringVelocity: 0.1, options:
.curveEaseOut, animations: {
self.continueMessagingButton.transform = .identity
self.messageLaterButton.transform = .identity
})
}
func setupLayout() {
addSubview(partyPopperImage)
addSubview(descriptionLabel)
addSubview(currentUserImage)
addSubview(otherUserImage)
addSubview(continueMessagingButton)
//addSubview(messageLaterButton)
partyPopperImage.anchor(top: nil, leading: nil, bottom:
descriptionLabel.topAnchor, trailing: nil, padding: .init(top: 0, left:
0, bottom: 16, right: 0), size: .init(width: 150, height: 150))
partyPopperImage.centerXAnchor.constraint(equalTo:
self.centerXAnchor).isActive = true
descriptionLabel.anchor(top: nil, leading: self.leadingAnchor,
bottom: currentUserImage.topAnchor, trailing: trailingAnchor, padding:
.init(top: 0, left: 0, bottom: 32, right: 0), size: .init(width: 0,
height: 80))
currentUserImage.anchor(top: nil, leading: nil, bottom: nil,
trailing: centerXAnchor, padding: .init(top: 0, left: 0, bottom: 0,
right: 16), size: .init(width: 140, height: 140))
currentUserImage.layer.cornerRadius = 70
currentUserImage.centerYAnchor.constraint(equalTo:
centerYAnchor).isActive = true
otherUserImage.anchor(top: nil, leading: centerXAnchor, bottom:
nil, trailing: nil, padding: .init(top: 0, left: 16, bottom: 0, right:
0), size: .init(width: 140, height: 140))
otherUserImage.layer.cornerRadius = 70
otherUserImage.centerYAnchor.constraint(equalTo:
centerYAnchor).isActive = true
continueMessagingButton.anchor(top: currentUserImage.bottomAnchor,
leading: leadingAnchor, bottom: nil, trailing: trailingAnchor, padding:
.init(top: 32, left: 48, bottom: 0, right: 48), size: .init(width: 0,
height: 60))
continueMessagingButton.layer.cornerRadius = 30
// messageLaterButton.anchor(top:
continueMessagingButton.bottomAnchor, leading:
continueMessagingButton.leadingAnchor, bottom: nil, trailing:
continueMessagingButton.trailingAnchor, padding: .init(top: 16, left:
0, bottom: 0, right: 0), size: .init(width: 0, height: 60))
// messageLaterButton.layer.cornerRadius = 30
self.layoutIfNeeded()
}
func setupBlurView() {
addSubview(visualEffectView)
visualEffectView.fillSuperview()
visualEffectView.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping:
1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.visualEffectView.alpha = 1
}) { (_) in
}
}
#objc func handleDismiss() {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping:
1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.alpha = 0
}) { (_) in
self.removeFromSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I've figured out the issue. For my gradient colors I had:
let leftColor = UIColor.blue
let rightColor = UIColor.green
gradientLayer.colors = [leftColor, rightColor]
Once I added .cgColor to the ends of these, it worked:
gradientLayer.colors = [leftColor.cgColor, rightColor.cgColor]
Super minor, but this fixed the gradient!
I also needed to change the frame from
self.frame
to
gradientLayer.frame
Also minor, but this fixed the button location.

How to make custom class for auto layouts?

Like we make custom classes for UIButton and other items of UIKit.
Just we define our layouts in that class and further use them as we do in case of other custom class.
If it can not happen, kindly comment that why it can't be done?
The below extension can be used for your requirement
extension UIView {
public func anchor(top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, topConstant: CGFloat = 0, leftConstant: CGFloat = 0, bottomConstant: CGFloat = 0, rightConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0) {
translatesAutoresizingMaskIntoConstraints = false
var anchors = [NSLayoutConstraint]()
if let top = top {
anchors.append(topAnchor.constraint(equalTo: top, constant: topConstant))
}
if let left = left {
anchors.append(leftAnchor.constraint(equalTo: left, constant: leftConstant))
}
if let bottom = bottom {
anchors.append(bottomAnchor.constraint(equalTo: bottom, constant: -bottomConstant))
}
if let right = right {
anchors.append(rightAnchor.constraint(equalTo: right, constant: -rightConstant))
}
if widthConstant > 0 {
anchors.append(widthAnchor.constraint(equalToConstant: widthConstant))
}
if heightConstant > 0 {
anchors.append(heightAnchor.constraint(equalToConstant: heightConstant))
}
anchors.forEach({$0.isActive = true})
}
public func anchor(centerX: NSLayoutXAxisAnchor? = nil, centerY: NSLayoutYAxisAnchor? = nil, xConstant: CGFloat = 0, yConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0) {
self.translatesAutoresizingMaskIntoConstraints = false
var anchors = [NSLayoutConstraint]()
if let centerX = centerX {
anchors.append(centerXAnchor.constraint(equalTo: centerX, constant: xConstant))
}
if let centerY = centerY {
anchors.append(centerYAnchor.constraint(equalTo: centerY, constant: yConstant))
}
if widthConstant > 0 {
anchors.append(widthAnchor.constraint(equalToConstant: widthConstant))
}
if heightConstant > 0 {
anchors.append(heightAnchor.constraint(equalToConstant: heightConstant))
}
anchors.forEach({$0.isActive = true})
}
}
as
label.anchor(centerX: view.centerXAnchor, centerY: view.centerYAnchor, xConstant: 20, yConstant: 5, widthConstant: screenSize.width, heightConstant: height1)
and
label.anchor(top: nil, left: customCell.leftAnchor, bottom: customCell.bottomAnchor, right: customCell.rightAnchor, topConstant: 0, leftConstant: 22, bottomConstant: 0, rightConstant: 22, widthConstant: width, heightConstant: btnHeigght)

How does UITableViewController change the table view's `adjustedContentInsets` when the keyboard appears?

When a UITableView governed by a UITableViewController has cells with text fields in them, if the user taps in a text field, the table view scrolls to keep that text field above the keyboard.
How does it do that? I tried to figure it out by implementing this method with a bunch of logging:
override func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView) {
print("did adjust")
print("contentInset", self.tableView.contentInset)
print("indicatorInsets", self.tableView.scrollIndicatorInsets)
print("adjustedContentInsets", self.tableView.adjustedContentInset)
print("safe area", self.tableView.safeAreaInsets)
print("additional safe area", self.additionalSafeAreaInsets)
}
Here's the output from before and after the tap-and-scroll:
did adjust
contentInset UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
indicatorInsets UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
adjustedContentInsets UIEdgeInsets(top: 64.0, left: 0.0, bottom: 0.0, right: 0.0)
safe area UIEdgeInsets(top: 64.0, left: 0.0, bottom: 0.0, right: 0.0)
additional safe area UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
did adjust
contentInset UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
indicatorInsets UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
adjustedContentInsets UIEdgeInsets(top: 64.0, left: 0.0, bottom: 253.0, right: 0.0)
safe area UIEdgeInsets(top: 64.0, left: 0.0, bottom: 0.0, right: 0.0)
additional safe area UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
After the scroll, the bottom of the adjustedContentInsets has changed. But how? It's not a settable property. It's supposed to respond to the safe area, but the safe area has not changed. The contentInset has not changed. How is this accomplished? How would I do the same thing with my own scroll views? (My solution currently is to change the contentInset, but clearly the table view controller doesn't have to do that.)

How to remove left padding from UIButton?

How to remove left padding from UIButton?
I have been created button with this code:
let button = UIButton(...)
button.setImage(UIImage(named: "plus")?.withRenderingMode(.alwaysTemplate), for: .normal)
button.setTitle("Text", for: .normal)
button.layer.cornerRadius = 8
button.layer.backgroundColor = UIColor.red.cgColor
You need to adjust the imageEdgeInsets and titleEdgeInsets with some negative left value. Then it will shift to left. I tested it's working. 100 is temp value.
button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: -100.0, bottom: 0.0, right: 0.0)
button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -100.0, bottom: 0.0, right: 0.0)
Let me know if it is not working.
This line could fix your issue
button.titleEdgeInsets.left = 0 // add left padding.
Or maybe you could use negative value in this case
There is also this way :
button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
Just try different values !

How do I put the image on the right side of the button and the text align left

I have a UIButton with image and text. How do I align the image to the right, and align the text to the left?
Use below two methods
button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: 0, bottom: 0.0, right: 0.0)
button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: 0, bottom: 0.0, right: 0.0)
Pass value for left and right and adjust it.
Set offset as per you requirement.
#IBDesignable class RightImageButton: UIButton {
#IBInspectable var alignImageToRight: Bool = true
override func layoutSubviews() {
super.layoutSubviews()
if alignImageToRight {
if let imageView = self.imageView, let titleLabel = self.titleLabel {
let imageWidth = imageView.frame.size.width
var imageFrame: CGRect = imageView.frame;
var labelFrame: CGRect = titleLabel.frame;
labelFrame.origin.x = self.titleEdgeInsets.left + self.contentEdgeInsets.left
imageFrame.origin.x = frame.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right - imageWidth
imageView.frame = imageFrame;
titleLabel.frame = labelFrame;
}
}
}
}

Resources