Animating UIIMageView Alpha on view did load - ios

I am attempting to animate the background image of my HomeController.
I would like to fade the image in, as such I was hoping to animate it's alpha property.
I have found many answers on here around this, however many seem dated (obj c, iOS 3/4/5 etc) and following the recommended approach, I still cannot get this animation to work.
Can anyone please tell me what is wrong with my code?
I would like to animate backgroundImage. I have placed my animation code at the end of my setupView method.
It does not 'fade in' as I would like, essentially the alpha jumps straight to 0.7
import UIKit
class HomeController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
private let backgroundImage: UIImageView = {
let image = UIImageView()
image.image = #imageLiteral(resourceName: "foggy").withRenderingMode(.alwaysOriginal)
image.contentMode = .scaleToFill
image.alpha = 0
image.isOpaque = false
return image
}()
private let currentLocation: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Southampton, UK", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 24)
button.contentMode = .center
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(onPressLocation), for: .touchUpInside)
return button
}()
private let currentTemp: UIButton = {
let button = UIButton(type: .system)
button.setTitle("37°C", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 54, weight: .thin)
button.contentMode = .center
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action: #selector(onPressTemp), for: .touchUpInside)
return button
}()
}
extension HomeController {
#objc fileprivate func onPressLocation() -> Void {
print("Location pressed.")
}
#objc fileprivate func onPressTemp() -> Void {
self.currentTemp.setTitle("98°F", for: .normal)
}
fileprivate func setupView() -> Void {
view.backgroundColor = .white
// MARK: Background Image
view.addSubview(backgroundImage)
backgroundImage.anchor(
top: view.safeAreaLayoutGuide.topAnchor,
left: view.safeAreaLayoutGuide.leftAnchor,
bottom: view.safeAreaLayoutGuide.bottomAnchor,
right: view.safeAreaLayoutGuide.rightAnchor,
paddingTop: 0,
paddingLeft: 0,
paddingBottom: 0,
paddingRight: 0,
width: 0,
height: 0
)
// MARK: Current Location
view.addSubview(currentLocation)
currentLocation.anchor(
top: view.safeAreaLayoutGuide.topAnchor,
left: view.safeAreaLayoutGuide.leftAnchor,
right: view.safeAreaLayoutGuide.rightAnchor,
paddingTop: 50,
paddingLeft: 0,
paddingBottom: 0,
paddingRight: 0,
width: 0,
height: 26,
centerX: view.centerXAnchor
)
// MARK: Temp Button
view.addSubview(currentTemp)
currentTemp.anchor(
top: currentLocation.bottomAnchor,
paddingTop: 10,
paddingLeft: 0,
paddingBottom: 0,
paddingRight: 0,
width: 200,
height: 70,
centerX: view.centerXAnchor
)
// MARK: Animations
UIView.animate(withDuration: 6, delay: 3, options: .curveEaseInOut, animations: {
self.backgroundImage.alpha = 0.7
}, completion: nil)
}
}

IBOutlets does not get visible when viewDidLoad is called so call your setupView method in viewDidAppear which is called after your view appeared on screen.
Hope this helps.

You can put your code in viewDidAppear view life cycle method for any animation work ,because viewDidAppear method notifies the view controller that its view was added to a view hierarchy.Use below code for your solution.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated: animated)
//Call method like this
setupView()
}

Related

UIButton Not Responding to Touch Events

