Dynamic cell height with SDWebImage - ios

I have a table view and table view cells with an image view on them. I want them to have a fixed width but with a dynamic height (depending on the image coming in from the server).
I am using SDWebImage to download and set the image, but the table view cells are turning out very weird.
I didn't forget to:
postTableView.estimatedRowHeight = UITableViewAutomaticDimension
postTableView.rowHeight = UITableViewAutomaticDimension
cellForRow method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! TableViewCell
let post = postArray[indexPath.row]
cell.setupCell(with: post)
return cell
}
Table view cell class:
class TableViewCell: UITableViewCell {
#IBOutlet weak var postTitle: UILabel!
#IBOutlet weak var postSource: UILabel!
#IBOutlet weak var postChart: UIImageView!
internal var aspectConstraint: NSLayoutConstraint? {
didSet {
if oldValue != nil {
postChart.removeConstraint(oldValue!)
}
if aspectConstraint != nil {
postChart.addConstraint(aspectConstraint!)
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
selectionStyle = UITableViewCellSelectionStyle.none
}
override func prepareForReuse() {
super.prepareForReuse()
postChart.image = nil
aspectConstraint = nil
}
func setupCell(with post: Post) {
postTitle.text = post.title
postSource.text = post.source
let tempImageView = UIImageView()
tempImageView.sd_setImage(with: URL(string: post.chartURL!), placeholderImage: UIImage(named: "placeholder.png")) { (image, error, cache, url) in
if let image = image {
self.setCustomImage(image: image)
}
}
}
func setCustomImage(image: UIImage) {
let aspect = image.size.width / image.size.height
let constraint = NSLayoutConstraint(item: postChart, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: postChart, attribute: NSLayoutAttribute.height, multiplier: aspect, constant: 0.0)
constraint.priority = UILayoutPriority(rawValue: 999)
aspectConstraint = constraint
postChart.image = image
setNeedsLayout()
}
}

You just need to tell the whole tableView to refresh its view. Use this code in the view controller holding the tableView:
func refreshTableView() {
self.tableView.beginUpdates()
self.tableView.setNeedsDisplay()
self.tableView.endUpdates()
}
Using a delegate pattern tell the viewController to refresh the tableView, so something like:
func setCustomImage(image: UIImage) {
let aspect = image.size.width / image.size.height
let constraint = NSLayoutConstraint(item: postChart, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: postChart, attribute: NSLayoutAttribute.height, multiplier: aspect, constant: 0.0)
constraint.priority = UILayoutPriority(rawValue: 999)
aspectConstraint = constraint
postChart.image = image
// call this to refresh table
delegate.refreshTableView()
}
Post class:
class Post {
var title : String?
var source : String?
var chartURL : String?
var postChart: UIImage?
var category : String?
var rank : CGFloat?
var imageSize: CGSize?
init(data: NSDictionary) {
title = data["title"] as? String
source = data["source"]as? String
chartURL = data["chartURL"] as? String
postChart = data["postChart"] as? UIImage
category = data["category"] as? String
rank = data["rank"] as? CGFloat
}
}

Related

Ad Banner appears under toolbar on certain ViewControllers

On certain viewcontrollers, my ad banner will appear above my tooldbar (which I want). However, on other viewcontrollers, it appears under the toolbar; hidden. All the code is the same for the different swift files. How do I go about putting the ad banner above the toolbar? Pics included:
What I want:
What I don't want:
----Working ad code:
import UIKit
import GoogleMobileAds
class ViewController: UIViewController, GADBannerViewDelegate {
var bannerView: GADBannerView!
override func viewDidLoad(){
super.viewDidLoad()
//---------ADS----------------
// In this case, we instantiate the banner with desired ad size.
bannerView = GADBannerView(adSize: kGADAdSizeBanner)
addBannerViewToView(bannerView)
}
func addBannerViewToView(_ bannerView: GADBannerView) {
bannerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(bannerView)
view.addConstraints(
[NSLayoutConstraint(item: bannerView,
attribute: .bottom,
relatedBy: .equal,
toItem: bottomLayoutGuide,
attribute: .top,
multiplier: 1,
constant: 1),
NSLayoutConstraint(item: bannerView,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 1)
])
bannerView.adUnitID = "ca-app-pub-9944401739416572/3708634126"
bannerView.rootViewController = self
bannerView.load(GADRequest())
}
// Forces Portrait
override var shouldAutorotate : Bool {
return false
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.portrait
}
//End of Forces Portrait */
Not Working Code:
import UIKit
import GoogleMobileAds
///You are using this class a UIViewCOntroller in storyBoard bbut hadnt provided **tablelist: UIViewController**
///This is Necessary in case when you are going to assign it to a UIVIewController
class toollist: UIViewController, UITableViewDataSource, UITableViewDelegate, GADBannerViewDelegate {
var bannerView: GADBannerView!
override func viewDidLoad(){
super.viewDidLoad()
self.navigationController?.navigationBar.barTintColor = UIColor.black
UINavigationBar.appearance().titleTextAttributes = \[NSAttributedString.Key.foregroundColor : UIColor.red\]
///You need to Sert datasource and Delegate as its not a TableViewController its just a Normal TableView
self.animalTableView.dataSource = self
self.animalTableView.delegate = self
self.view.backgroundColor = UIColor.black
//---------ADS-------------------------------------------
// In this case, we instantiate the banner with desired ad size.
bannerView = GADBannerView(adSize: kGADAdSizeBanner)
addBannerViewToView(bannerView)
}
func addBannerViewToView(_ bannerView: GADBannerView) {
bannerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(bannerView)
view.addConstraints(
\[NSLayoutConstraint(item: bannerView,
attribute: .bottom,
relatedBy: .equal,
toItem: bottomLayoutGuide,
attribute: .top,
multiplier: 1,
constant: 1),
NSLayoutConstraint(item: bannerView,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 1)
\])
bannerView.adUnitID = "ca-app-pub-9944401739416572/3708634126"
bannerView.rootViewController = self
bannerView.load(GADRequest())
}
//--------------------------LIST Specs-------------------------------------------------------//
let tool = \["APGAR Calculator","Dopamine Calculator","GCS Calculator","Parkland Burn Formula","Rule of Nines (Adult)","Epocrates","Event Logger","Rate Calculator","Medical Sign Language"/*"EKG Examples"*/\]
///You did not connected a outlet of tableView
///as its not a tableViewController just a TableView so it should be Connected
#IBOutlet weak var animalTableView: UITableView!
///Set elements in cell
func tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "listoftools"/*Identifier*/, for: indexPath)
cell.textLabel?.text = tool\[indexPath.row\]
// FONT STYLE
cell.textLabel?.textColor = UIColor.white
cell.detailTextLabel?.font = UIFont.boldSystemFont(ofSize: 30.0)
cell.textLabel?.textAlignment = .center
self.animalTableView.backgroundColor = UIColor.clear
cell.textLabel?.backgroundColor = UIColor.black
return cell
}
// var AMPT : \[UIImage\] = \[
// UIImage(named: "AMPT")! \]
var sign : \[UIImage\] = \[
UIImage(named: "signlang1")!,
UIImage(named: "signlang2")!,
UIImage(named: "signlang3")!,
UIImage(named: "signlang4")!,
UIImage(named: "signlang5")!,
UIImage(named: "signlang6")!,
UIImage(named: "signlang7")!,
UIImage(named: "signlang8")!,
\]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return tool.count
}
//--------------------------Respiratory List--------------------
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let Tools = UIStoryboard(name: "Tools", bundle: nil)
let Vc = self.storyboard?.instantiateViewController(withIdentifier: "imageViewController") as! imageViewController
let apgarcalc = Tools.instantiateViewController(withIdentifier: "apgarcalculator") as! DopamineCalculator
let dopecalc = Tools.instantiateViewController(withIdentifier: "dopaminecalculator") as! DopamineCalculator
let gcscalc = Tools.instantiateViewController(withIdentifier: "gcscalculator") as! DopamineCalculator
let ruleofninecalc = Tools.instantiateViewController(withIdentifier: "adultruleofnines") as! DopamineCalculator
let burncalc = Tools.instantiateViewController(withIdentifier: "burnpercentcalculator") as! DopamineCalculator
let evenlog = Tools.instantiateViewController(withIdentifier: "OPENTIME") as! eventLogger
let tempo = Tools.instantiateViewController(withIdentifier: "taptempo") as! taptempo
// let ekg = Tools.instantiateViewController(withIdentifier: "ekglist") as! ekglist
// let Vc = self.storyboard?.instantiateViewController(withIdentifier: "imageViewController") as! imageViewController
switch indexPath.row
{
case 0:
self.navigationController?.pushViewController(apgarcalc, animated: true)
break;
case 1:
self.navigationController?.pushViewController(dopecalc, animated: true)
break;
case 2:
self.navigationController?.pushViewController(gcscalc, animated: true)
break;
case 3:
self.navigationController?.pushViewController(burncalc, animated: true)
break;
case 4:
self.navigationController?.pushViewController(ruleofninecalc, animated: true)
break;
case 5:
//epocrates
if let url = URL(string: "http://www.epocrates.com") { UIApplication.shared.openURL(url)}
break;
case 6:
self.navigationController?.pushViewController(evenlog, animated: true)
break;
case 7:
self.navigationController?.pushViewController(tempo, animated: true)
break;
case 8:
Vc.passedArray = sign
self.navigationController?.pushViewController(Vc, animated: true)
break;
default:
self.navigationController?.pushViewController(evenlog, animated: true)
}
}

