I have a UITableView with 1 cell and when the array loads I just want for the user to see the content of the first 5 rows and blur the rest. So, if there is an array with 20 items, the first 5 need to be visible and the remaining 15 with a blur. With the code below, I'm able to just add a blur to row 5 only, I can't figure this out. Any help is greatly appreciated.
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) - Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) - UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
cell.cellLbl?.text = array[indexPath.row]
if indexPath.row == 5 {
visualEffectView.frame = cell.bounds
visualEffectView.layer.masksToBounds = true
cell.addSubview(visualEffectView)
}
return cell
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello, I'm working on an app that is fetching data from Firebase and the data is loaded in a UITableView. I'm using pagination (loading 3 posts at a time). Users are allowed to delete their own post. The issue I'm having is when the user deletes the post (first from Firebase and then from the array), the tableView removes the user's post, but it also removes (from the view only) the next 2 posts. Then all I see are the next 3 posts and if I scroll up to see the previous ones, the app crashes because the indexPath.row is out of range. Below is my code. Any help is greatly appreciated:
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
fetchGlimpseData()
configureRefreshControl()
}
func configureRefreshControl() {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
glimpseTableView?.refreshControl = refreshControl
}
private func createSpinnerFooter() -> UIView {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 100))
let spinner = UIActivityIndicatorView()
spinner.center = footerView.center
spinner.color = .brick
footerView.addSubview(spinner)
spinner.startAnimating()
return footerView
}
@objc func handleRefresh() {
glimpse.removeAll(keepingCapacity: false)
self.currentKey = nil
fetchGlimpseData()
}
func fetchGlimpseData() {
if lastDocument == nil {
GLIMPSE_ALL_USERS_DATA.order(by: TIMESTAMP, descending: true).limit(to: 3)
.getDocuments { [self] (snapshot, error) in.... //this block of code works properly
else {
glimpseTableView.tableFooterView = createSpinnerFooter()
GLIMPSE_ALL_USERS_DATA.order(by: TIMESTAMP, descending: true).start(afterDocument: lastDocument!).limit(to: 3)
.getDocuments { [self] (snapshot, error ) in.......//this block of code works properly
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let position = scrollView.contentOffset.y
let maxOffset = scrollView.contentSize.height - scrollView.frame.size.height
if maxOffset - position <= 50 {
fetchGlimpseData()
}}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return glimpse.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let gCell = glimpseTableView.dequeueReusableCell(withIdentifier: "GlimpseCell", for: indexPath) as! GlimpseCell
gCell.delegateProfilePic = self
gCell.delegateGlimpseZoom = self
gCell.delegateGlimpseOption = self
gCell.configureGlimpseCell(glimpse: glimpse[indexPath.row])
gCell.separatorInset = .init(top: 5, left: 0, bottom: 5, right: 0)
gCell.backgroundColor = .beige
gCell.layer.borderWidth = 1
gCell.layer.borderColor = UIColor.gray.cgColor
gCell.selectionStyle = .none
return gCell
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .delete
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
guard editingStyle == .delete else { return }
glimpseTableView.beginUpdates()
glimpse.remove(at: indexPath.row)
glimpseTableView.deleteRows(at: [indexPath], with: .automatic)
glimpseTableView.reloadData()
glimpseTableView.endUpdates()
}
Hello,
I'm working on this messaging app where users have the option of blocking other users. The problem I'm having is reloading the UITableView after a user has been blocked. The first block of code is to block the users:
MemberVC
func blockUserOption(forMember memberData: String, userHasBeenBlocked: Bool, completion: ((Error?) -> Void)?) {
BLOCKED_USERS_COLLECTION.document(currentUID!).getDocument { (snapshot, error) in
let data = [self.memberDocumentID: userHasBeenBlocked]
if snapshot?.exists == true {
BLOCKED_USERS_COLLECTION.document(self.currentUID!).updateData(data)
} else {
BLOCKED_USERS_COLLECTION.document(self.currentUID!).setData(data)
}}}
//Here is how I'm executing the code above:
let blockUser = UIAlertAction(title: "Block", style: .default) { (action) in
let alert = UIAlertController(title: "Block", message: "Are you sure you want to block" + " " + "\(self.memberName as Any)?", preferredStyle: .alert)
alert.view.tintColor = .brick
alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (action: UIAlertAction) in
self.blockUserOption(forMember: self.memberDocumentID, userHasBeenBlocked: true, completion: nil)
self.userDefaults.setValue("yes", forKey: RELOAD)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action: UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
}
Once the user has been blocked, the current view controller gets dismissed and the user goes back to the view controller where the table view needs to reload and remove the blocked user from the list.
MemberListVC
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
let reloadQuery = userDefaults.string(forKey: RELOAD)
if reloadQuery == "yes" {
self.match.removeAll()
let query = MATCH_INFO_COLLECTION.document(currentUID!)
.collection("info").order(by: TIMESTAMP, descending: false)
query.limit(to: 10).getDocuments { (snapshot, error) in
self.filterUsersThatWereBlocked { blockedUsers in
guard let last = snapshot?.documents.last else { return }
guard let snap = snapshot else { return }
snap.documents.forEach({ document in
let data = document.data()
let memberId = data[DOCUMENT_ID] as? String ?? ""
let memberAge = data[AGE] as? Int ?? 0
let memberName = data[FIRST_NAME] as? String ?? ""
let memberImageUrl = data[PROFILE_IMAGE_URL] as? String ?? ""
let memberCurrentCity = data[CURRENT_CITY] as? String ?? ""
let timestamp = data[TIMESTAMP] as? Double ?? 0.0
let matches = Match(memberId: memberId, memberAge: memberAge ,memberName: memberName, memberImageUrl: memberImageUrl, memberCurrentCity: memberCurrentCity, matchTimestamp: Date(timeIntervalSince1970: timestamp))
guard matches.memberId != Auth.auth().currentUser?.uid else { return }
guard blockedUsers[matches.memberId] == nil else { return }
self.match.append(matches)
self.matchedMessagesTV.reloadData()
})
self.lastDocument = last
}
}
userDefaults.setValue("no", forKey: RELOAD)
} else {
print("NOTHING TO DO HERE")
}
}
func filterUsersThatWereBlocked(completion: @escaping([String: Bool]) -> Void) {
guard let currentUid = Auth.auth().currentUser?.uid else { return }
BLOCKED_USERS_COLLECTION.document(currentUid).getDocument { (snapshot, error) in
guard let data = snapshot?.data() as? [String: Bool] else {
completion([String: Bool]())
return
}
completion(data)
}}
Now, if I close and re-open the app, the users that were blocked, do not show up. I'm not sure if the issue is because I'm trying to reload the view inside "viewDidAppear", I tried with "viewWillAppear" and the outcome is the same. Any help is greatly appreciated. Thank you!
I'm trying to replicate the image zoom in/out feature we find in IG, the only issue I'm having is when I zoom-in, the image is not covering the entire screen, it only zooms-in inside the cell. This is a regular setup, a table view, a cell, an image view and a label. I'm not sure what I'm missing here. Any help is greatly appreciated:
View Controller
import UIKit
class ViewController: UIViewController, UITableViewDelegate {
@IBOutlet weak var tableView: UITableView!
var picArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = 300
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return picArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! cell
let data = picArray[indexPath.item]
cell.backgroundColor = .red
cell.setupCell(image: data)
cell.clipsToBounds = false
cell.selectionStyle = .none
return cell
}
}
Cell Class
import UIKit
class cell: UITableViewCell, UIScrollViewDelegate {
@IBOutlet var picture: UIImageView!
@IBOutlet var caption: UILabel!
var zoomEnabled = false
var imgCenter:CGPoint?
override func awakeFromNib() {
super.awakeFromNib()
picture.contentMode = .scaleAspectFill
picture.isUserInteractionEnabled = true
picture.clipsToBounds = false
caption.layer.zPosition = -1
let pinch = UIPinchGestureRecognizer(target: self, action: #selector(self.pinch(sender:)))
pinch.delegate = self
self.picture.addGestureRecognizer(pinch)
let pan = UIPanGestureRecognizer(target: self, action: #selector(self.pan(sender:)))
pan.delegate = self
self.picture.addGestureRecognizer(pan)
}
override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
@objc func pan(sender: UIPanGestureRecognizer) {
if self.zoomEnabled && sender.state == .began {
self.imgCenter = sender.view?.center
} else if self.zoomEnabled && sender.state == .changed {
let translation = sender.translation(in: self)
if let view = sender.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
sender.setTranslation(CGPoint.zero, in: self.picture.superview)
}
}
@objc func pinch(sender: UIPinchGestureRecognizer) {
if sender.state == .began {
let currentScale = self.picture.frame.size.width / self.picture.bounds.size.width
let newScale = currentScale * sender.scale
if newScale > 1 {
self.zoomEnabled = true
}
} else if sender.state == .changed {
guard let view = sender.view else {return}
let pinchCenter = CGPoint(x: sender.location(in: view).x - view.bounds.midX,
y: sender.location(in: view).y - view.bounds.midY)
let transform = view.transform.translatedBy(x: pinchCenter.x, y: pinchCenter.y)
.scaledBy(x: sender.scale, y: sender.scale)
.translatedBy(x: -pinchCenter.x, y: -pinchCenter.y)
let currentScale = self.picture.frame.size.width / self.picture.bounds.size.width
var newScale = currentScale * sender.scale
if newScale < 1 {
newScale = 1
let transform = CGAffineTransform(scaleX: newScale, y: newScale)
self.picture.transform = transform
sender.scale = 1
}else {
view.transform = transform
sender.scale = 1
}
} else if sender.state == .ended {
guard let center = self.imgCenter else {return}
UIView.animate(withDuration: 0.3, animations: {
self.picture.transform = CGAffineTransform.identity
self.picture.center = center
}, completion: { _ in
self.zoomEnabled = false
})
}
}
func setupCell(image: String) {
if let image : UIImage = UIImage(named: image) {
picture.image = image
}
}
}
Hello, I'm working on this chat app and I have a snapshot listener to keep track the number of messages (with a badge) each user receives. I'm using a table view with pagination. The problem I'm having that I can't figure out is when a user gets a message, the table view duplicates the user, increases the badge number every time a message is received. Then, if i open the messages and then i go back to the first VC, there is another duplicate of the user but with no badge number because it was cleared. Any help is greatly appreciated.
VC
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
fetchMatches()
}
func fetchMatches() {
fetchInfo { matches in
self.match = matches
self.matchedMessagesTV.reloadData()
}
}
func fetchInfo(completion: @escaping([Match]) -> Void) {
if lastDocument == nil {
let query = MATCH_INFO_COLLECTION.document(currentUID!)
.collection("info").order(by: MATCH_TIMESTAMP, descending: false)
query.limit(to: 10).addSnapshotListener { (snapshot, error) in
guard let last = snapshot?.documents.last else { return }
guard let snap = snapshot else { return }
snap.documentChanges.forEach({ diff in
let dictionary = diff.document.data()
let memberId = dictionary[DOCUMENT_ID] as? String ?? ""
let memberAge = dictionary[AGE] as? Int ?? 0
let memberName = dictionary[FIRST_NAME] as? String ?? ""
let memberImageUrl = dictionary[PROFILE_IMAGE_URL] as? String ?? ""
let memberCurrentCity = dictionary[CURRENT_CITY] as? String ?? ""
let matchTimestamp = dictionary[MATCH_TIMESTAMP] as? Double ?? 0.0
let messageCounter = dictionary[MESSAGE_COUNTER] as? Int ?? 0
let matches = Match(memberId: memberId, memberAge: memberAge ,memberName: memberName, memberImageUrl: memberImageUrl, memberCurrentCity: memberCurrentCity, matchTimestamp: Date(timeIntervalSince1970: matchTimestamp), messageCounter: messageCounter)
self.match.append(matches)
self.memberId = matches.memberId
self.lastDocument = last
completion(self.match)
})
}
} else {
matchedMessagesTV.tableFooterView = createSpinnerFooter()
let query = MATCH_INFO_COLLECTION.document(currentUID!)
.collection("info").order(by: MATCH_TIMESTAMP, descending: false)
DispatchQueue.main.async {
self.matchedMessagesTV.tableFooterView = nil
}
query.start(afterDocument: self.lastDocument!)
.limit(to: 10).addSnapshotListener { (snapshot, error) in
guard let last = snapshot?.documents.last else { return }
guard let snap = snapshot else { return }
snap.documentChanges.forEach({ diff in
let dictionary = diff.document.data()
let memberId = dictionary[DOCUMENT_ID] as? String ?? ""
let memberAge = dictionary[AGE] as? Int ?? 0
let memberName = dictionary[FIRST_NAME] as? String ?? ""
let memberImageUrl = dictionary[PROFILE_IMAGE_URL] as? String ?? ""
let memberCurrentCity = dictionary[CURRENT_CITY] as? String ?? ""
let matchTimestamp = dictionary[MATCH_TIMESTAMP] as? Double ?? 0.0
let messageCounter = dictionary[MESSAGE_COUNTER] as? Int ?? 0
let matches = Match(memberId: memberId, memberAge: memberAge ,memberName: memberName, memberImageUrl: memberImageUrl, memberCurrentCity: memberCurrentCity, matchTimestamp: Date(timeIntervalSince1970: matchTimestamp), messageCounter: messageCounter)
self.match.append(matches)
self.memberId = matches.memberId
self.lastDocument = last
completion(self.match)
})
}}
}
class Match {
var memberId: String
let memberAge: Int
let memberName: String
let memberImageUrl: String
let memberCurrentCity: String
let matchTimestamp: Date!
let messageCounter: Int
init(memberId: String, memberAge: Int, memberName: String, memberImageUrl: String, memberCurrentCity: String, matchTimestamp: Date, messageCounter: Int) {
self.memberId = memberId
self.memberAge = memberAge
self.memberName = memberName
self.memberImageUrl = memberImageUrl
self.memberCurrentCity = memberCurrentCity
self.matchTimestamp = matchTimestamp
self.messageCounter = messageCounter
}
}
Hi, I'm having a problem when opening a push notification to a specific tab when the app is closed/killed. The code below works properly when the app is in the background or in another tab. If closed and I open the push notification, the app opens to the main screen. Any ideas on how can I get it to open to the correct tab when is completely closed? any help is greatly appreciated.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let scene = UIApplication.shared.connectedScenes.first
if let sceneDelegate = scene?.delegate as? SceneDelegate {
if let tabController = sceneDelegate.window?.rootViewController as? UITabBarController {
tabController.selectedIndex = 1
}
}
}
I'm working on a chat app and I configured a function to check if a user is online. I'm able to see if another user is active or not, but, the issue I'm having is that if I scroll down (I'm using a UITableView) other users show as active and they are not. I placed the code inside the UITableViewCell class. Any suggestions as to what could be the problem are greatly appreciated. Here is my code:
UITableViewCell
`func configureHomeFeedCell(member: Member) {
profileImage.loadImage(with: member.imageURL)
profileName.text = "\(member.name)" + ", " + "\(member.age)"
checkUserOnlineStatus(with: member.documentId) { _ in }
}
func checkUserOnlineStatus(with userId: String, completion: @escaping(Bool) -> Void) {
let query = USERS_COLLECTION.document(userId).collection(IS_ONLINE)
query.getDocuments { (snapshot, error) in
if let error = error {
print("ERROR..\(error.localizedDescription)")
} else {
snapshot?.documents.forEach({ diff in
let isOnline = diff.get(USER_IS_ONLINE) as? Bool
self.onlineViewStatus.backgroundColor = isOnline == true ? .green : .red
completion(isOnline!)
})}}
query.addSnapshotListener { (snapshot, error) in
snapshot?.documentChanges.forEach { diff in
let isOnline = diff.document.get(USER_IS_ONLINE) as? Bool
if (diff.type == .modified) {
self.onlineViewStatus.backgroundColor = isOnline == true ? .green : .red
completion(isOnline!)
}}}
}`