Swift UIRefreshControl to UICollectionView inside UIScrollView - swift

I have UICollectioview inside UIScrollView and I want to add UIRefreshControl, but it don't work
private let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
self.refreshControl.addTarget(self, action: #selector(didPullToRefresh(_:)), for: .valueChanged)
self.folderCollectionView.alwaysBounceVertical = true
self.folderCollectionView.bounces = true
self.refreshControl.tintColor = UIColor.black
self.folderCollectionView.refreshControl = refreshControl
}
#objc
private func didPullToRefresh(_ sender: Any) {
print("123")
getFolder(update: true)
refreshControl.endRefreshing()
}
In getFolder I get data and reload collection
When I run collection don't have pull to update and don't work
What have I done wrong

Add UIRefreshControl to the UICollectionView using this way, see the following code, I hope it helps you.
// Add Refresh Control to Collection View
if #available(iOS 10.0, *) {
folderCollectionView.refreshControl = refreshControl
} else {
folderCollectionView.addSubview(refreshControl)
}

Related

How to navigate from one View Controller to the other?

I want to navigate from one View Controller to another.
let vc = SecondViewController()
I have tried until now :
vc.modalPresentationController = .fullScreen
self.present(vc, animated: true) //self refers to the main view controller
Im trying to open a new ViewController when the users manages to register or to log in.I am new to software developing, and I want to ask, is this the best method to navigate from one ViewController to another, im asking because as I can see the mainViewController is not deinit(). I have found other similar questions and tried the answers, the problem is with the:
self.navigationController?.pushViewController
it doesn't work because I don't have any storyboard.
The question is it is right to navigate as explained above?
Thanks,
Typically when you are doing login you would use neither push or present. There are multiple ways of handling this, but the easiest is to embed in some parent (root) VC. Here is an example:
class ViewController: UIViewController {
private var embeddedViewController: UIViewController! {
didSet {
// https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller
// Add the view controller to the container.
addChild(embeddedViewController)
view.addSubview(embeddedViewController.view)
// Create and activate the constraints for the child’s view.
embeddedViewController.view.translatesAutoresizingMaskIntoConstraints = false
embeddedViewController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
embeddedViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
embeddedViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
embeddedViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
// Notify the child view controller that the move is complete.
embeddedViewController.didMove(toParent: self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let loginVC = LoginViewController()
loginVC.delegate = self
embeddedViewController = loginVC
}
}
extension ViewController: LoginDelegate {
func didLogin() {
embeddedViewController = MainViewController()
}
}
protocol LoginDelegate: AnyObject {
func didLogin()
}
class LoginViewController: UIViewController {
private lazy var loginButton: UIButton = {
let button = UIButton()
button.setTitle("Login", for: .normal)
button.addTarget(self, action: #selector(didTapLoginButton), for: .touchUpInside)
return button
}()
weak var delegate: LoginDelegate?
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(loginButton)
view.backgroundColor = .red
loginButton.translatesAutoresizingMaskIntoConstraints = false
loginButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
#objc private func didTapLoginButton() {
delegate?.didLogin()
}
}
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
}
}

Make the UIRefreshControl short for swiping

When using the standard UIRefreshControl in TableView the swipe down can be too long, that is, I have to drag my finger almost to the very bottom of the screen.
Is it possible to shorten the swipe path?
var refreshControl = UIRefreshControl()
#objc func refresh(_ sender: AnyObject) {
// Refresh anything
}
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.addTarget(self, action: #selector(self.refresh(_:)), for: .valueChanged)
refreshControl.backgroundColor = UIColor.clear
TableView.addSubview(refreshControl)
refresh(view)
}
Thank you in advance for your help.
Try it.
refreshControl.addTarget(self, action: #selector(refreshHande(_:)), for: .valueChanged)
let ori = tableView.frame
let temp_frame = CGRect.init(x: ori.origin.x, y: ori.origin.y, width:
ori.size.width, height: ori.size.height/1.3 )
tableView.frame = temp_frame
tableView.addSubview(refreshControl)
tableView.frame = ori
TableView has property refreshControl. Use the following code
var refreshControl = UIRefreshControl()
#objc func refresh(_ sender: AnyObject) {
// Refresh anything
}
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.addTarget(self, action: #selector(self.refresh(_:)), for: .valueChanged)
refreshControl.backgroundColor = UIColor.clear
// tableView is a UITableView outlet
tableView.refreshControl = refreshControl
}

TableView doesn't refresh when created programmatically