Show activity indicator in UICollectionView Footer

How to show and hide activity indicator in collection-view footer. I need to add a activity indicator in footer area of collectionview.
Sample for you:
import UIKit
open class PagingTableView: UITableView {
private var loadingView: UIView!
private var indicator: UIActivityIndicatorView!
internal var page: Int = 0
internal var previousItemCount: Int = 0
open var currentPage: Int {
get {
return page
}
}
open weak var pagingDelegate: PagingTableViewDelegate? {
didSet {
pagingDelegate?.paginate(self, to: page)
}
}
open var isLoading: Bool = false {
didSet {
isLoading ? showLoading() : hideLoading()
}
}
open func reset() {
page = 0
previousItemCount = 0
pagingDelegate?.paginate(self, to: page)
}
private func paginate(_ tableView: PagingTableView, forIndexAt indexPath: IndexPath) {
let itemCount = tableView.dataSource?.tableView(tableView, numberOfRowsInSection: indexPath.section) ?? 0
guard indexPath.row == itemCount - 1 else { return }
guard previousItemCount != itemCount else { return }
page += 1
previousItemCount = itemCount
pagingDelegate?.paginate(self, to: page)
}
private func showLoading() {
if loadingView == nil {
createLoadingView()
}
tableFooterView = loadingView
}
private func hideLoading() {
reloadData()
pagingDelegate?.didPaginate?(self, to: page)
tableFooterView = nil
}
private func createLoadingView() {
loadingView = UIView(frame: CGRect(x: 0, y: 0, width: frame.width, height: 50))
indicator = UIActivityIndicatorView()
indicator.color = UIColor.lightGray
indicator.translatesAutoresizingMaskIntoConstraints = false
indicator.startAnimating()
loadingView.addSubview(indicator)
centerIndicator()
tableFooterView = loadingView
}
private func centerIndicator() {
let xCenterConstraint = NSLayoutConstraint(
item: loadingView, attribute: .centerX, relatedBy: .equal,
toItem: indicator, attribute: .centerX, multiplier: 1, constant: 0
)
loadingView.addConstraint(xCenterConstraint)
let yCenterConstraint = NSLayoutConstraint(
item: loadingView, attribute: .centerY, relatedBy: .equal,
toItem: indicator, attribute: .centerY, multiplier: 1, constant: 0
)
loadingView.addConstraint(yCenterConstraint)
}
override open func dequeueReusableCell(withIdentifier identifier: String, for indexPath: IndexPath) -> UITableViewCell {
paginate(self, forIndexAt: indexPath)
return super.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
}
}