Problem
I am trying to do everything programmatically, so I have created this ResultController. For some reason, two of my buttons work but the other three don't work. The program doesn't even notice the touch-up event. I have read many posts on this topic but none of the solutions worked for me.
The two buttons that work are the language button and the swap button, which are embedded in a stack view towards the top of the screen. The 3 buttons that don't work are the soundButton, loopButton, and addFlashcardButton on the result card shown in the image below.
Question
What do I need to do such that these buttons respond to touch events?
Here is the code for this viewController, as well as a picture of the result. I will post the important parts and the whole code for reference. The Buttons are laid out in two functions, setupResultsView() and setupScrollView():
Button Instantiation
var soundButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "speaker.3.fill"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(soundButtonPressed), for: .touchUpInside)
return button
}()
var loopButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "repeat"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(loopButtonPressed), for: .touchUpInside)
return button
}()
var addFlashcardButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
button.setImage(UIImage(systemName: "plus"), for: .normal)
button.backgroundColor = K.Colors.purple
button.tintColor = .white
button.roundCorners(cornerRadius: 15)
button.addTarget(self, action: #selector(addFlashcardButtonPressed), for: .touchUpInside)
return button
}()
Selector Functions
#objc func soundButtonPressed() {
print("soundButton")
}
#objc func loopButtonPressed() {
print("loopButton")
}
#objc func addFlashcardButtonPressed() {
print("adding flashcard")
}
Complete Code
import UIKit
class ResultsController: UIViewController {
//MARK: - Info
let cellID = "SoundItOutCell"
//MARK: - Views
var centerTitle: UILabel = {
let label = UILabel(frame: CGRect(x: 10, y: 0, width: 50, height: 40))
label.backgroundColor = K.Colors.purple
label.font = UIFont.boldSystemFont(ofSize: 30)
label.text = "Aura"
label.numberOfLines = 2
label.textColor = .white
label.textAlignment = .center
return label
}()
var languageBarView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.setUnderlineStyle(color: K.Colors.purple)
return view
}()
var langStackView: UIStackView = {
let stackView = UIStackView()
stackView.backgroundColor = .white
stackView.alignment = .center
stackView.distribution = .fillEqually
return stackView
}()
var languageButton: UIButton = {
let button = UIButton()
button.setTitle("Japanese", for: .normal)
button.addTarget(self, action: #selector(languageButtonPressed), for: .touchUpInside)
button.backgroundColor = .white
button.setTitleColor(UIColor.systemBlue, for: .normal)
return button
}()
var swapButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "repeat"), for: .normal)
button.addTarget(self, action: #selector(swapButtonPressed), for: .touchUpInside)
button.tintColor = .black
button.backgroundColor = .white
return button
}()
var englishLabel: UILabel = {
let label = UILabel()
label.text = "English"
label.textColor = .black
label.backgroundColor = .white
label.textAlignment = .center
return label
}()
var textViewBackgroundView = UIView()
var textView: UITextView = {
let textView = UITextView()
textView.returnKeyType = .search
textView.text = "Enter text"
textView.textColor = .lightGray
textView.font = .systemFont(ofSize: 20)
textView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 50)
return textView
}()
var cancelButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "multiply"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(cancelButtonPressed), for: .touchUpInside)
button.isHidden = true
return button
}()
var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.backgroundColor = K.Colors.lightGrey
return scrollView
}()
var contentView: UIView = {
let view = UIView()
view.backgroundColor = K.Colors.lightGrey
return view
}()
var resultCardView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.roundCorners(cornerRadius: 10)
return view
}()
var topLabel = UILabel()
var bottomLabel = UILabel()
var soundButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "speaker.3.fill"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(soundButtonPressed), for: .touchUpInside)
return button
}()
var loopButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "repeat"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(loopButtonPressed), for: .touchUpInside)
return button
}()
var lineDividerView: UIView = {
let view = UIView()
view.backgroundColor = K.Colors.purple
return view
}()
var addFlashcardButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
button.setImage(UIImage(systemName: "plus"), for: .normal)
button.backgroundColor = K.Colors.purple
button.tintColor = .white
button.roundCorners(cornerRadius: 15)
button.addTarget(self, action: #selector(addFlashcardButtonPressed), for: .touchUpInside)
return button
}()
// Background Views
let resultBackgroundView = UIView ()
let addFlashcardBackgroundView = UIView()
//MARK: - Class Functions
override func viewDidLoad() {
super.viewDidLoad()
setupView()
view.backgroundColor = K.Colors.lightGrey
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setupShadows()
}
}
extension ResultsController {
//MARK:- View Setup Functions
func setupView() {
self.setupToHideKeyboardOnTapOnView()
setupNavBar()
setupLanguageSelectionView()
setupTextView()
setupScrollView()
}
func setupShadows() {
textViewBackgroundView.setShadow(color: UIColor.black, opacity: 0.3, offset: .init(width: 0, height: 3), radius: 2)
resultBackgroundView.setShadow(color: .black, opacity: 0.3, offset: CGSize(width: 5, height: 5), radius: 2, cornerRadius: 10)
addFlashcardBackgroundView.setShadow(color: .black, opacity: 0.5, offset: CGSize(width: 2, height: 2), radius: 2, cornerRadius: 15)
}
func setupNavBar() {
// Add Center Title
self.navigationItem.titleView = centerTitle
// Add userbutton
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "person"),
style: .plain,
target: self,
action: #selector(profileButtonTapped))
// Make bar color purple, and buttons white
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.barTintColor = K.Colors.purple
}
func setupLanguageSelectionView() {
// Add Language Bar View
view.addSubview(languageBarView)
languageBarView.anchor(top: view.safeAreaLayoutGuide.topAnchor,
bottom: nil, leading: view.leadingAnchor,
trailing: view.trailingAnchor,
height: 60,
width: nil)
// Add Stack View
languageBarView.addSubview(langStackView)
langStackView.anchor(top: languageBarView.topAnchor,
bottom: languageBarView.bottomAnchor,
leading: languageBarView.leadingAnchor,
trailing: languageBarView.trailingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 0, left: 0, bottom: -2, right: 0))
// Add Language Button
langStackView.addArrangedSubview(languageButton)
// Add Swap Button
langStackView.addArrangedSubview(swapButton)
// Add English Label
langStackView.addArrangedSubview(englishLabel)
}
func setupTextView() {
// Add View
view.addSubview(textViewBackgroundView)
textViewBackgroundView.anchor(top: langStackView.bottomAnchor,
bottom: nil,
leading: view.leadingAnchor,
trailing: view.trailingAnchor,
height: 60,
width: nil,
padding: UIEdgeInsets(top: 2, left: 0, bottom: 0, right: 0))
// Add TextView
textView.delegate = self
view.addSubview(textView)
textView.anchor(top: textViewBackgroundView.topAnchor,
bottom: textViewBackgroundView.bottomAnchor,
leading: textViewBackgroundView.leadingAnchor,
trailing: textViewBackgroundView.trailingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
// Add X Button
view.addSubview(cancelButton)
cancelButton.anchor(top: textView.topAnchor,
bottom: nil,
leading: nil,
trailing: textView.trailingAnchor,
height: 40,
width: 40,
padding: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
}
func setupScrollView() {
// Add scroll view and content view
view.addSubview(scrollView)
view.sendSubviewToBack(scrollView)
scrollView.addSubview(contentView)
// Anchor Scroll View
scrollView.anchorXCenter(top: textView.topAnchor,
bottom: view.safeAreaLayoutGuide.bottomAnchor,
centerAnchor: view.centerXAnchor,
width: view.widthAnchor,
height: nil)
// Anchor Content View
contentView.anchorXCenter(top: scrollView.topAnchor,
bottom: scrollView.bottomAnchor,
centerAnchor: scrollView.centerXAnchor,
width: scrollView.widthAnchor,
height: nil)
// Setup Results Background
contentView.addSubview(resultBackgroundView)
resultBackgroundView.anchorXCenter(top: contentView.topAnchor,
bottom: nil,
centerAnchor: contentView.centerXAnchor,
width: contentView.widthAnchor,
height: nil,
padding: UIEdgeInsets(top: 90, left: 0, bottom: 0, right: 0),
widthOffset: -40)
// Setup Results Card
resultBackgroundView.addSubview(resultCardView)
resultCardView.anchorXCenter(top: resultBackgroundView.topAnchor,
bottom: resultBackgroundView.bottomAnchor,
centerAnchor: resultBackgroundView.centerXAnchor,
width: resultBackgroundView.widthAnchor,
height: nil)
setupResultsView(resultCardView)
}
func setupResultsView(_ resultCardView: UIView) {
let searchInput = "Hello"
let searchOutput = "Yo what's up dog congratulations"
// Configure Top Label
topLabel.attributedText = NSAttributedString(string: searchInput)
topLabel.configureBasedOnInput()
// Configure Bottom Label
bottomLabel.attributedText = NSAttributedString(string: searchOutput)
bottomLabel.configureBasedOnInput()
// Add Flashcard Button to its Background View
addFlashcardBackgroundView.addSubview(addFlashcardButton)
addFlashcardButton.anchor(top: addFlashcardBackgroundView.topAnchor,
bottom: addFlashcardBackgroundView.bottomAnchor,
leading: addFlashcardBackgroundView.leadingAnchor,
trailing: addFlashcardBackgroundView.trailingAnchor,
height: nil,
width: nil)
// Add subviews to Result Card
resultCardView.addSubview(topLabel)
resultCardView.addSubview(bottomLabel)
resultCardView.addSubview(soundButton)
resultCardView.addSubview(loopButton)
resultCardView.addSubview(lineDividerView)
resultCardView.addSubview(addFlashcardBackgroundView)
// Autolayout Constraints For Result Card Subviews
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.topAnchor.constraint(equalTo: resultCardView.topAnchor, constant: 10).isActive = true
topLabel.centerXAnchor.constraint(equalTo: resultCardView.centerXAnchor, constant: 0).isActive = true
topLabel.leadingAnchor.constraint(greaterThanOrEqualTo: resultCardView.leadingAnchor, constant: 10).isActive = true
topLabel.trailingAnchor.constraint(lessThanOrEqualTo: resultCardView.trailingAnchor, constant: -10).isActive = true
lineDividerView.anchor(top: topLabel.bottomAnchor,
bottom: nil, leading: resultCardView.leadingAnchor,
trailing: resultCardView.trailingAnchor,
height: 1,
width: nil,
padding: UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0))
loopButton.anchor(top: lineDividerView.bottomAnchor,
bottom: nil,
leading: nil,
trailing: resultCardView.trailingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 10, left: 0, bottom: 0, right: -10))
soundButton.anchor(top: lineDividerView.bottomAnchor,
bottom: nil,
leading: nil,
trailing: loopButton.leadingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 10, left: 0, bottom: 0, right: -10))
bottomLabel.translatesAutoresizingMaskIntoConstraints = false
bottomLabel.topAnchor.constraint(equalTo: soundButton.bottomAnchor, constant: 10).isActive = true
bottomLabel.centerXAnchor.constraint(equalTo: resultCardView.centerXAnchor, constant: 0).isActive = true
bottomLabel.leadingAnchor.constraint(greaterThanOrEqualTo: resultCardView.leadingAnchor, constant: 10).isActive = true
bottomLabel.trailingAnchor.constraint(lessThanOrEqualTo: resultCardView.trailingAnchor, constant: -10).isActive = true
addFlashcardBackgroundView.anchor(top: bottomLabel.bottomAnchor,
bottom: resultCardView.bottomAnchor,
leading: nil,
trailing: resultCardView.trailingAnchor,
height: 30,
width: 30,
padding: UIEdgeInsets(top: 10, left: 0, bottom: -10, right: -10))
}
//MARK:- Selector Functions
#objc func profileButtonTapped() {
print(0)
}
#objc func languageButtonPressed() {
print(1)
}
#objc func swapButtonPressed() {
print(2)
}
#objc func cancelButtonPressed() {
textView.text = ""
textView.textColor = .lightGray
textView.text = "Enter text"
cancelButton.isHidden = true
}
#objc func soundButtonPressed() {
print("soundButton")
}
#objc func loopButtonPressed() {
print("loopButton")
}
#objc func addFlashcardButtonPressed() {
print("adding flashcard")
}
}
Output: Circled Buttons are ones that don't work