I programmatically created a UITableView that fills with data that I fetch from an API. When I fetched the data asynchronously, I try to update my table view—but it does not update.
I first create a UITableView within my UIViewController. The data I am trying to load does load correctly, it just comes in after the initial view has loaded. When I try to refresh my data by doing reloadData(), nothing happens.
What am I missing? Thanks!
Creating my controller:
class SpotifyTableViewController: UIViewController, UITableViewDelegate {
//table view programmatically added
let tableView = UITableView()
var safeArea: UILayoutGuide!
var playlists = [PlaylistItem]()
#objc func handleRefreshControl() {
// Update your content…
tableView.reloadData()
// Dismiss the refresh control.
DispatchQueue.main.async {
self.tableView.refreshControl?.endRefreshing()
}
}
My viewDidLoad() function
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let refreshControl = UIRefreshControl()
tableView.refreshControl?.addTarget(tableView, action:
#selector(handleRefreshControl),
for: .valueChanged)
tableView.refreshControl = refreshControl
self.loadPlaylists(accessToken:
setupTableView()
}
Setting up the table:
func setupTableView() {
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
}
func loadPlaylists(accessToken: String) {
.... make API call and retrieve data
let task = session.dataTask(with: url, completionHandler: { data, response, error in
DispatchQueue.main.async {
// update UI
...
}
}
DispatchQueue.main.async{
self.tableView.reloadData()
}
return
}
}
})
task.resume()
self.tableView.performSelector(onMainThread: Selector("reloadData"), with: nil, waitUntilDone: true)
}
}
the problem is you set tableview delegates after you reload tableview you must add tableview.reloadData() in setupTableView() in last line of code or you can first call setupTableView() and after that call self.loadPlaylists(accessToken:
super.viewDidLoad()
view.backgroundColor = .white
let refreshControl = UIRefreshControl()
tableView.refreshControl?.addTarget(tableView, action:
#selector(handleRefreshControl),
for: .valueChanged)
tableView.refreshControl = refreshControl
setupTableView()
self.loadPlaylists(accessToken:
or
func setupTableView() {
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
}

UIRefresh Control UI bug with large titles & collection view

I am using a UICollectionViewController embedded within a UITabBarController & UINavigationController and when I switch between tabs multiple times I am occasionally experiencing a bug where the refresh control appears above the title when I do not want it to.
Refresh Control UI Bug
Debug View Hierachy
var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.tintColor = UIColor.primaryRed
return refreshControl
}()
refreshControl.addTarget(self, action: #selector(refreshData), for: .valueChanged)
collectionView?.refreshControl = refreshControl
#objc private func refreshData() {
refreshControl.beginRefreshing()
datasource.fetchEvents {
self.refreshControl.endRefreshing()
self.collectionView?.reloadData()
}
}

Creating a checkbox programmatically using images as the UIButtons background

I have seen multiple questions on how to implement a checkbox by just changing the background image when clicked, but I don't understand why the checkbox only shows when I add it to my ViewController setupViews.
It simply will not show up or change when I have all the functionality in my actionButton function. Should i be using a protocol and delegate set up to get my button showing changing when clicked? Below is my code, I am hoping someone can shed some light as to what I am missing here?
class MainMenuViewController: UIViewController {
let clickingCheckbox = ClickingCheckbox()
var checkbox = UIImage(named: "Checked_Checkbox")
var empty_checkbox = UIImage(named:"Empty_Checkbox")
var isBoxClicked: Bool!
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func setupViews() {
self.backgroundImage.addSubview(contentView)
self.contentView.addSubview(clickingCheckbox)
clickingCheckbox.snp.makeConstraints { (make) in
make.top.equalTo(signInButton.snp.bottom).offset(-MainMenuViewController.padding)
make.leading.equalTo(buttonView)
make.width.equalTo(signInButton).multipliedBy(0.2)
make.height.equalTo(clickingCheckbox.snp.width)
}
clickingCheckbox.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
clickingCheckbox.setImage(empty_checkbox, for: UIControlState.normal) #The checkbox only shows on screen if I put it here, however it does nothing when clicked!
}
#objc func buttonAction(_ sender: ClickingCheckbox) {
if isBoxClicked == true {
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true {
sender.setImage(checkbox, for: UIControlState.selected)
}else{
sender.setImage(empty_checkbox, for: UIControlState.normal)
}
print("test")
}
In my Class I have.....
class ClickingCheckbox: UIButton {
override func draw(_ rect: CGRect) {
super.draw(rect)
}
}
I have tried keeping the buttonAction functionality in the class, but that didn't work, I have tried a multiple different ways but can't get my head around how to show it working. All other advice is given to implement using IBOutlets so this would be really helpful for me to understand. Thanks
Try something like this:
class ClickingCheckbox: UIButton {
convenience init() {
self.init(frame: .zero)
self.setImage(UIImage(named: "Empty_Checkbox"), for: .normal)
self.setImage(UIImage(named: "Checked_Checkbox"), for: .selected)
self.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
#objc private func buttonTapped() {
self.isSelected = !self.isSelected
}
}