Make the UIRefreshControl short for swiping - swift

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
}

Related

Swift - UITapGestureRecognizer for parent view only

I have a UIViewController with a subview of a UIView. I add a UITapGestureRecognizer to the UIViewController to dismiss the view, but when I tap on the subview, the whole view still dismisses and I only want to dismiss when tapping the parent view.
var backgroundView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let tap = UITapGestureRecognizer(target: self, action: #selector(didTapOutsideBackgroundView))
tap.numberOfTapsRequired = 1
view.addGestureRecognizer(tap)
setupUI()
}
func setupUI() {
view.addSubview(backgroundView)
backgroundView.translatesAutoresizingMaskIntoConstraints = false
backgroundView.layer.cornerRadius = 8
NSLayoutConstraint.activate([
backgroundView.topAnchor.constraint(equalTo: view.topAnchor, constant: distanceFromTop ?? 0),
backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
backgroundView.backgroundColor = .systemBackground
// add subviews to backgroundView
backgroundView.addSubview(pageTitle)
backgroundView.addSubview(closeButton)
backgroundView.addSubview(itemLabel)
backgroundView.addSubview(itemNameLabel)
backgroundView.addSubview(priceLabel)
backgroundView.addSubview(quantityLabel)
backgroundView.addSubview(itemQuantityLabel)
backgroundView.addSubview(itemOriginalPriceLabel)
}
#objc func didTapOutsideBackgroundView(sender: UITapGestureRecognizer) {
print("called")
dismiss(animated: true)
}
You can find tapped view and ignore the tap if its a backgroundView with this in your didTapOutsideBackgroundView
#objc func didTapOutsideBackgroundView(sender: UITapGestureRecognizer) {
let location = sender.location(in: self.view)
if let view = self.view.hitTest(location, with: nil), let guester = view.gestureRecognizers {
if guester.contains(sender) {
print("Parent tapped")
dismiss(animated: true)
}
} else {
print("Ignore tap")
}
}
One solution can be check if it is subview or not & ignore based on that.
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view.isDescendantOfView(yourSubView){ // this will check if this is subview of the main view or not..
return false
}
return true
}

#selector(didTapRegister) not in scope

When I run this code by #selector(didTapRegister) I get a didTapRegister is not in scope. I have a bigger application I am using it in and on one page it works and another it won't, well it won't work anywhere else.
I am stuck on figuring out why. Can anyone help solve it? seems to be an Objective-C issue possibly because I have same issues trying to make IBOutlets, I have tried searching for answers and I just don't have enough knowledge to understand why it isn't working, I've tried moving the code to different scopes and still nothing. with the IBOutlets it's saying IBOutlet property cannot have non-object type UIButton?.Type
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let Button = UIButton.init(type: .custom)
Button.setTitle("Chat", for: .normal)
Button.layer.backgroundColor = CGColor.init(gray: 0.0, alpha: 0.0)
Button.setTitleColor(.white, for: .normal)
Button.setTitleColor(.red, for: .highlighted)
Button.layer.borderWidth = 1
Button.layer.cornerRadius = 5
Button.layer.borderColor = UIColor.white.cgColor
Button.isHighlighted = false
Button.showsTouchWhenHighlighted = true
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: Button)
Button.addTarget(self, action: #selector(didTapRegister), for: .touchUpInside)
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.isTranslucent = true
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Do any additional setup after loading the view.
}
}
}
Maybe try what he said but
Just use SwiftUI it is much better
#objc and all of that is fine but in SwiftUI you can just right click and add buttons
There 2 mistakes in the code.
You have to create #objc function for the button action
In your code move viewWillAppear method outside the viewDidLoad
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton.init(type: .custom)
button.setTitle("Chat", for: .normal)
button.setTitleColor(.white, for: .normal)
button.setTitleColor(.red, for: .highlighted)
button.layer.borderWidth = 1
button.layer.cornerRadius = 5
button.layer.borderColor = UIColor.white.cgColor
button.isHighlighted = false
button.showsTouchWhenHighlighted = true
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
button.addTarget(self, action: #selector(didTapRegister), for: .touchUpInside)
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.isTranslucent = true
}
#objc func didTapRegister(_ sender: UIButton) {
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Do any additional setup after loading the view.
}
}
Note: button name start with lowercase.

How should I set button's image in same action?

