I'm looking to implement a Pull-to-refresh, and I'm seeing that the pull-to-refresh action isn't smooth; it makes the Content View jump around the screen, like so:
https://imgur.com/a/6oWPizP
I have the following constraints:
My ViewController looks like this:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textLabel: UILabel!
#IBOutlet weak var scrollView: UIScrollView!
var refreshControl: UIRefreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.addTarget(self, action: #selector(reloadData), for: UIControl.Event.valueChanged)
refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
scrollView.refreshControl = refreshControl
}
#objc func reloadData() {
textLabel.text = "SURPRISE"
refreshControl.endRefreshing()
}
}
Related
ViewController has a label and a button for go to secondVC. And secondVC has a text field , label , button to write user-entered text in the text field on the label. When user press the back button of navigation bar, I want transit secondVC's label's text to ViewController's label's text. How can I do this ?
ViewController's code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goVC2(_ sender: Any) {
performSegue(withIdentifier: "toVC2", sender: nil)
}
}
secondVC's code:
import UIKit
class secondVC: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var resultLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveClicked(_ sender: Any) {
resultLabel.text = nameField.text
}
}
I tried prepare for segue in ViewController and but it was error. And I searched on google for this but I couldn't find solution.
Use protocol for pass data from second VC to first VC. you need to create your own delegate method and call on dismiss with pass data, check below code :----
ViewController's code:
import UIKit
class ViewController: UIViewController, Delegate {
#IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func save(str : String) {
self.nameLabel.text = str
}
#IBAction func goVC2(_ sender: Any) {
if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "secondVC") as? secondVC {
vc.delegate = self
self.present(vc, animated: true, completion: nil)
}
}
}
secondVC's code:
import UIKit
protocol Delegate : AnyObject {
func save(str : String)
}
class secondVC: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var resultLabel: UILabel!
weak var delegate : Delegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveClicked(_ sender: Any) {
if let del = self.delegate {
let txt = nameField.text
del.save(str: txt)
self.dismiss(animated: true, completion: nil)
}
}
}
I have a tableviewController and it uses a custom cell class for it's data.
The custom cell has a Mapview and a button.
I was able to connect the button to an event like this
class MyTVCellTableViewCell: UITableViewCell {
var placeButtonAction : (() -> ())?
var mapViewAction : (() -> ())?
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var placeButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.deleteButton.addTarget(self, action: #selector(placeButtonSelected(_:)),for: .touchUpInside)
// This is where it fails as it does not recognize touchUpInside
self.mapView.addTarget(self, action: #selector(mapViewSelected()),for: .touchUpInside)
}
#IBAction func placeButtonSelected(_ sender: UIButton) {
placeButtonAction?()
}
func mapViewSelected(){
mapViewAction?()
}
Any events that I can insert in this line?
self.mapView.addTarget(self, action: #selector(mapViewSelected()),for: .touchUpInside)
If you want to see the tap position over the map as a geographic location, the following should do the job.
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(mapTapped))
tapGesture.numberOfTapsRequired = 1
mapView.addGestureRecognizer(tapGesture)
mapView.delegate = self
}
#objc func mapTapped(_ sender: UITapGestureRecognizer) {
let tapPoint = sender.location(in: mapView)
let geoPoint = mapView.convert(tapPoint, toCoordinateFrom: mapView)
print(geoPoint)
}
}
I have a custom cell class with two buttons and one label defined in its own class. Am using protocol-delegates to update the value of the label when the button is pressed. But am not able to figure out how to update the UITableView.
protocol customCellDelegate: class {
func didTapDecrementBtn(_ sender: AllCountersTableViewCell)
func didTapIncrementBtn(_ sender: AllCountersTableViewCell)
func updateTableViewCell(_ sender: AllCountersTableViewCell)
}
class AllCountersTableViewCell: UITableViewCell {
#IBOutlet weak var counterValueLbl: UILabel!
#IBOutlet weak var counterNameLbl: UILabel!
#IBOutlet weak var counterResetDateLbl: UILabel!
#IBOutlet weak var counterDecrementBtn: UIButton!
#IBOutlet weak var counterIncrementBtn: UIButton!
weak var delegate: customCellDelegate?
#IBAction func decrementBtnPressed(_ sender: UIButton) {
delegate?.didTapDecrementBtn(self)
delegate?.updateTableViewCell(self)
}
#IBAction func incrementBtnPressed(_ sender: UIButton) {
delegate?.didTapIncrementBtn(self)
delegate?.updateTableViewCell(self)
}
In my ViewController, I have provided the delegate. But reloadData() is not working, so although sender.counterLbl.value is changing its not reflecting on the view.
extension AllCountersVC: customCellDelegate {
func didTapIncrementBtn(_ sender: AllCountersTableViewCell) {
guard let tappedCellIndexPath = tableView.indexPath(for: sender) else {return}
let rowNoOfCustomCell = tappedCellIndexPath[1]
let newValue = String(allCounter[rowNoOfCustomCell].incrementCounterValue(by: allCounter[rowNoOfCustomCell].counterIncrementValue))
sender.counterValueLbl.text = newValue
}
func updateTableViewCell(_ sender: AllCountersTableViewCell) {
allCountersTableView.reloadData()
}
In cellForRow you must set cell.delegate = self for this logic to start working. Its not enough just to make you controller confroms to your custom cell delegate protocol. From your post I assume delegate is always nil in the cell, that is why it does not work.
I'm trying to customize Navigation bar and get it bigger with vertical alignment. Here is my code:
#IBOutlet weak var topNavTitleLabel: UILabel!
#IBOutlet weak var topNavStackView: UIStackView!
#IBOutlet weak var leftNavHomeButton: UIBarButtonItem!
#IBOutlet weak var rightNavSearchButton: UIBarButtonItem!
var rightNavSearchButton_: UIBarButtonItem?
#IBAction func searchAction(sender: UIButton) {
topNavStackView.hidden = true
topNavStackView.hidden = false
rightNavSearchButton_ = rightNavSearchButton
navigationItem.rightBarButtonItem = nil
}
#IBAction func performSearch(sender: UIButton) {
topNavStackView.hidden = false
topNavStackView.hidden = true
navigationItem.rightBarButtonItem = rightNavSearchButton_
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if let navConBar = self.navigationController?.navigationBar {
navConBar.bounds = CGRectMake(0, 0, view.bounds.width, 100)
navConBar.setTitleVerticalPositionAdjustment(-10.0, forBarMetrics: .Default)
let offset = UIOffset(horizontal: 0, vertical: -10)
navigationItem.rightBarButtonItem?.setTitlePositionAdjustment(offset, forBarMetrics: .Default)
navigationItem.leftBarButtonItem?.setTitlePositionAdjustment(offset, forBarMetrics: .Default)
}
}
When It appears it looks ok.
But When I click on right navigation bar button, left button goes to down.
Also when it turns back:
How can it be fixed?
Below is the code that I'm trying to use to have the view scroll only when the focused textField or UIButton is hidden by the keyboard:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var buttonToBottomConstraint: NSLayoutConstraint!
#IBOutlet weak var textFieldUsername: UITextField!
#IBOutlet weak var textFieldPassword: UITextField!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeShown:", name: UIKeyboardWillShowNotification, object: nil)
}
func textFieldDidBeginEditing(textField: UITextField) {
}
func textFieldShouldReturn(textField: UITextField) -> Bool {textField.resignFirstResponder()
return true
}
func keyboardWillBeHidden(notification: NSNotification){
self.scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}
func keyboardWillBeShown(notification: NSNotification){
let userInfo = notification.userInfo!
if let kbsize = userInfo[UIKeyboardFrameBeginUserInfoKey]?.CGRectValue().size{
self.scrollView .setContentOffset(CGPointMake(0, kbsize.or), animated: true)
}
}
}
Problem: The View scrolls even when the keyboard is not hiding anything.
View at Launch:
View Upon Tapping on a TextField:
Question: How do I check to see if the focused field is hidden by the keyboard, and ONLY if it is, push it above it?
Project: TextFieldScroll
EDIT
App works fine in Portrait mode, however, not in landscape mode. Also in landscape mode, when the Username textField keyboard is up and I tap the Password textField, it remains hidden behind the keyboard. I updated the project on Github and fixed the link. Thanks
Screen shot in landscape:
var currentTextField:UITextField?
#IBOutlet weak var textFieldUsername: UITextField!
#IBOutlet weak var textFieldPassword: UITextField!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad()
{
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeShown:", name: UIKeyboardWillShowNotification, object: nil)
}
func textFieldDidBeginEditing(textField: UITextField)
{
currentTextField=textField;
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func keyboardWillBeHidden(notification: NSNotification){
currentTextField=nil;
self.scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}
func keyboardWillBeShown(notification: NSNotification){
let userInfo = notification.userInfo!
if let kbsize = userInfo[UIKeyboardFrameBeginUserInfoKey]?.CGRectValue().size
{
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbsize.height, right: 0)
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenHeight = screenSize.height
let height:CGFloat=screenHeight-(kbsize.height)-(currentTextField!.frame.size.width)
if(currentTextField!.frame.origin.y>=height )
{
var scrollPoint: CGPoint = CGPointMake(0.0, currentTextField!.frame.origin.y - (kbsize.height));
self.scrollView .setContentOffset(scrollPoint, animated: true)
}
}
}
func textFieldDidEndEditing(textField: UITextField) {
currentTextField=nil;
}
I don't see you setting the scrollView's contentSize. Thus, the scrollView scrolls with the keyboard since it uses the screen's size.