While typing on keyboard button tap doesn't get recognized

I've got a problem with my iOS application. I want to implement something like a MessagingViewController where you got a UITextView and Button (sendButton) below an UITableView. If a tap the textView, the keyboard appears, the View goes up.. so far so good.
But, if I am entering random text and tab/press the send button (independent of what should happen now) while typing or if the time gap between typing and Button tab is to small, the tap doesn't get recognized. If you try iMessage or WhatsApp this isn't a problem.
I don't know what to do, I also tried CocoaPods like SlackViewController or InputAccessoryView but it is always the same problem. While typing, the button tap doesn't get recognized. I tried it with the normal IBAction of a UIButton and UITapGestureRecognizer.
I hope somebody can help me, this problem makes the UX horrible.
Thanks a lot!!!
Edit: Here's an example where the Button is in an InputAccessoryView.
import UIKit
class MessagingViewController: UIViewController, UITableViewDataSource {
var messages: [String] = ["12", "32"]
var accessory: UIView!
var cancelButton: UIButton!
var charactersLeftLabel: UILabel!
var sendButton: UIButton!
#IBOutlet var tableView: UITableView!
#IBOutlet var messagesTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.register(UINib(nibName: TableViewCell.className, bundle:nil),
forCellReuseIdentifier: TableViewCell.className)
addAccessoryView()
NotificationCenter.default.addObserver(self, selector: #selector(MessagingViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(MessagingViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as? TableViewCell
cell?.titleLabel.text = "Sender: \(indexPath.row): "
cell?.detailLabel.text = messages[indexPath.row]
return cell!
}
func addAccessoryView() {
let frame = CGRect(x:0, y:0, width: self.view.frame.width,height: 45)
accessory = UIView(frame: frame)
accessory.backgroundColor = UIColor.lightGray
accessory.alpha = 0.6
accessory.translatesAutoresizingMaskIntoConstraints = false
self.messagesTextView.inputAccessoryView = accessory
sendButton = UIButton(type: .custom)
sendButton.setTitleColor(UIColor.red, for: .normal)
sendButton.setTitle("Send", for: .normal)
sendButton.setTitleColor(UIColor.white, for: .disabled)
sendButton.addTarget(self, action: #selector(MessagingViewController.sendButtonTapped(_:)), for: .touchUpInside)
sendButton.showsTouchWhenHighlighted = true
sendButton.isEnabled = true
sendButton.translatesAutoresizingMaskIntoConstraints = false
accessory.addSubview(sendButton)
let sendTrailingConstraint = NSLayoutConstraint(item: sendButton, attribute: .trailing, relatedBy: .equal, toItem: accessory, attribute: .trailing, multiplier: 1.0, constant: -20)
accessory.addConstraint(sendTrailingConstraint)
let sendCenterYConstraint = NSLayoutConstraint(item: sendButton, attribute: .centerY, relatedBy: .equal, toItem: accessory, attribute: .centerY, multiplier: 1.0, constant: 0)
accessory.addConstraint(sendCenterYConstraint)
}
func sendButtonTapped(_ sender: UIButton) {
messages.append(messagesTextView.text)
messagesTextView.text.removeAll()
tableView.reloadData()
tableView.scrollToRow(at: IndexPath(row: messages.count - 1, section: 0), at: .bottom, animated: true)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
}
}
I just tested on my project, it's works without any problem, add your code to see what you did. (i can't comment so i put this as an answer)

