I have following controller
class CategoriesViewController: ASViewController<ASTableNode>, CategoriesViewProtocol {
override init(nibName: String?, bundle: Bundle?) {
super.init(node: ASTableNode())
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
node.dataSource = self
node.delegate = self
}
}
extension CategoriesViewController: ASTableDataSource, ASTableDelegate {
func tableNode(_ tableNode: ASTableNode, numberOfRowsInSection section: Int) -> Int {
return 13
}
func tableView(_ tableView: ASTableView, nodeForRowAt indexPath: IndexPath) -> ASCellNode {
let node = CategoryCell()
return node
}
}
class CategoryCell: ASCellNode {
var name: ASTextNode?
init() {
super.init()
self.name = ASTextNode()
name?.attributedText = NSAttributedString(string: "Hello!", attributes: [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue", size: 12.0)])
}
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
let verticalStack = ASStackLayoutSpec.vertical()
verticalStack.children = [ASInsetLayoutSpec(insets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), child: self.name!)]
return verticalStack
}
}
But the table shows blank
What am I doing wrong ?
In your init method of your CategoryCell, you must add the following:
addSubnode(name!)
So your categorycell will look like this:
class CategoryCell: ASCellNode {
var name: ASTextNode?
init() {
super.init()
self.name = ASTextNode()
addSubnode(name!)
name?.attributedText = NSAttributedString(string: "Hello!", attributes: [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue", size: 12.0)])
}
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
let verticalStack = ASStackLayoutSpec.vertical()
verticalStack.children = [ASInsetLayoutSpec(insets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), child: self.name!)]
return verticalStack
}
Related
I have following productviewcontroller which says "Value of type 'SSBadgeButton' has no member 'animationZoom'" -
import UIKit
class ProductViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
let notificationButton = SSBadgeButton()
let rightbarbuttonimage = UIImage(named:"ic_cart")
fileprivate var cart = Cart()
let scrollView = UIScrollView()
let sections = ["Section A", "Section B","Section C", "Section D","Section E","Section F","Section G","Section H", "Section I","Section J","Section K","Section L"]
let rowspersection = [2,3,1,2,2,3,3,1,4,2,1,2]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.tableView.backgroundColor = UIColor.gray
//Add and setup scroll view
self.tableView.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.tableView.leadingAnchor, constant: 20).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.tableView.topAnchor, constant: 20).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.tableView.trailingAnchor, constant: -20).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.tableView.bottomAnchor, constant: -20).isActive = true;
// customising rightBarButtonItems as notificationbutton
notificationButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
notificationButton.setImage(UIImage(named: "ic_cart")?.withRenderingMode(.alwaysTemplate), for: .normal)
notificationButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: notificationButton)
//following register is needed because I have rightbarbuttonitem customised as uibutton i.e. notificationbutton
notificationButton.addTarget(self, action: #selector(self.registerTapped(_:)), for: .touchUpInside)
}
#objc func registerTapped(_ sender: UIButton) {
self.performSegue(withIdentifier: "showCart", sender: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Workaround to avoid the fadout the right bar button item
self.navigationItem.rightBarButtonItem?.isEnabled = false
self.navigationItem.rightBarButtonItem?.isEnabled = true
//Update cart if some items quantity is equal to 0 and reload the product table and right button bar item
cart.updateCart()
//self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
notificationButton.badge = String(cart.items.count)// making badge equal to no.ofitems in cart
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// this segue to transfer data
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showCart" {
if let cartViewController = segue.destination as? CartViewController {
cartViewController.cart = self.cart
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return productMap.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productMap[section]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let product = productMap[indexPath.section]![indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "ProductTableViewCell") as! ProductTableViewCell
cell.imageView?.image = product.imagename
cell.delegate = self as CartDelegate
cell.setButton(state: self.cart.contains(product: product))
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch(section) {
case 0: return "Section A"
case 1: return "Section B"
case 2: return "Section C"
case 3: return "Section D"
case 4: return "Section E"
case 5: return "Section F"
case 6: return "Section G"
case 7: return "Section H"
case 8: return "Section I"
case 9: return "Section J"
case 10: return "Section K"
case 11: return "Section L"
default: return ""
}
}
}
extension ProductViewController: CartDelegate {
// MARK: - CartDelegate
func updateCart(cell: ProductTableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
let product = productMap[indexPath.section]![indexPath.row]
var selectedIndexPaths = [IndexPath]()
if selectedIndexPaths.contains(indexPath) {
if let index = selectedIndexPaths.firstIndex(of: indexPath) {
selectedIndexPaths.remove(at: index)
removeProductFromCart(indexPath: indexPath)
}
} else {
selectedIndexPaths.append(indexPath)
addProductToCart(indexPath: indexPath)
}
addProductToCart(indexPath: indexPath)
//Update Cart with product
cart.updateCart(with: product)
self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
notificationButton.badge = String(cart.items.count) // making badge equal to noofitems in cart
}
func addProductToCart(indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? ProductTableViewCell {
if let imageView = cell.imagename {
let initialImageViewFrame = imageView.convert(imageView.frame, to: self.view)
let targetImageViewFrame = self.notificationButton.frame
let imgViewTemp = UIImageView(frame: initialImageViewFrame)
imgViewTemp.clipsToBounds = true
imgViewTemp.contentMode = .scaleAspectFill
imgViewTemp.image = imageView.image
self.view.addSubview(imgViewTemp)
UIView.animate(withDuration: 1.0, animations: {
imgViewTemp.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}) { _ in
UIView.animate(withDuration: 0.5, animations: {
imgViewTemp.transform = CGAffineTransform(scaleX: 0.2, y: 0.2).rotated(by: CGFloat(Double.pi))
imgViewTemp.frame = targetImageViewFrame
}) { _ in
imgViewTemp.removeFromSuperview()
UIView.animate(withDuration: 1.0, animations: {
self.notificationButton.transform = CGAffineTransform(scaleX: 1.4, y: 1.4)
}, completion: {_ in
self.notificationButton.transform = CGAffineTransform.identity
})
}
}
}
}
}
func removeProductFromCart(indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? ProductTableViewCell {
if let imageView = cell.imagename {
let initialImageViewFrame = self.notificationButton.frame
let targetImageViewFrame = imageView.convert(imageView.frame, to: self.view)
let imgViewTemp = UIImageView(frame: initialImageViewFrame)
imgViewTemp.clipsToBounds = true
imgViewTemp.contentMode = .scaleAspectFill
imgViewTemp.image = imageView.image
self.view.addSubview(imgViewTemp)
var initialTransform = CGAffineTransform.identity
initialTransform = initialTransform.scaledBy(x: 0.2, y: 0.2)
initialTransform = initialTransform.rotated(by: CGFloat(Double.pi))
UIView.animate(withDuration: 0.5, animations: {
self.notificationButton.animationZoom(scaleX: 1.4, y: 1.4) ***//Error - Value of type 'SSBadgeButton' has no member 'animationZoom'***
imgViewTemp.transform = initialTransform
}) { _ in
UIView.animate(withDuration: 1, animations: {
self.notificationButton.animationZoom(scaleX: 1, y: 1)
imgViewTemp.transform = CGAffineTransform.identity
imgViewTemp.frame = targetImageViewFrame
}) { _ in
imgViewTemp.removeFromSuperview()
}
}
}
}
}
}
This is my code for "SSBadgeButton" -
import UIKit
class SSBadgeButton: UIButton {
var badgeLabel = UILabel()
var badge: String? {
didSet {
addBadgeToButon(badge: badge)
}
}
public var badgeBackgroundColor = UIColor.red {
didSet {
badgeLabel.backgroundColor = badgeBackgroundColor
}
}
public var badgeTextColor = UIColor.white {
didSet {
badgeLabel.textColor = badgeTextColor
}
}
public var badgeFont = UIFont.systemFont(ofSize: 12.0) {
didSet {
badgeLabel.font = badgeFont
}
}
public var badgeEdgeInsets: UIEdgeInsets? {
didSet {
addBadgeToButon(badge: badge)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addBadgeToButon(badge: nil)
}
func addBadgeToButon(badge: String?) {
badgeLabel.text = badge
badgeLabel.textColor = badgeTextColor
badgeLabel.backgroundColor = badgeBackgroundColor
badgeLabel.font = badgeFont
badgeLabel.sizeToFit()
badgeLabel.textAlignment = .center
let badgeSize = badgeLabel.frame.size
let height = max(18, Double(badgeSize.height) + 5.0)
let width = max(height, Double(badgeSize.width) + 10.0)
var vertical: Double?, horizontal: Double?
if let badgeInset = self.badgeEdgeInsets {
vertical = Double(badgeInset.top) - Double(badgeInset.bottom)
horizontal = Double(badgeInset.left) - Double(badgeInset.right)
let x = (Double(bounds.size.width) - 10 + horizontal!)
let y = -(Double(badgeSize.height) / 2) - 10 + vertical!
badgeLabel.frame = CGRect(x: x, y: y, width: width, height: height)
} else {
let x = self.frame.width - CGFloat((width / 2.0))
let y = CGFloat(-(height / 2.0))
badgeLabel.frame = CGRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height))
}
badgeLabel.layer.cornerRadius = badgeLabel.frame.height/2
badgeLabel.layer.masksToBounds = true
addSubview(badgeLabel)
badgeLabel.isHidden = badge != nil ? false : true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addBadgeToButon(badge: nil)
fatalError("init(coder:) has not been implemented")
}
}
Earlier, it used to work fine. It used to zoom the animation Now, I don't know why it does not work fine ? please help me with this. The code also seems okay. still, it does not work fine.
I have a class:
class CustomLayout: UICollectionViewLayout {
// Cant pass it directly into the init because it is an override init :/
override init() {
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
weak var delegate: layoutDelegate?
private var cache: [UICollectionViewLayoutAttributes] = []
private var contentHeight: CGFloat = 0
private var contentWidth: CGFloat {
guard let collectionView = collectionView else {
print("Collectionview not found")
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func prepare() {
guard
cache.isEmpty,
let collectionView = collectionView
else { print("No Collectionview rip"); return }
let columnWidth = contentWidth
for item in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let postHeight = delegate?.collectionView(_collectionView: collectionView, heightForPostAtIndexPath: indexPath) ?? 200
let height = postHeight
let frame = CGRect(x: 0, y: 0, width: columnWidth, height: height)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
cache.append(attributes)
contentHeight = max(contentHeight, frame.maxY)
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []
// Loop through the cache and look for items in the rect
for attributes in cache {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
}
What I am trying to do is pass a variable called CustomCollectionView into this class so that I can use this variable instead of the default collectionVIew. However I am unsure how I am supposed to do this because this class has an override init() which doesn't allow you to pass variables into.
How do I pass a CustomCollectionView variable into this class?
I'm trying to add a new NSTextView to the last index in my collection view every time the attributed string exceeds a certain bounds. The code works perfectly until the 5th item then it starts its starts creating an item every time the enter button is pressed. I'm thinking its a bug but im not sure. if any one can show me a better way to do it or improve the current code I have I would appreciate it. Below is my code:
Here is the CollectionViewItem
class DocumentItem: NSCollectionViewItem {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
self.itemView?.wantsLayer = true
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
}
func getView() -> DocumentTextView {
return self.itemView!
}
}
Here is the collectionView datasource
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return DocList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "DocumentItem"), for: indexPath)
return item
}
Here is the NSTextView subclass
class DocumentTextView: NSTextView {
var theContainer = NSTextContainer()
var theStorage = NSTextStorage()
var theManager = NSLayoutManager()
var table = NSTextTable()
var pdfPage: PDFPage?
override init(frame frameRect: NSRect) {
super.init(frame: NSRect(origin: frameRect.origin, size: NSSize(width: 800, height: 1131 )), textContainer: theContainer)
theStorage.addLayoutManager(theManager)
theManager.addTextContainer(theContainer)
self.textContainerInset = CGSize(width: 50, height: 50)
self.textContainer?.widthTracksTextView = true
self.textContainer?.heightTracksTextView = true
self.textContainer?.lineBreakMode = .byWordWrapping
self.maxSize = NSSize(width: 800, height: 1131)
self.backgroundColor = NSColor.fromHexString("ffffff")!
self.isRichText = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is the function bringing the bug
func textDidChange(_ notification: Notification) {
var textView = notification.object as? DocumentTextView
let numberOfItems = theDocumentOutlineView.numberOfItems(inSection: 0)
let theLastTextView = theDocumentOutlineView.item(at: numberOfItems - 1) as! DocumentItem
if textView == theLastTextView.itemView {
print(textView?.attributedString().size())
if (textView?.attributedString().size().height)! >= 1106.0 {
self.DocList.append(2)
var set = Set<IndexPath>()
set.insert(NSIndexPath(forItem: self.DocList.count - 1 , inSection: 0) as IndexPath)
theDocumentOutlineView.insertItems(at: set)
theDocumentOutlineView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
var newFirstResponder = theDocumentOutlineView.item(at: self.DocList.count - 1) as! DocumentItem
newFirstResponder.itemView?.delegate = self
self.view.window?.makeFirstResponder(newFirstResponder.itemView)
}
}
}
Here's my test project, maybe it helps. The delegate of the text view is its view controller, the NSCollectionViewItem. The view controller of the collection view also receives NSText.didChangeNotification notifications to check the length of the text. heightTracksTextView of the text container is false.
ViewController:
class ViewController: NSViewController, NSCollectionViewDataSource, NSCollectionViewDelegate {
#IBOutlet weak var collectionView: NSCollectionView!
var docList: [DocumentObject] = [DocumentObject(index: 0, string: NSAttributedString(string: "New 0"))]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(DocumentItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"))
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange),
name: NSText.didChangeNotification, object: nil)
}
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return docList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
if let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"),
for: indexPath) as? DocumentItem {
item.representedObject = docList[indexPath.item]
return item
}
return NSCollectionViewItem()
}
#objc func textDidChange(_ notification: Notification) {
if let textView = notification.object as? NSTextView {
if let theLastItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem,
textView === theLastItem.itemView {
//if textView.attributedString().size().height >= 1106.0 {
print("\(textView.attributedString().size().height) \(textView.layoutManager!.usedRect(for: textView.textContainer!).size.height)")
if let textContainer = textView.textContainer,
let heigth = textView.layoutManager?.usedRect(for: textContainer).size.height,
heigth >= 1106.0 {
DispatchQueue.main.async {
if let window = self.view.window,
window.makeFirstResponder(nil) { // end editing of previous item
self.docList.append(DocumentObject(index: self.docList.count - 1, string: NSAttributedString(string: "New \(self.docList.count)")))
let set: Set = [IndexPath(item: self.docList.count - 1, section: 0)]
self.collectionView.insertItems(at: set)
self.collectionView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
if let newItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem {
window.makeFirstResponder(newItem.itemView)
}
}
}
}
}
}
}
}
DocumentItem:
class DocumentItem: NSCollectionViewItem, NSTextViewDelegate {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
self.itemView?.delegate = self
}
override var representedObject: Any? {
didSet {
if let item = representedObject as? DocumentObject {
itemView?.textStorage?.setAttributedString(item.string)
}
}
}
func textDidEndEditing(_ notification: Notification) {
if let item = representedObject as? DocumentObject {
item.string = itemView?.textStorage?.copy() as! NSAttributedString
}
}
}
DocumentObject:
class DocumentObject {
var index: Int
var string: NSAttributedString
init(index: Int, string: NSAttributedString) {
self.index = index
self.string = string
}
}
I'm having an issue, I can append all the posts into my collection view but the username and profileImage change to whoever the currently logged in user is. Can someone help me figure out how to set it to the user who posted it?
import UIKit
import Firebase
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var cellId = "cellId"
var filteredPosts = [Post]()
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handleUpdateFeed), name: PostController.updateFeedNotificationName, object: nil)
collectionView?.backgroundColor = UIColor(red: 240/255, green: 240/255, blue: 240/255, alpha: 1)
collectionView?.register(HomePostCell.self, forCellWithReuseIdentifier: cellId)
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
collectionView?.refreshControl = refreshControl
setupNavigationItems()
fetchPosts()
}
#objc func handleUpdateFeed() {
handleRefresh()
}
fileprivate func fetchPosts() {
guard let uid = FIRAuth.auth()?.currentUser?.uid else { return }
FIRDatabase.fetchUserWithUID(uid: uid) { (user) in
self.fetchPostsWithUser(user: user)
}
}
fileprivate func fetchPostsWithUser(user: User) {
let ref = FIRDatabase.database().reference().child("posts")
ref.observe(.childAdded, with: { (snapshot) in
guard let dictionaries = snapshot.value as? [String: Any]
else { return }
dictionaries.forEach({ (key, value) in
guard let userDictionary = value as? [String: Any] else { return }
var post = Post(user: user, dictionary: userDictionary)
self.posts.append(post)
})
self.posts.sort(by: { (post1, post2) -> Bool in
return post1.creationDate.compare(post2.creationDate) == .orderedDescending
})
self.collectionView?.reloadData()
}) { (err) in
print("Failed to fetch posts.",err)
}
}
#objc func handleRefresh() {
self.posts.removeAll()
self.fetchPosts()
DispatchQueue.global(qos: .background).async {
self.collectionView?.reloadData()
self.collectionView?.refreshControl?.endRefreshing()
}
}
func setupNavigationItems() {
navigationItem.title = "Events"
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "download").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleFilter))
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! HomePostCell
cell.post = posts[indexPath.item]
return cell
}
}
import UIKit
class HomePostCell: UICollectionViewCell {
var post: Post? {
didSet{
usernameLabel.text = post?.user.username
guard let profileImageUrl = post?.user.profileImageUrl else { return }
userProfileImageView.loadImage(urlString: profileImageUrl)
setupCaptionText()
setupDateLabel()
}
}
let userProfileImageView: CustomImageView = {
let iv = CustomImageView()
iv.clipsToBounds = true
iv.contentMode = .scaleAspectFill
return iv
}()
let usernameLabel: UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
return label
}()
let captionLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.backgroundColor = .white
return label
}()
let dateLabel: UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
return label
}()
let optionsButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("•••", for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
return button
}()
fileprivate func setupCaptionText() {
guard let post = self.post else { return }
let attributedText = NSMutableAttributedString(string: " \(post.caption)", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14)])
captionLabel.attributedText = attributedText
}
fileprivate func setupDateLabel() {
guard let post = self.post else { return }
let timeAgoDisplay = post.creationDate.timeAgoDisplay()
let attributedText = NSMutableAttributedString(string: timeAgoDisplay, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14), NSAttributedStringKey.foregroundColor: UIColor.gray])
dateLabel.attributedText = attributedText
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(userProfileImageView)
userProfileImageView.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 8, paddingLeft: 8, paddingBottom: 5, paddingRight: 0, width: 40, height: 40)
userProfileImageView.layer.cornerRadius = 40 / 2
backgroundColor = .white
addSubview(usernameLabel)
usernameLabel.anchor(top: topAnchor, left: userProfileImageView.rightAnchor, bottom: nil, right: nil, paddingTop: 12, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
addSubview(captionLabel)
captionLabel.anchor(top: userProfileImageView.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 10, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
addSubview(optionsButton)
optionsButton.anchor(top: topAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: 5, paddingLeft: 0, paddingBottom: 0, paddingRight: 10, width: 0, height: 0)
addSubview(dateLabel)
dateLabel.anchor(top: nil, left: leftAnchor, bottom: bottomAnchor, right: nil, paddingTop: 0, paddingLeft: 8, paddingBottom: 5, paddingRight: 0, width: 0, height: 0)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import Foundation
struct User {
var uid: String
let username: String
let profileImageUrl: String
init(uid: String, dictionary: [String: Any]) {
self.uid = uid
self.username = dictionary["usernames"] as? String ?? ""
self.profileImageUrl = dictionary["profileImageUrl"] as? String ?? ""
}
}
import Foundation
struct Post {
var id: String?
let user: User
let caption: String
let creationDate: Date
init(user: User, dictionary: [String: Any]) {
self.user = user
self.caption = dictionary["caption"] as? String ?? ""
let secondsFrom1970 = dictionary["creationDate"] as? Double ?? 0
self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
}
}
This code here:
fileprivate func fetchPosts() {
guard let uid = FIRAuth.auth()?.currentUser?.uid else { return }
FIRDatabase.fetchUserWithUID(uid: uid) { (user) in
self.fetchPostsWithUser(user: user)
}
}
You're basically making a query based on the currentUser?.uid and not on the user that created the post. You're passing that to the fileprivate func fetchPostsWithUser(user: User) hence it retrieves the same logged in user.
It actually should pass the user.uid stored for each post on the database (unless you want to pull out the posts for the currentUser and display those.
Each post at the moment of posting needs to store the user uid and store that on the database. Then make query to get those posts based on the uid of the user. And cache your users in an array just like you did with your posts.
UPDATED:
class Post {
var id : String?
var title : String?
var content : String?
var userUid : String?
static func transformDataToPost (dictionary: [String : Any], key: String) -> Post {
let post = Post()
post.id = key // this is the snapshot.key that you get
post.userUid = dictionary["userUid"] as? String
post.title = dictionary["title"] as? String
post.content = dictionary["content"] as? String
return
}
Now, when observing the post to get data back from Firebase I'm using it a little more structured, in another class, ie, I have separate PostApi class where I deal with all API requests, not in the UIViewController itself, but the idea is the same.
var REF_POSTS = Database.database().reference().child("posts")
func observePost(withId id: String, completion: #escaping (Post) -> Void) {
REF_POSTS.child(id).observeSingleEvent(of: .value, with: { snapshot in
if let dictionary = snapshot.value as? [String : Any] {
let post = Post.transformDataToPost(dictionary: dictionary, key: snapshot.key)
completion(post)
}
})
}
For sending the data to FirebaseDatabase I do it the following way:
static func sendPostDataToDatabase ( title: String?,
content: String?,
onSuccess: #escaping () -> Void,
onError: #escaping (_ errorMessage: String?) -> Void) {
let newPostId = Api.Post.REF_POSTS.childByAutoId().key // THIS creates the new ID of a post, it's just a dynamic way to get a unique post ID , you can also use NSUUID().uuidString which will give you a unique string
// the definition of `uuidString` is: A string containing a formatted UUID for example E621E1F8-C36C-495A-93FC-0C247A3E6E5F.
let newPostReference = Api.Post.REF_POSTS.child(newPostId)
// MARK: - TIMESTAMP FEATURE
let timestamp = Int(Date().timeIntervalSince1970)
var newPostDict = [ "userUid" : Api.Users.CURRENT_USER!.uid,
"title" : title as Any,
"content" : content as Any,
"timestamp" : timestamp
] as [String : Any]
newPostReference.setValue(newPostDict) { (error, databaseRef) in
if error != nil {
onError(error!.localizedDescription)
return
}
else {
onSuccess(newShipId, photosArray[0])
}
}
I'm trying to use tableviewcotroller with this but when look at the screenshot at the button will seen a issue I need helping fixing so if anyone knows how to fix this plz help I don't want use SWRevealViewController I'm also doing with all code not scoreboards thanks for the help
class SidebarView: UIView, UITableViewDelegate, UITableViewDataSource {
var titleArr = [String]()
weak var delegate: SidebarViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
self.clipsToBounds=true
titleArr = ["Brittney Atwood", "Messages", "Contact", "Settings", "History", "Help", "Sign Out"]
setupViews()
myTableView.delegate=self
myTableView.dataSource=self
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
myTableView.tableFooterView=UIView()
myTableView.separatorStyle = UITableViewCellSeparatorStyle.none
myTableView.allowsSelection = true
myTableView.bounces=false
myTableView.showsVerticalScrollIndicator=false
myTableView.backgroundView = UIImageView(image: #imageLiteral(resourceName: "Rectangle 96"))
myTableView.isOpaque = false
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titleArr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.backgroundColor = .clear
cell.selectionStyle = .none
if indexPath.row == 0 {
let cellImg: UIImageView!
cellImg = UIImageView(frame: CGRect(x: 15, y: 10, width: 80, height: 80))
cellImg.layer.cornerRadius = 40
cellImg.layer.masksToBounds=true
cellImg.contentMode = .scaleAspectFill
cellImg.layer.masksToBounds=true
cellImg.image=#imageLiteral(resourceName: "user11")
cell.addSubview(cellImg)
let cellLbl = UILabel(frame: CGRect(x: 110, y: cell.frame.height/2-15, width: 250, height: 30))
cell.addSubview(cellLbl)
cellLbl.text = titleArr[indexPath.row]
cellLbl.font=UIFont.systemFont(ofSize: 17)
cellLbl.textColor=UIColor.white
} else {
cell.textLabel?.text=titleArr[indexPath.row]
cell.textLabel?.textColor=UIColor.white
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.delegate?.sidebarDidSelectRow(row: Row(row: indexPath.row))
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 100
} else {
return 60
}
}
func setupViews() {
self.addSubview(myTableView)
myTableView.topAnchor.constraint(equalTo: topAnchor).isActive=true
myTableView.leftAnchor.constraint(equalTo: leftAnchor).isActive=true
myTableView.rightAnchor.constraint(equalTo: rightAnchor).isActive=true
myTableView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive=true
}
let myTableView: UITableView = {
let table=UITableView()
table.translatesAutoresizingMaskIntoConstraints=false
return table
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Please write this code it may helps to you.
var topSafeArea: CGFloat
var bottomSafeArea: CGFloat
if #available(iOS 11.0, *) {
topSafeArea = view.safeAreaInsets.top
bottomSafeArea = view.safeAreaInsets.bottom
} else {
topSafeArea = topLayoutGuide.length
bottomSafeArea = bottomLayoutGuide.length
}
// safe area values are now available to use
Thank you.
that the view controller I don’t know where the issue is it probably in one of the two files that I post it still not fix
class ViewController: UITableViewController {
var sidebarView: SidebarView!
var blackScreen: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Messages"
let btnMenu = UIBarButtonItem(image: #imageLiteral(resourceName: "menu"), style: .plain, target: self, action: #selector(btnMenuAction))
btnMenu.tintColor=UIColor(red: 54/255, green: 55/255, blue: 56/255, alpha: 1.0)
self.navigationItem.leftBarButtonItem = btnMenu
sidebarView=SidebarView(frame: CGRect(x: 0, y: 0, width: 0, height: self.view.frame.height))
sidebarView.delegate=self
sidebarView.layer.zPosition=100
self.view.isUserInteractionEnabled=true
self.navigationController?.view.addSubview(sidebarView)
blackScreen=UIView(frame: self.view.bounds)
blackScreen.backgroundColor=UIColor(white: 0, alpha: 0.5)
blackScreen.isHidden=true
self.navigationController?.view.addSubview(blackScreen)
blackScreen.layer.zPosition=99
let tapGestRecognizer = UITapGestureRecognizer(target: self, action: #selector(blackScreenTapAction(sender:)))
blackScreen.addGestureRecognizer(tapGestRecognizer)
}
#objc func btnMenuAction() {
blackScreen.isHidden=false
UIView.animate(withDuration: 0.3, animations: {
self.sidebarView.frame=CGRect(x: 0, y: 0, width: 250, height: self.sidebarView.frame.height)
}) { (complete) in
self.blackScreen.frame=CGRect(x: self.sidebarView.frame.width, y: 0, width: self.view.frame.width-self.sidebarView.frame.width, height: self.view.bounds.height+100)
}
}
#objc func blackScreenTapAction(sender: UITapGestureRecognizer) {
blackScreen.isHidden=true
blackScreen.frame=self.view.bounds
UIView.animate(withDuration: 0.3) {
self.sidebarView.frame=CGRect(x: 0, y: 0, width: 0, height: self.sidebarView.frame.height)
}
}
}
extension ViewController: SidebarViewDelegate {
func sidebarDidSelectRow(row: Row) {
blackScreen.isHidden=true
blackScreen.frame=self.view.bounds
UIView.animate(withDuration: 0.3) {
self.sidebarView.frame=CGRect(x: 0, y: 0, width: 0, height: self.sidebarView.frame.height)
}
switch row {
case .editProfile:
let vc=EditProfileVC()
self.navigationController?.pushViewController(vc, animated: true)
case .messages:
print("Messages")
case .contact:
print("Contact")
case .settings:
print("Settings")
case .history:
print("History")
case .help:
print("Help")
case .signOut:
print("Sign out")
case .none:
break
// default: //Default will never be executed
// break
}
}
}