Force label to display it's text - ios

I want to include a voting function similar to the reddit app. I think a UIStackView would be perfect for this. Now I'm struggling to make the label between the vote-up and vote-down button display it's text.
I've tried to change the contentCompression to .fittingSizeLevel and to .defaultHigh but this seems to change nothing. On the image you can see, there would be plenty of space to fit the whole text, but it doesn't. What aspect am I missing?
class VotingStackView: UIStackView {
let arrowUpButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.tintColor = GSSettings.UI.Colors.tintColor
button.imageView?.contentMode = .scaleAspectFit
button.contentEdgeInsets = UIEdgeInsets(top: 16, left: 0, bottom: 16, right: 0)
button.clipsToBounds = true
return button
}()
let arrowDownButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.tintColor = GSSettings.UI.Colors.tintColor
button.imageView?.contentMode = .scaleAspectFit
button.contentEdgeInsets = UIEdgeInsets(top: 16, left: 0, bottom: 16, right: 0)
button.clipsToBounds = true
return button
}()
let percentageLabel: UILabel = {
let label = UILabel()
label.text = "100%"
label.textColor = GSSettings.UI.Colors.regularTextColor
label.font = GSSettings.UI.Fonts.helveticaLight?.withSize(20)
label.clipsToBounds = false
label.setContentCompressionResistancePriority(UILayoutPriority.fittingSizeLevel, for: .horizontal)
return label
}()
var views: [UIView] = [UIView]()
//MARK: - Init & View Loading
override init(frame: CGRect) {
super.init(frame: frame)
views = [arrowUpButton, percentageLabel ,arrowDownButton]
setupStackView()
setupImages()
setupSubviews()
}
//MARK: - Setup
func setupStackView() {
self.axis = .horizontal
self.spacing = 0
self.alignment = .center
self.distribution = .fillEqually
}
func setupImages() {
let upImage = UIImage(named: "arrow_up")
let downImage = UIImage(named: "arrow_down")
arrowUpButton.setImage(upImage, for: .normal)
arrowDownButton.setImage(downImage, for: .normal)
}
func setupSubviews() {
for view in views {
addArrangedSubview(view)
}
layoutIfNeeded()
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The votingStackView is part of another StackView:
class BottomStackView: UIStackView {
let votingStackView: VotingStackView = {
let stackview = VotingStackView()
return stackview
}()
let addFriendButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.tintColor = GSSettings.UI.Colors.tintColor
button.setImage(UIImage(named: "plus")?.withRenderingMode(.alwaysTemplate), for: .normal)
return button
}()
let redView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
var views: [UIView] = [UIView]()
//MARK: - Init & View Loading
override init(frame: CGRect) {
super.init(frame: frame)
views = [votingStackView, addFriendButton, redView]
setupStackView()
setupSubviews()
}
//MARK: - Setup
func setupStackView() {
self.axis = .horizontal
self.spacing = 0
self.alignment = .leading
self.distribution = .fillEqually
}
func setupSubviews() {
for view in views {
addArrangedSubview(view)
}
layoutIfNeeded()
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Change
label.setContentCompressionResistancePriority(UILayoutPriority.fittingSizeLevel, for: .horizontal)
to
label.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .horizontal)
From the docs it seems that fittingSizeLevel does not take into account parent constraints, so using defaultHigh seems like the safer option.

Related

Button in UIStackView not clickable

I'm trying to add a button to my stack view. The button has a buttonTapped method that should be called when it is tapped. The problem is it is never being called, the button does not seem to be clickable.
class CustomButton: UIViewController {
var buttonDelegate: ButtonDelegate?
let button = UIButton(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width - 40, height: 30))
init(label: String) {
button.setTitle(label, for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemBlue
super.init(nibName: nil, bundle: nil)
}
#objc func buttonTapped() {
print("this never gets printed")
buttonDelegate?.buttonTapped(buttonType: .submit)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
view.addSubview(button)
}
}
And then my main view controller:
protocol ButtonDelegate {
func buttonTapped(buttonType: ButtonType)
}
class DynamicViewController: UIViewController, ButtonDelegate {
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .equalSpacing
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
lazy var contentView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private func setupViews() {
view.addSubview(scrollView)
scrollView.addSubview(contentView)
contentView.addSubview(stackView)
let btn = CustomButton(label: "hi")
btn.buttonDelegate = self
self.stackView.addArrangedSubview(btn.view)
}
func buttonTapped(buttonType: ButtonType) {
print("also never gets printed")
}
}
There is nothing overlapping the button or anything like that:
My question is why the button is not clickable.
You are adding the view controller as a subview. So you also need to add as a child.
Add bellow code after self.stackView.addArrangedSubview(btn.view) this line.
self.addChild(btn)
btn.didMove(toParent: self)