UIInputViewController NSAutoresizingMaskLayoutConstraint issue

I keep trying to implement input accessory VC in my app and I faced with the following issue. When I'm trying to modify the height of the root view of my custom UIInputViewController it's working well despite the one problem. The problem is that in the logs I see the following:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
<NSAutoresizingMaskLayoutConstraint:0x174490cc0 UIInputView:0x10a80bb80.(null) == 46.5>,
<NSAutoresizingMaskLayoutConstraint:0x17448cd50 UIInputView:0x10a80bb80.height == 76>,
<NSLayoutConstraint:0x17429b710 UIInputView:0x10a80bb80.top == UIInputSetHostView:0x10402e940.top>
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x17429b710 UIInputView:0x10a80bb80.top == UIInputSetHostView:0x10402e940.top>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Code of my custom UIInputViewController:
import UIKit
import RxSwift
import RxCocoa
#objc protocol InputViewControllerDelegate: NSObjectProtocol {
func answerTextViewDidChange(_ textView: UITextView)
}
class InputViewController: UIInputViewController {
fileprivate var closeButton: UIButton?
private var separatorView: UIView?
private var tipLabel: UILabel?
private var answerTextView: ConstrainedTextView?
private var buttonHeightConstraint: NSLayoutConstraint?
private var separatorHeightConstraint: NSLayoutConstraint?
private var answerTextViewBottomConstraint: NSLayoutConstraint?
weak var delegate: InputViewControllerDelegate?
private let junk = DisposeBag()
private var appropriateMaxLines: Int {
let isPortrait = UIDevice.current.orientation.isPortrait
return isPortrait ? 5 : 3
}
var answerText: String {
get {
return answerTextView?.text ?? ""
}
set {
answerTextView?.text = newValue
}
}
var isAnswerTextViewFirstResponder: Bool {
get {
return answerTextView?.isFirstResponder ?? false
}
set {
_ = newValue ? answerTextView?.becomeFirstResponder() : answerTextView?.resignFirstResponder()
}
}
// MARK: - Life Cycle
deinit {
NotificationCenter.default.removeObserver(self)
}
override func loadView() {
super.loadView()
let notifName = Notification.Name.UIDeviceOrientationDidChange
NotificationCenter.default.addObserver(self,
selector: #selector(rotated),
name: notifName,
object: nil)
configureView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
answerTextView?.maxLines = appropriateMaxLines
setCloseButtonDisabledIfNeeded()
}
// MARK: - Layout
private func configureView() {
view.backgroundColor = RGB(0xF6F6F6)
view.frame = CGRect(x: 0, y: 0, width: screenWidth, height: 70)
view.autoresizingMask = [.flexibleWidth]
// Separator
separatorView = UIView()
separatorView?.backgroundColor = UIColor.lightGray
separatorView?.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(separatorView!)
AutoLayoutEqualizeSuper(separatorView, .left, 0)
AutoLayoutEqualizeSuper(separatorView, .right, 0)
AutoLayoutEqualizeSuper(separatorView, .top, 0)
separatorHeightConstraint = AutoLayoutSetAttribute(separatorView, .height, 1)
// Close Button
closeButton = UIButton(type: .system)
closeButton?.setTitle("Hide", for: .normal)
closeButton?.titleLabel?.font = UIFont.systemFont(ofSize: 17)
closeButton?.translatesAutoresizingMaskIntoConstraints = false
closeButton?.addTarget(self, action: #selector(dismissKeyboard), for: .touchUpInside)
view.addSubview(closeButton!)
AutoLayoutSetAttribute(closeButton, .width, 70)
buttonHeightConstraint = AutoLayoutSetAttribute(closeButton, .height, 35)
AutoLayoutEqualizeSuper(closeButton, .right, -5)
view.addConstraint(NSLayoutConstraint(item: closeButton!, attribute: .top, relatedBy: .equal, toItem: separatorView, attribute: .bottom, multiplier: 1, constant: 0))
// Tip Label
tipLabel = UILabel()
tipLabel?.textColor = UIColor.darkGray
tipLabel?.text = "Your answer:"
tipLabel?.font = UIFont.systemFont(ofSize: 17)
tipLabel?.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tipLabel!)
AutoLayoutEqualizeSuper(tipLabel, .left, 5)
AutoLayoutSetAttribute(tipLabel, .height, 35)
view.addConstraint(NSLayoutConstraint(item: tipLabel!, attribute: .right, relatedBy: .equal, toItem: closeButton, attribute: .left, multiplier: 1, constant: 0))
// Text View
answerTextView = ConstrainedTextView()
answerTextView?.backgroundColor = UIColor.white
answerTextView?.delegate = self
answerTextView?.scrollsToTop = false
answerTextView?.showsVerticalScrollIndicator = false
answerTextView?.font = REG_FONT(15)
answerTextView?.translatesAutoresizingMaskIntoConstraints = false
answerTextView?.layer.masksToBounds = true
answerTextView?.layer.cornerRadius = 7
answerTextView?.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.7).cgColor
answerTextView?.layer.borderWidth = 1
view.addSubview(answerTextView!)
AutoLayoutEqualizeSuper(answerTextView, .left, 5)
AutoLayoutEqualizeSuper(answerTextView, .right, -5)
answerTextViewBottomConstraint = AutoLayoutEqualizeSuper(answerTextView, .bottom, -5)
answerTextView?
.rx
.observe(CGRect.self, "bounds")
.distinctUntilChanged {
$0?.height == $1?.height
}
.subscribe(onNext: { [unowned self] newBounds in
if var newHeight = newBounds?.height,
let separatorHeight = self.separatorHeightConstraint?.constant,
let buttonHeight = self.buttonHeightConstraint?.constant,
let bottomSpace = self.answerTextViewBottomConstraint?.constant {
newHeight = newHeight < 35 ? 35 : newHeight
let generalHeight = newHeight + separatorHeight + buttonHeight + abs(bottomSpace)
var frame = self.view.frame
frame.size.height = generalHeight
self.view.frame = frame
}
})
.addDisposableTo(junk)
}
// MARK: - Other methods
fileprivate func setCloseButtonDisabledIfNeeded() {
closeButton?.isEnabled = answerTextView?.isFirstResponder ?? false
}
func rotated() {
answerTextView?.maxLines = appropriateMaxLines
}
}
// MARK: - UITextViewDelegate Protocol Conformance
extension InputViewController: UITextViewDelegate {
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
textView.inputAccessoryView = view
return true
}
func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
textView.inputAccessoryView = nil
return true
}
func textViewDidBeginEditing(_ textView: UITextView) {
setCloseButtonDisabledIfNeeded()
}
func textViewDidEndEditing(_ textView: UITextView) {
setCloseButtonDisabledIfNeeded()
}
func textViewDidChange(_ textView: UITextView) {
delegate?.answerTextViewDidChange(textView)
}
}