How do I get a UILabel to show multiline and word wrapping?

I am trying to get my itemLabel UILabel to be multiline and do word wrapping, but I can't figure out where I'm going wrong here. I have numberOfLines = 0 and .byWordWrapping set. I'm sure it's a simple line of code I messed up, but I can't find it.
import UIKit
import Foundation
protocol ListItemCellDelegate {
func setChecked(cell: ListItemCell)
}
class ListItemCell: UITableViewCell {
var delegate: ListItemCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse() {
super.prepareForReuse()
self.delegate = nil
}
let cellView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.white
view.setCellShadow()
return view
}()
let checkButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "UnChecked"), for: .normal)
button.setImage(UIImage(named: "Checked"), for: .selected)
button.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
return button
}()
let priorityButton: UIButton = {
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
button.setTitleColor(.black, for: .normal)
button.backgroundColor = UIColor.white
button.layer.borderWidth = 2
button.layer.borderColor = UIColor.black.cgColor
button.titleLabel?.font = UIFont.init(name: "Avenir Next", size: 24)
return button
}()
let itemLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.black
label.font = UIFont.init(name: "Avenir Next", size: 16)
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupCell()
checkButton.addTarget(self, action: #selector(setChecked), for: .touchUpInside)
itemLabel.translatesAutoresizingMaskIntoConstraints = false
itemLabel.numberOfLines = 0
itemLabel.lineBreakMode = .byWordWrapping
}
func setupCell() {
addSubview(cellView)
cellView.addSubview(checkButton)
cellView.addSubview(priorityButton)
cellView.addSubview(itemLabel)
cellView.setAnchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 4, paddingLeft: 8, paddingBottom: 4, paddingRight: 8)
checkButton.setAnchor(top: nil, left: cellView.leftAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 50, height: 50)
checkButton.centerYAnchor.constraint(equalTo: cellView.centerYAnchor).isActive = true
priorityButton.setAnchor(top: nil, left: checkButton.rightAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 40, height: 40)
priorityButton.centerYAnchor.constraint(equalTo: checkButton.centerYAnchor).isActive = true
itemLabel.setAnchor(top: nil, left: priorityButton.rightAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 20, paddingBottom: 0, paddingRight: 20)
itemLabel.centerYAnchor.constraint(equalTo: priorityButton.centerYAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc private func setChecked() {
self.delegate?.setChecked(cell: self)
}
}
I expect the UILabel to wrap the text and take up as much space as needed to fit the whole label text in the cell. Right now it is not displaying the entire message, only what the size will allow. But, I want it to resize based on the length of the string. I did this easily in Storyboard, but I'm trying to get it to work programmatically.
I have done that before like in UITableView() there was an array of Strings and the length of the String was not fixed it can be in 3 lines or more.
So for that, i have given the constraints to UILabel() like top, bottom,leading, trailing all constraint to 0.
In UITableView(), there is a method called :
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Try this one it will definitly help you i guess.
In my case, part of the solution was what Varsha Shivhare suggested, and the other was setting the heightAnchor constraint to >= 60 which is what I'm using right now. Thank you!