How can I make this gray area go away (iOS UIKit)?

My iOS app, built with UIKit, has this gray area at the top and I don't know how to make it go away. Here is the code for this screen:
app screenshot
import Foundation
import UIKit
class HomeController: UIViewController {
//MARK: - Properties
private let topStack = HomeNavigationStackView()
private let bottomStack = BottomControlsStackView();
private let deckView: UIView = {
let view = UIView()
view.backgroundColor = .systemPink
view.layer.cornerRadius = 5
return view
}()
//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
configureCards()
}
//MARK: - Helpers
func configureCards(){
let user1 = User(name: "Jane Doe", age: 22, images: [#imageLiteral(resourceName: "jane1"),#imageLiteral(resourceName: "appSampleProfile")])
let user2 = User(name: "Megan", age: 34, images: [#imageLiteral(resourceName: "kelly2"),#imageLiteral(resourceName: "appSampleProfile")])
let cardView1 = CardView(viewModel: CardViewModel(user: user1))
let cardView2 = CardView(viewModel: CardViewModel(user: user2))
deckView.addSubview(cardView1)
deckView.addSubview(cardView2)
cardView1.fillSuperview()
cardView2.fillSuperview()
}
func configureUI(){
view.backgroundColor = .white
let stack = UIStackView(arrangedSubviews: [topStack, deckView, bottomStack])
stack.axis = .vertical
view.addSubview(stack)
stack.anchor(top:view.safeAreaLayoutGuide.topAnchor, left: view.leftAnchor, bottom: view.safeAreaLayoutGuide.bottomAnchor, right: view.rightAnchor)
stack.isLayoutMarginsRelativeArrangement = true
stack.layoutMargins = .init(top: 0, left: 12, bottom: 0, right: 12)
stack.bringSubviewToFront(deckView)
}
}
And here is the code for the navigation items at the top:
import UIKit
class HomeNavigationStackView: UIStackView {
// MARK: - Properties
let settingsButton = UIButton(type: .system)
let messageButton = UIButton(type: .system)
let tinderIcon = UIImageView(image: #imageLiteral(resourceName: "app_icon"))
//MARK: - Lifecycle
override init(frame: CGRect){
super.init(frame: frame)
heightAnchor.constraint(equalToConstant: 80).isActive = true
tinderIcon.contentMode = .scaleAspectFit
settingsButton.setImage(#imageLiteral(resourceName: "top_left_profile").withRenderingMode(.alwaysOriginal), for: .normal)
messageButton.setImage(#imageLiteral(resourceName: "top_right_messages").withRenderingMode(.alwaysOriginal), for: .normal)
[settingsButton, UIView(), tinderIcon, UIView(), messageButton].forEach{
view in addArrangedSubview(view)
}
distribution = .equalCentering
isLayoutMarginsRelativeArrangement = true
layoutMargins = .init(top:0, left:16, bottom:0, right:16)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
you have embedded your view controller to a NavigationController in order to perform segues. You can hide the navigationBar and set your own Items like this:
navigationController?.navigationBar.tintColor = UIColor.clear
navigationController?.navigationBar.isHidden = false
navigationController?.navigationBar.backgroundColor = UIColor.clear
Or if you want to leave it and the thing that bothers you is the shadow and gray color then you can use this code. It removes the shadow on the bottom of navigationBar (Gray Bar) and sets the backGrounColor to clear, but it leaves you ability to set the titleColor, tile etc.
view.backgroundColor = UIColor.white
navigationController?.navigationBar.tintColor = UIColor.black
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.backgroundColor = UIColor.clear
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)

View design not showing in ViewController

I'm trying to create a UIView and set it as a ViewController's view.
I did set it up but it won't show properly. for example, I chose a backgroundColor for the view, which is not showing. I added two buttons and they do show, but not as expected.
This is my UIView code:
import UIKit
public final class LoginView: UIView {
public override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(stackView)
self.backgroundColor = UIColor.appColors.white
NSLayoutConstraint.activate([
stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public let login: UIButton = {
let button = UIButton(type: .system)
button.titleLabel?.font = UIFont(name: "AvenirNext-Regular", size: 17.0)
button.setTitle("Login", for: .normal)
button.setTitleColor(UIColor.appColors.white, for: .normal)
button.backgroundColor = UIColor.appColors.green
button.contentHorizontalAlignment = .center
button.layer.cornerRadius = 10
button.layer.shadowColor = UIColor(white: 0, alpha: 0.25).cgColor
button.layer.shadowOffset = CGSize(width: 0, height: 2)
button.layer.shadowOpacity = 1
button.layer.shadowRadius = 0
button.layer.masksToBounds = false
button.clipsToBounds = true
return button
}()
public let signup: UIButton = {
let button = UIButton(type: .system)
button.titleLabel?.font = UIFont(name: "AvenirNext-Regular", size: 17.0)
button.setTitle("Signup", for: .normal)
button.setTitleColor(UIColor.appColors.white, for: .normal)
button.backgroundColor = UIColor.appColors.red
button.contentHorizontalAlignment = .center
button.layer.cornerRadius = 10
button.layer.shadowColor = UIColor(white: 0, alpha: 0.25).cgColor
button.layer.shadowOffset = CGSize(width: 0, height: 2)
button.layer.shadowOpacity = 1
button.layer.shadowRadius = 0
button.layer.masksToBounds = false
button.clipsToBounds = true
return button
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [self.login, self.signup])
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.alignment = .fill
stackView.spacing = 10.0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
}
This is my ViewController:
import UIKit
class loginVC: UIViewController {
override func loadView() {
super.loadView()
self.view = LoginVC()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
As you can see, I did set up everything, and I did changed the look of the buttons and chose a backgorund color, but it just won't show on the ViewController.
I want to seperate the View and the ViewController because I really need flexability with this app, but it just won't work.
Any ideas?
In loadView(), it must be LoginView() instead of loginVC(), i.e
class loginVC: UIViewController {
override func loadView() {
super.loadView()
self.view = LoginView()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Edit:
Try replacing UIColor.appColors with just UIColor and see if it giving the expected result. This is the only thing I changed in your code to get that working perfectly.

Action not being called when button is tapped in a stack view

I have a custom view that includes a stack view. Inside the stack view I have a label and a button.
I created my stack view, label and button in the following way and added them to the parent view.
class HomeView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
stackView.addArrangedSubview(haveAccount)
stackView.addArrangedSubview(signin)
stackView.setCustomSpacing(4.0, after: haveAccount)
}
let stackView: UIStackView = {
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
stack.distribution = .fillProportionally
stack.alignment = .fill
stack.isUserInteractionEnabled = false
return stack
}()
let haveAccount: UILabel = {
let label = UILabel()
...
return label
}()
let signin: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Sign in", for: .normal)
button.titleLabel?.font = UIFont(name: "Avenir", size: 14)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(HomeController.loginClicked(_:)), for: .touchUpInside)
return button
}()
}
In my view controller I add the view to the controller's base view and set the constraints. I also create the method that should be called when the signin button is tapped.
override func viewDidLoad() {
super.viewDidLoad()
homeView = HomeView()
homeView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(homeView)
homeView.fullscreenView(parentView: view)
}
#objc func loginClicked(_ sender: UIButton) {
print("sign in button pressed")
}
When I press the button the loginClicked method is not called. Now I did tried moving the loginClicked method to the custom view and changing the addTarget accordingly and loginClicked method is called. This being said I know the button is clickable but I don't think the target for the button action is correct and that is why the loginClicked method in the view controller is not being called.
You can use Protocol/Delegation
//1. Create a protocol
protocol HomeViewDelegate{
func loginButtonClicked(sender: UIButton)
}
class HomeView: UIView {
//2. Create a delegate
var delegate: HomeViewDelegate?
let stackView: UIStackView = {
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
stack.distribution = .fillProportionally
stack.alignment = .fill
stack.isUserInteractionEnabled = false
return stack
}()
let haveAccount: UILabel = {
let label = UILabel()
return label
}()
let signin: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Sign in", for: .normal)
button.titleLabel?.font = UIFont(name: "Avenir", size: 14)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(loginClicked(sender:)), for: .touchUpInside)
button.backgroundColor = .red
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
stackView.addArrangedSubview(haveAccount)
stackView.addArrangedSubview(signin)
stackView.setCustomSpacing(4.0, after: haveAccount)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//3. Call your protocol method via delegate
#objc func loginClicked(sender: UIButton) {
if let delegate = delegate{
delegate.loginButtonClicked(sender: sender)
}
}
}
In You Caller ViewController create an extension
extension ViewController: HomeViewDelegate{
func loginButtonClicked(sender: UIButton) {
print("login Button Clicked")
}
}
First of all you set userInteractionEnabled property of your stackView to false, set it to true. Then if it does not work consider the following approach:
There are two possible ways to fix this, first is adding the target from ViewController, and the other one is using delegation.
I think the first way would be easier to implement for you.
You need to add your target from your ViewController class.
First update your view class and get rid of adding a target:
class HomeView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
stackView.addArrangedSubview(haveAccount)
stackView.addArrangedSubview(signin)
stackView.setCustomSpacing(4.0, after: haveAccount)
}
let stackView: UIStackView = {
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
stack.distribution = .fillProportionally
stack.alignment = .fill
stack.isUserInteractionEnabled = true
return stack
}()
let haveAccount: UILabel = {
let label = UILabel()
...
return label
}()
let signin: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Sign in", for: .normal)
button.titleLabel?.font = UIFont(name: "Avenir", size: 14)
button.setTitleColor(UIColor.white, for: .normal)
return button
}()
}
Now in your ViewController:
override func viewDidLoad() {
super.viewDidLoad()
homeView = HomeView()
homeView.translatesAutoresizingMaskIntoConstraints = false
homeView.signIn.addTarget(self, action: #selector(loginClicked), for: .touchUpInside)
view.addSubview(homeView)
homeView.fullscreenView(parentView: view)
}
#objc func loginClicked(_ sender: UIButton) {
print("sign in button pressed")
}
You need to add the right constraints, I had this problem, I had this problem and the solution was this.
Solution:
import Foundation
import UIKit
protocol HomeViewDelegate:class{
func loginButtonClicked(sender: UIButton)
}
class HomeView: UIView {
//2. Create a delegate
weak var delegate: HomeViewDelegate?
var stackView: UIStackView = {
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
stack.distribution = .fillProportionally
stack.alignment = .fill
stack.axis = .vertical
stack.isUserInteractionEnabled = true
return stack
}()
let haveAccount: UILabel = {
let label = UILabel()
label.backgroundColor = .gray
label.text = "Label"
label.textAlignment = .center
return label
}()
let signin: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Sign in", for: .normal)
button.titleLabel?.font = UIFont(name: "Avenir", size: 14)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(loginClicked(sender:)), for: .touchUpInside)
button.isUserInteractionEnabled = true
button.backgroundColor = .red
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
stackView.addArrangedSubview(haveAccount)
stackView.addArrangedSubview(signin)
stackView.setCustomSpacing(4.0, after: haveAccount)
addSubview(stackView)
NSLayoutConstraint.activate([
self.stackView.topAnchor.constraint(equalTo: self.topAnchor),
self.stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
self.stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
self.stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//3. Call your protocol method via delegate
#objc func loginClicked(sender: UIButton) {
if let delegate = delegate{
delegate.loginButtonClicked(sender: sender)
}
}
}
ViewController
override func viewDidLoad() {
super.viewDidLoad()
let homeView = HomeView()
homeView.translatesAutoresizingMaskIntoConstraints = false
homeView.delegate = self
self.view.addSubview(homeView)
NSLayoutConstraint.activate([
homeView.centerXAnchor.constraint(equalTo: centerXAnchor),
homeView.centerYAnchor.constraint(equalTo: centerYAnchor),
homeView.heightAnchor.constraint(equalToConstant: 300),
homeView.widthAnchor.constraint(equalToConstant: 300)
])
}
#objc func loginClicked(_ sender: UIButton) {
print("sign in button pressed")
}
add this line to your button code
button.isUserInteractionEnabled = true
re-active isUserInteractionEnabled again
let signin: UIButton = {
let button = UIButton()
button.backgroundColor = .blue
button.setTitle("Sign in", for: .normal)
button.titleLabel?.font = UIFont(name: "Avenir", size: 14)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(ViewController.loginClicked(_:)), for: .touchUpInside)
button.isUserInteractionEnabled = true
return button
}()

Constraint animation with SnapKit

I am trying to implement the animation of 2 views using SnapKit.
Here is my Animation view:
class MatchAnimation: UIView {
let viewBackground: UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.75)
view.alpha = 1
return view
}()
let matchView: UIView = {
let view = UIView()
return view
}()
let matchLabel: UILabel = {
let label = UILabel()
label.text = "Title"
label.textColor = .white
label.textAlignment = .center
return label
}()
let leftAvatarBg: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 91/2
return view
}()
let rightAvatarBg: UIView = {
let view = UIView()
view.backgroundColor = .blue
view.layer.cornerRadius = 91/2
return view
}()
let goToChatButton: UIButton = {
let button = UIButton()
button.setTitle("Button", for: .normal)
button.backgroundColor = .red
button.setTitleColor(.white, for: .normal)
button.layer.cornerRadius = 24.5
return button
}()
init() {
super.init(frame: UIScreen.main.bounds)
viewBackground.frame = self.frame
self.addSubview(viewBackground)
self.addSubview(matchView)
matchView.addSubview(matchLabel)
matchView.addSubview(leftAvatarBg)
matchView.addSubview(rightAvatarBg)
matchView.addSubview(goToChatButton)
matchView.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.center.equalToSuperview()
}
matchLabel.snp.makeConstraints { (make) in
make.top.equalToSuperview()
make.centerX.equalToSuperview()
make.size.equalTo(CGSize(width: 193, height: 40))
}
leftAvatarBg.snp.makeConstraints { (make) in
make.top.equalTo(matchLabel.snp.bottom).offset(20)
make.size.equalTo(CGSize(width: 91, height: 91))
make.right.equalTo(self.snp.left).offset(0)
}
rightAvatarBg.snp.makeConstraints { (make) in
make.top.equalTo(leftAvatarBg)
make.size.equalTo(leftAvatarBg)
make.left.equalTo(self.snp.right).inset(0)
}
goToChatButton.snp.makeConstraints { (make) in
make.size.equalTo(CGSize(width: 171, height: 50))
make.top.equalTo(leftAvatarBg.snp.bottom).offset(25)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview()
}
}
func animate() {
UIView.animate(withDuration: 5) {
self.leftAvatarBg.snp.updateConstraints { (make) in
make.right.equalTo(self.snp.left).offset(UIScreen.main.bounds.width/2+30)
}
self.rightAvatarBg.snp.updateConstraints { (make) in
make.left.equalTo(self.snp.right).inset(UIScreen.main.bounds.width/2+30)
}
self.layoutIfNeeded()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The 2 views I tried to animate are leftAvatarBg and rightAvatarBg.
Before the animation, I set them at the exterior of the screen and want to make them slide from left to right for one view and from right to left for the other.
In my controller, I just call:
func setupAnimation() {
let matchView = MatchAnimation()
view.addSubview(matchView)
matchView.animate()
}
The result of this is that the entire view is animating (scaling).
Did I miss something?
UPDATE: Thanks to swift2geek, it seems that they is a conflict between the creation of the object and the animation. In his solution, he trigger the animation by pressing a button. In my case, I want to trigger the animation as soon as possible and automatically. How can I ensure that the animation will be fired after the creation of the object ?
im not good with your bdsm SnapKit, so put the right constraints on your own. So the main reason its not working - you should separate animation and object creation.
your viewcontroller:
import UIKit
class ViewController: UIViewController {
#IBOutlet var matchButton: MatchButton!
#IBOutlet var matchView: MatchAnimation!
override func viewDidLoad() {
super.viewDidLoad()
setupAnimation()
setupButton()
}
func setupAnimation() {
matchView = MatchAnimation()
matchView.isUserInteractionEnabled = true
view.addSubview(matchView)
}
func setupButton() {
matchButton = MatchButton()
matchButton.isUserInteractionEnabled = true
matchButton.isEnabled = true
matchButton.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)
matchView.addSubview(matchButton)
}
#objc func pressed(_ sender: MatchButton!) {
print("button tapped")
matchView.animate()
}
}
your MatchAnimation class:
import UIKit
import SnapKit
class MatchAnimation: UIView {
let viewBackground: UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.75)
view.alpha = 1
return view
}()
let matchView: UIView = {
let view = UIView()
return view
}()
let matchLabel: UILabel = {
let label = UILabel()
label.text = "Title"
label.textColor = .white
label.textAlignment = .center
return label
}()
let leftAvatarBg: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 91/2
return view
}()
let rightAvatarBg: UIView = {
let view = UIView()
view.backgroundColor = .blue
view.layer.cornerRadius = 91/2
return view
}()
init() {
super.init(frame: UIScreen.main.bounds)
viewBackground.frame = self.frame
self.addSubview(viewBackground)
self.addSubview(matchView)
matchView.addSubview(matchLabel)
matchView.addSubview(leftAvatarBg)
matchView.addSubview(rightAvatarBg)
matchView.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.center.equalToSuperview()
}
matchLabel.snp.makeConstraints { (make) in
make.top.equalToSuperview()
make.centerX.equalToSuperview()
make.size.equalTo(CGSize(width: 193, height: 40))
}
leftAvatarBg.snp.makeConstraints { (make) in
make.top.equalTo(matchLabel.snp.bottom).offset(20)
make.centerX.equalToSuperview()
make.size.equalTo(CGSize(width: 91, height: 91))
make.right.equalTo(self.snp.left).offset(90)
}
rightAvatarBg.snp.makeConstraints { (make) in
make.top.equalTo(leftAvatarBg)
make.size.equalTo(leftAvatarBg)
make.left.equalTo(self.snp.right).inset(120)
}
}
func animate() {
UIView.animate(withDuration: 5) {
self.leftAvatarBg.snp.updateConstraints { (make) in
make.right.equalTo(self.snp.left).offset(UIScreen.main.bounds.width/2+30)
}
self.rightAvatarBg.snp.updateConstraints { (make) in
make.left.equalTo(self.snp.right).inset(UIScreen.main.bounds.width/2+30)
}
self.layoutIfNeeded()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
and MatchButton:
import UIKit
import SnapKit
class MatchButton: UIButton {
let goToChatButton: UIButton = {
let button = UIButton()
button.setTitle("Button", for: .normal)
button.backgroundColor = .red
button.setTitleColor(.white, for: .normal)
button.layer.cornerRadius = 24.5
return button
}()
init() {
super.init(frame: UIScreen.main.bounds)
self.addSubview(goToChatButton)
goToChatButton.snp.makeConstraints { (make) in
make.size.equalTo(CGSize(width: 171, height: 50))
make.top.greaterThanOrEqualTo(100)
make.centerX.equalToSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
If you want your animation to fire as soon as possible, just add layout animate() function to viewDidAppear.

Resources