In my ViewController,
there is multiple buttons connected to the same action
my button is like check or uncheck
I have tried below
My action is triggered, but image didn't change
var uncheckBoxImage = UIImage(named: "uncheckBox")
var checkBoxImage = UIImage(named: "checkBox")
override func viewDidLoad() {
super.viewDidLoad()
for button in buttons{
button?.setImage(uncheckBoxImage, for: .normal)
//every button I set uncheckBoxImage first.
}
}
#IBAction func btnAction(_ sender: UIButton) { //connect every button
if sender.imageView == checkBoxImage {
sender.setImage(uncheckBoxImage, for: .normal)
}else {
sender.setImage(checkBoxImage, for: .normal)
}
}
I also tried below, but it can't process multiple button
var cube:Bool = false
#IBAction func btnAction(_ sender: Any) {
cube = !cube
if cube {
sender.setImage(checkBoxImage, for: .normal)
} else {
sender.setImage(uncheckBoxImage, for: .normal)
}
}
How should I fix these situation ?
Like it has some questions for you
And you just need to click to be check or click again to be uncheck
The trick is to use the selectedState for buttons.
Set both images for .normal and .selected state:
button?.setImage(uncheckBoxImage, for: .normal)
button?.setImage(checkBoxImage, for: .selected)
then, in IBAction:
#IBAction func btnAction(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
...
}
You should implement different button's state, it will change image automatically
var uncheckBoxImage = UIImage(named: "uncheckBox")
var checkBoxImage = UIImage(named: "checkBox")
override func viewDidLoad() {
super.viewDidLoad()
for button in buttons{
button?.setImage(uncheckBoxImage, for: .normal)
button?.setImage(checkBoxImage, for: .selected)
}
}
#IBAction func btnAction(_ sender: UIButton) { //connect every button
sender.isSelected = !sender.isSelected
}
Hi Please try with a tintcolor if that works
var uncheckBoxImage = UIImage(named: "uncheckBox")
var checkBoxImage = UIImage(named: "checkBox")
override func viewDidLoad() {
super.viewDidLoad()
for button in buttons{
button?.setImage(uncheckBoxImage, for: .normal)
button?.tintColor = UIColor.clear
}
}
#IBAction func btnAction(_ sender: UIButton) {
if sender.tintColor == UIColor.clear {
sender.setImage(checkBoxImage, for: .normal)
sender.tintColor = UIColor.green
}else if sender.tintColor == UIColor.green {
sender.setImage(uncheckBoxImage, for: .normal)
sender.tintColor = UIColor.clear
}
}
For just two states, abstracting "normal" and "selected", it's better to use the above answers, but if you need to handle multiple cases, you can use <#UIButton#>.currentImage!.isEqual(to: foo), to compare images and use only .normal state.
This is an example:
#IBAction func btnAction(_ sender: UIButton) {
if sender.currentImage != nil && sender.currentImage!.isEqual(UIImage(named: "a")) {
sender.setImage(UIImage(named: "b"), for: .normal)
} else {
sender.setImage(UIImage(named: "a"), for: .normal)
}
}
If you want multiple selection then you can use.
override func viewDidLoad() {
super.viewDidLoad()
for button in buttons {
button.setImage(UIImage(named: "uncheckBox"), for: .normal)
button.setImage(UIImage(named: "checkBox"), for: .selected)
button.tintColor = .clear
}
}
#IBAction func btnAction(_ sender: UIButton) {
// toggle automatic changes selection state
sender.isSelected.toggle()
}

Swift UIRefreshControl to UICollectionView inside UIScrollView

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)
}

Swift 3 - Floating Button over UICollectionView

I created a floating button by this first answer. It works but when the UICollectionViewlaunched, the floating button still square and became circle after all datas appear (after loadAPI finished running).
Here's my code:
override func viewDidLoad() {
super.viewDidLoad()
self.roundButton = UIButton(type: .custom)
self.roundButton.setTitleColor(UIColor.orange, for: .normal)
self.roundButton.addTarget(self, action: #selector(self.ButtonClick(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(self.roundButton)
self.loadAPI(Page: 1)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
roundButton.layer.cornerRadius = roundButton.layer.frame.size.width/2
roundButton.backgroundColor = green
roundButton.clipsToBounds = true
roundButton.setImage(UIImage(named:"ic_add_white_2x"), for: .normal)
roundButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
roundButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
roundButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -20),
roundButton.widthAnchor.constraint(equalToConstant: 60),
roundButton.heightAnchor.constraint(equalToConstant: 60)
])
}
#IBAction func ButtonClick(_ sender: UIButton){
//print("clicked")
}
I need the button being a circle since the UICollectionView first appears. Can somebody help me please? Thanks!
// update this code
override func viewDidLoad() {
super.viewDidLoad()
self.roundButton = UIButton(type: .custom)
self.roundButton.setTitleColor(UIColor.orange, for: .normal)
self.roundButton.layer.cornerRadius = roundButton.layer.frame.size.width/2
self.roundButton.addTarget(self, action: #selector(self.ButtonClick(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(self.roundButton)
self.loadAPI(Page: 1)
}