TextView Not Wrapping

I have a textview instead of a textfield so I can autowrap text. However, the text itself is not auto wrapping. When the line gets too long the following text just disappears. If I go to an earlier point in the line and start deleting text, then the text that wasn't visible begins to appear.It should autoresize itself butit does not.
import UIKit
protocol CommentInputAccessoryViewDelegate {
func handleSubmit(for comment: String?)
}
class CommentInputAccessoryView: UIView, UITextViewDelegate {
var delegate: CommentInputAccessoryViewDelegate?
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
fileprivate let submitButton: UIButton = {
let submitButton = UIButton(type: .system)
submitButton.setTitle("Submit", for: .normal)
submitButton.setTitleColor(.black, for: .normal)
submitButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
submitButton.addTarget(self, action: #selector(handleSubmit), for: .touchUpInside)
//submitButton.isEnabled = false
return submitButton
}()
lazy var commentTextView: UITextView = {
let textView = UITextView()
// textView.placeholder = "Add a comment"
textView.delegate = self
textView.isScrollEnabled = false
textView.backgroundColor = .red
textView.font = UIFont.boldSystemFont(ofSize: 12)
textView.textContainer.lineBreakMode = .byWordWrapping
// textView.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
return textView
}()
override init(frame: CGRect) {
super.init(frame: frame)
// backgroundColor = .red
//1
autoresizingMask = .flexibleHeight
addSubview(submitButton)
submitButton.anchor(top: topAnchor, left: nil, bottom: bottomAnchor, right:rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 12, width: 50, height: 0)
addSubview(commentTextView)
//3
if #available(iOS 11.0, *){
commentTextView.anchor(top: topAnchor, left: leftAnchor, bottom: safeAreaLayoutGuide.bottomAnchor, right: submitButton.leftAnchor, paddingTop: 0, paddingLeft: 12, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}else{
//fallback on earlier versions
}
setupLineSeparatorView()
}
//2
override var intrinsicContentSize: CGSize{
return .zero
}
fileprivate func setupLineSeparatorView(){
let lineSeparatorView = UIView()
lineSeparatorView.backgroundColor = UIColor.rgb(red: 230, green: 230, blue: 230)
addSubview(lineSeparatorView)
lineSeparatorView.anchor(top:topAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0.5)
}
#objc func handleSubmit(){
guard let commentText = commentTextView.text else{
return
}
delegate?.handleSubmit(for: commentText)
}
#objc func textFieldDidChange(_ textField: UITextView) {
let isCommentValid = commentTextView.text?.count ?? 0 > 0
if isCommentValid {
submitButton.isEnabled = true
}else{
submitButton.isEnabled = false
}
}
func clearCommentTextField(){
commentTextView.text = nil
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I'm thinking it is the anchors but I'm not entirely sure.

UICollectionViewCell Constraint Issues

Look hear for edits
So I have a comments feature in my app that users use to communicate. Each comment has a pic, some text and button that lets you either flag or reply to comments. As seen in the picture below
However as seen in the picture there is a clear problem. If you add too much text it seems to run right over the button. Is there anyway I can prevent this from happening I think it looks really bad.
Below is my sorce code for reference I'm thinking it might be my constraints but I am not entirely sure.
import Foundation
import UIKit
import Firebase
protocol CommentCellDelegate: class {
func optionsButtonTapped(cell: CommentCell)
func handleProfileTransition(tapGesture: UITapGestureRecognizer)
}
class CommentCell: UICollectionViewCell {
weak var delegate: CommentCellDelegate? = nil
override var reuseIdentifier : String {
get {
return "cellID"
}
set {
// nothing, because only red is allowed
}
}
var didTapOptionsButtonForCell: ((CommentCell) -> Void)?
var comment: CommentGrabbed?{
didSet{
guard let comment = comment else{
return
}
// print("apples")
// textLabel.text = comment.content
//shawn was also here
profileImageView.loadImage(urlString: comment.user.profilePic!)
// print(comment.user.username)
let attributedText = NSMutableAttributedString(string: comment.user.username!, attributes: [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 14)])
attributedText.append(NSAttributedString(string: " " + (comment.content), attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14)]))
textView.attributedText = attributedText
}
}
let textView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 14)
textView.isScrollEnabled = false
textView.isEditable = false
return textView
}()
lazy var profileImageView: CustomImageView = {
let iv = CustomImageView()
iv.clipsToBounds = true
iv.isUserInteractionEnabled = true
iv.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleProfileTransition)))
iv.contentMode = .scaleAspectFill
return iv
}()
lazy var flagButton: UIButton = {
let flagButton = UIButton(type: .system)
flagButton.setImage(#imageLiteral(resourceName: "icons8-Info-64"), for: .normal)
flagButton.addTarget(self, action: #selector(optionsButtonTapped), for: .touchUpInside)
return flagButton
}()
#objc func optionsButtonTapped (){
didTapOptionsButtonForCell?(self)
}
#objc func onOptionsTapped() {
delegate?.optionsButtonTapped(cell: self)
}
#objc func handleProfileTransition(tapGesture: UITapGestureRecognizer){
delegate?.handleProfileTransition(tapGesture: tapGesture)
// print("Tapped image")
}
override init(frame: CGRect){
super.init(frame: frame)
addSubview(textView)
addSubview(profileImageView)
addSubview(flagButton)
textView.anchor(top: topAnchor, left: profileImageView.rightAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4, width: 0, height: 0)
profileImageView.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 8, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 40, height: 40)
profileImageView.layer.cornerRadius = 40/2
flagButton.anchor(top: topAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: 4, paddingLeft: 0, paddingBottom: 0, paddingRight: 4, width: 40, height: 40)
flagButton.addTarget(self, action: #selector(CommentCell.onOptionsTapped), for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You need to assign textView's right anchor to the button's left one so they got aligned on sides. This would be the correct layout setup for the textView:
textView.anchor(top: topAnchor, left: profileImageView.rightAnchor, bottom: bottomAnchor, right: flagButton.leftAnchor, paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4, width: 0, height: 0)

Uncaught Exception in Button

I have a uiview with a couple of elements that I use for a comment function in my app. There is a text field, button, and line separator. Everything renders fine however when I click submit the app crashes and I get this error.
'NSInvalidArgumentException', reason: '-[UIButton copyWithZone:]: unrecognized selector sent to instance 0x7fe58c459620'
I don't see anything wrong with my implementation so this error is a little confusing to me. This is the class for my UIView
import UIKit
protocol CommentInputAccessoryViewDelegate {
func handleSubmit(for comment: String?)
}
class CommentInputAccessoryView: UIView, UITextFieldDelegate {
var delegate: CommentInputAccessoryViewDelegate?
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
fileprivate let submitButton: UIButton = {
let submitButton = UIButton(type: .system)
submitButton.setTitle("Submit", for: .normal)
submitButton.setTitleColor(.black, for: .normal)
submitButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
submitButton.addTarget(self, action: #selector(handleSubmit), for: .touchUpInside)
//submitButton.isEnabled = false
return submitButton
}()
lazy var commentTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Add a comment"
textField.delegate = self
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
return textField
}()
override init(frame: CGRect) {
super.init(frame: frame)
// backgroundColor = .red
addSubview(submitButton)
submitButton.anchor(top: topAnchor, left: nil, bottom: bottomAnchor, right:rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 12, width: 50, height: 0)
addSubview(commentTextField)
commentTextField.anchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: submitButton.leftAnchor, paddingTop: 0, paddingLeft: 12, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
setupLineSeparatorView()
}
fileprivate func setupLineSeparatorView(){
let lineSeparatorView = UIView()
lineSeparatorView.backgroundColor = UIColor.rgb(red: 230, green: 230, blue: 230)
addSubview(lineSeparatorView)
lineSeparatorView.anchor(top:topAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0.5)
}
#objc func handleSubmit(for comment: String?){
guard let commentText = commentTextField.text else{
return
}
delegate?.handleSubmit(for: commentText)
}
#objc func textFieldDidChange(_ textField: UITextField) {
let isCommentValid = commentTextField.text?.count ?? 0 > 0
if isCommentValid {
submitButton.isEnabled = true
}else{
submitButton.isEnabled = false
}
}
func clearCommentTextField(){
commentTextField.text = nil
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This is the accompanying class that ultimately handles the submission through a protocol method
//allows you to gain access to the input accessory view that each view controller has for inputting text
lazy var containerView: CommentInputAccessoryView = {
let frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 50)
let commentInputAccessoryView = CommentInputAccessoryView(frame:frame)
commentInputAccessoryView.delegate = self
return commentInputAccessoryView
}()
#objc func handleSubmit(for comment: String?){
guard let comment = comment, comment.count > 0 else{
return
}
let userText = Comments(content: comment, uid: User.current.uid, profilePic: User.current.profilePic!,eventKey: eventKey)
sendMessage(userText)
// will clear the comment text field
self.containerView.clearCommentTextField()
}
extension NewCommentsViewController {
func sendMessage(_ message: Comments) {
ChatService.sendMessage(message, eventKey: eventKey)
}
}
The associated method for the target/action #selector(handleSubmit) must be
#objc func handleSubmit(_ sender: UIButton) { ...
or
#objc func handleSubmit() { ...
Other forms are not supported.
Does the code compile at all?
Actually you can't use self in the initializer let submitButton: UIButton = { .. }()
The problem seems to be that UIButton doesn't have a copyWithZone method and that you can't define delegates for UIButtons:
what are the delegate methods available with uibutton

Resources