Dynamicly insert Views into custom cell with Dynamic Height

Hello Guys i spend few days figuring out how to solve my problem and i am not much skilled in swift i decided ask some profesionals
My Problem:
DATA: array list of events(apointment, task, etc...)
number of events its not always same thats why i have to insert as many views as events in array and height of each cell is always different
custom cell created with xib file
I am inserting views inside cell ( creating column of apointments and tasks) but i have a problem when scrolling everything start to look really bad. Can someone help me and told my why it look like broken lego when scrolling ?
I want to make something like this
I tried add label to left side of my column of views and it did not work. cell height was small and content did not appear because was hidden under next row. Cell height was only height of that one lable. It ignores constrains of last view and only notice constrain of that label
ViewController
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var data = [PLCalendarDay]()
var tableView : UITableView!
let days = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]
override func viewDidLoad() {
super.viewDidLoad()
for (var i = 0; i<5; i++) {
var boleen = true
if i > 2 {boleen = false}
let calendar = NSCalendar.currentCalendar()
let day = calendar.dateByAddingUnit(.Day, value: i, toDate: NSDate(), options: [])
print("robim pole")
self.data.append(PLCalendarDay(day: day!, withEnd: boleen))
}
tableView = UITableView()
tableView.registerNib(UINib(nibName: "PLCalendarCell", bundle: nil), forCellReuseIdentifier: "PLCalendarCellid")
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
tableView.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .None
self.view.addSubview(tableView!)
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
// self.tableView.reloadSections(NSIndexSet(indexesInRange: NSMakeRange(0, self.tableView.numberOfSections)), withRowAnimation: .None)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("davam cell number")
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("davam cell")
let cell = tableView.dequeueReusableCellWithIdentifier("PLCalendarCellid", forIndexPath: indexPath) as! PLCalendarCell
cell.setupCell(data[indexPath.row].events)
//cell.selectionStyle = .None
// cell.day.text = data[indexPath.row].date.dateStringWithFormat("dd")
// let day = data[indexPath.row].date.dateStringWithFormat("dd-MM-yyyy")
// cell.dayWord.text = days[getDayOfWeek(day)!-1]
print("som awake1 1 1 ")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// cell selected code here
}
func getDayOfWeek(today:String)->Int? {
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
if let todayDate = formatter.dateFromString(today) {
let myCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let myComponents = myCalendar.components(.Weekday, fromDate: todayDate)
let weekDay = myComponents.weekday
return weekDay
} else {
return nil
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 200
}
}
cell file
class PLCalendarCell: UITableViewCell {
#IBOutlet weak var day: UILabel!
#IBOutlet weak var dayWord: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
print("som awake")
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setupCell (events: [PLCalendarEvent]){
let cellWidht = self.contentView.frame.width
var positionY:CGFloat = 10.0
var lastView: UIView? = nil
for event in events {
if event.end != nil {
let view = PLCalendarCellView(frame: CGRectMake(70, positionY, cellWidht, 50.0), time: true)
view.title.text = event.desc
view.time.text = "\(event.start.dateStringWithFormat("dd-MM-yyyy")) - \(event.end!.dateStringWithFormat("dd-MM-yyyy"))"
view.backgroundColor = UIColor.greenColor()
view.layer.cornerRadius = 4
self.addSubview(view)
if lastView == nil {
let constrain = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: 10)
self.addConstraint(constrain)
} else {
let constrain = NSLayoutConstraint(item: lastView!, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 10)
self.addConstraint(constrain)
}
lastView = view
positionY += 60.0
}
else {
let view = PLCalendarCellView(frame: CGRectMake(70, positionY, cellWidht, 30.0), time: false)
view.title.text = event.desc
view.backgroundColor = UIColor.greenColor()
view.layer.cornerRadius = 4
self.addSubview(view)
if lastView == nil {
let constrain = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: 10)
self.addConstraint(constrain)
} else {
let constrain = NSLayoutConstraint(item: lastView!, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 10)
self.addConstraint(constrain)
}
lastView = view
positionY += 40.0
}
}
// eventHolderView.frame = CGRectMake(0, 0, cellWidht, positionY)
// let constrain = NSLayoutConstraint(item: self.contentView, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: lastView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10)
// self.addConstraint(constrain)
let constrain = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: lastView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10)
self.addConstraint(constrain)
}
}
Callendar day
class PLCalendarDay: NSObject {
let date: NSDate!
var events = [PLCalendarEvent]()
init(day: NSDate, withEnd: Bool) {
self.date = NSCalendar.currentCalendar().startOfDayForDate(day)
if withEnd {
for(var i=0; i<5;i++){
events.append(PLCalendarEvent(description: "Only one day", startDate: NSCalendar.currentCalendar().startOfDayForDate(date)))
}
} else {
for(var i=0; i<5;i++){
events.append(PLCalendarEvent(description: "Only one day", startDate: NSCalendar.currentCalendar().startOfDayForDate(date), endDate: date))
}
}
}
}
Callendar event
class PLCalendarEvent : NSObject{
let desc: String
let start: NSDate
var end: NSDate? = nil
init(description: String, startDate: NSDate) {
self.desc = description
self.start = startDate
}
init(description: String, startDate: NSDate, endDate: NSDate) {
self.desc = description
self.start = startDate
self.end = endDate
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
i really cant achieve any good result i will be really thankful for help
I resolve the problem. All i needed was proper constraints but not only vertical but even horizontal.

Resources