UIScrollView didn't scrolling? - ios

I'm creating a UIScrollView from code.The only problem is the scrolling is not working go through lot's of the post but didn't find anything.
Here is my code Any help greatly Appreciated.
class ShopDetailviewController : UIViewController {
var MainScrollView : UIScrollView?
let viewForScrollview : UIView = {
let view = UIView()
view.backgroundColor = UIColor.darkGray
return view
}()
let shopNameandAddresView : UIView = {
let view = UIView()
view.backgroundColor = UIColor.black
return view
}()
let timePaymentDetail : UIView = {
let view = UIView()
view.backgroundColor = UIColor.blue
return view
}()
let shopImage : UIImageView = {
let shopeImage = UIImageView()
shopeImage.backgroundColor = UIColor.green
return shopeImage
}()
let ratingStarLable : UILabel = {
let ratingStratLable = UILabel()
ratingStratLable.backgroundColor = UIColor.red
ratingStratLable.text = "3.5"
return ratingStratLable
}()
let shopName : UILabel = {
let shopName = UILabel()
shopName.backgroundColor = UIColor.gray
shopName.text = "Kimling"
return shopName
}()
let shopLocation : UILabel = {
let shopLocation = UILabel()
shopLocation.backgroundColor = UIColor.white
shopLocation.text = "Kondhwa"
return shopLocation
}()
let seprater : UIView = {
let seprater = UIView()
seprater.backgroundColor = UIColor.white
return seprater
}()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
navigationController?.navigationBar.tintColor = .white
view.backgroundColor = UIColor.white
}
override func viewDidLoad() {
super.viewDidLoad()
MainScrollView = UIScrollView()
MainScrollView?.isScrollEnabled = true
MainScrollView?.indicatorStyle = .default
MainScrollView?.contentSize = CGSize(width:self.view.bounds.width, height: 8000)
MainScrollView?.backgroundColor = UIColor.purple
setupViews()
}
func setupViews(){
view.addSubview(MainScrollView!)
MainScrollView?.addSubview(viewForScrollview)
viewForScrollview.addSubview(shopImage)
viewForScrollview.addSubview(shopNameandAddresView)
viewForScrollview.addSubview(timePaymentDetail)
addConstraintsWithFormat("H:|-0-[v0(414)]-0-|", views: MainScrollView!)
addConstraintsWithFormat("V:|-0-[v0(8000)]", views: MainScrollView!)
addConstraintsWithFormat("H:|-0-[v0(414)]-0-|", views: viewForScrollview)
addConstraintsWithFormat("V:|-0-[v0(8000)]", views: viewForScrollview)
addConstraintsWithFormat("V:|-0-[v0(1000)]-0-[v1(1000)]", views: shopImage,shopNameandAddresView)
addConstraintsWithFormat("H:|-0-[v0]-0-|", views: shopImage)
addConstraintsWithFormat("H:|-0-[v0]-0-|", views: shopNameandAddresView)
}
}

Use as this
override func viewDidLayoutSubviews()
{
MainScrollView?.contentSize = CGSize(width:self.view.bounds.width, height: 8000)
}

It seems like the in viewDidLoad layout is not finished so the scrollView wont scroll because it has no proper contentSize try setting the contentSize in ViewWillAppear as
MainScrollView?.contentSize = CGSize(width:self.view.bounds.width, height: 8000)

Related

How to pass data forward between View Controllers - Swift

Hi I would like to know why every-time i ask for the emailCatched value in the second VC, I always get nil. Isn't how you pass data forward? Sorry if it's very basic.
I wrote the same code for passing the password from VC2 to VC3 and it works, it's weird. Thanks
First VC :
class EmailAddressViewController: UIViewController {
let emailField: UITextField = {
let emailField = UITextField()
return emailField
}()
private let continueButton: UIButton = {
let button = UIButton()
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
// SubViews
view.backgroundColor = .white
view.frame = view.bounds
view.addSubview(emailField)
view.addSubview(continueButton)
// I omitted the frames
continueButton.addTarget(self,
action: #selector(continueButtonTapped),
for: .touchUpInside)
}
#objc private func continueButtonTapped() {
let email = emailField.text,
let vc = PasswordViewController()
vc.emailCatched = email
self.present(PasswordViewController(), animated: true)
}
}
Second VC (PasswordViewController) :
class PasswordViewController: UIViewController {
private let passwordField: UITextField = {
let passwordField = UITextField()
passwordField.autocapitalizationType = .none
passwordField.autocorrectionType = .no
passwordField.returnKeyType = .next
passwordField.layer.cornerRadius = 10
passwordField.layer.borderWidth = 1
passwordField.layer.borderColor = UIColor.darkGray.cgColor
passwordField.placeholder = "Mot de passe"
passwordField.textAlignment = .center
passwordField.backgroundColor = .white
passwordField.translatesAutoresizingMaskIntoConstraints = false
passwordField.isSecureTextEntry = true
return passwordField
}()
private let continueButton: UIButton = {
let button = UIButton()
button.setTitle("Continuer", for: .normal)
button.backgroundColor = .systemGreen
button.setTitleColor(.white, for: .normal)
button.layer.cornerRadius = 25
button.layer.masksToBounds = true
button.titleLabel?.font = .systemFont(ofSize: 20, weight: .bold)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
var emailCatched: String?
// MARK: viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
print(emailCatched!) // returns error or nil
// SubViews
view.backgroundColor = .white
view.frame = view.bounds
view.addSubview(passwordField)
view.addSubview(continueButton)
continueButton.addTarget(self,
action: #selector(continueButtonTapped),
for: .touchUpInside)
}
// function bouton continuer
#objc private func continueButtonTapped() {
passwordField.resignFirstResponder()
guard let password = passwordField.text,
!password.isEmpty,
password.count >= 8 else {
alertInvalidPassword()
return
}
let vc = NamesViewController()
// vc.emailCatched = emailCatched!
vc.passwordCatched = password
HapticsManager.shared.vibrate(for: .success)
self.presenter(vc, animated: false, pushing: true, completion: nil)
}
}

UIScrollView for ViewController horizontally and vertically

My code tutorial works for scrolling horizontally with ScrollView.
I would like to make it with ViewControllers (instead of views) from my Storyboard.
And I would like to add a vertical ScrollView (To move from center to right or left = ScrollView horizontal, and to move from center to top or bottom (vertically).
Is that possible? Could someone give me a hint ?
Thanks
For information, this is my code :
import UIKit
class ViewController: UIViewController {
lazy var view0: UIView = {
let view = UIView()
view.backgroundColor = .systemTeal
let label = UILabel()
label.text = "Page 0"
label.textAlignment = .center
view.addSubview(label)
label.edgeTo(view: view)
return view
}()
lazy var view1: UIView = {
let view = UIView()
view.backgroundColor = .systemPink
let label = UILabel()
label.text = "Page 1"
label.textAlignment = .center
view.addSubview(label)
label.edgeTo(view: view)
return view
}()
lazy var view2: UIView = {
let view = UIView()
view.backgroundColor = .systemYellow
let label = UILabel()
label.text = "Page 2"
label.textAlignment = .center
view.addSubview(label)
label.edgeTo(view: view)
return view
}()
lazy var views = [view0, view1, view2]
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.showsHorizontalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(views.count), height: view.frame.height)
for i in 0..<views.count {
scrollView.addSubview(views[i])
views[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
}
scrollView.delegate = self
return scrollView
}()
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.numberOfPages = views.count
pageControl.currentPage = 0
pageControl.addTarget(self, action: #selector(pageControlTapHandler(sender:)), for: .touchUpInside)
return pageControl
}()
#objc
func pageControlTapHandler(sender: UIPageControl) {
scrollView.scrollTo(horizontalPage: sender.currentPage, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(scrollView)
scrollView.edgeTo(view: view)
view.addSubview(pageControl)
pageControl.pinTo(view)
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x / view.frame.width)
pageControl.currentPage = Int(pageIndex)
}

Scroll the ScrollView when tap a button Swift with ViewCode

I'm creating a ViewPager in Swift using ViewCode.
I need to create the following action: tap on the Next button (method: actionNextPressed() ), and scroll the scrollview to the next page (like a TapGesture scrolling to right or left).
Here is my Swift code, what I've tried until now, and the printscreen from the viewpager (at the moment)
PagerViewController.swift
import UIKit
import SnapKit
open class PagerViewController: UIViewController, UIPageViewControllerDelegate {
private lazy var dimmedView: UIView = {
let view = UIView()
view.backgroundColor = .black
view.alpha = maxDimmedAlpha
return view
}()
private lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 1, alpha: 0)
return view
}()
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.showsHorizontalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(pages.count), height: containerView.frame.height)
for i in 0..<pages.count {
var page = pages[i]
let dialog = PageViewController(
icon: page.icon,
titleText: page.title,
descriptionText: page.description,
titleActionButton: page.titleButton,
actionButton: page.actionButton
)!
scrollView.addSubview(dialog.view)
scrollView.subviews[i].frame = CGRect(
x: view.frame.width * CGFloat(i),
y: 0,
width: containerView.frame.width,
height: containerView.frame.height
)
}
scrollView.delegate = self
return scrollView
}()
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.currentPage = 0
pageControl.numberOfPages = pages.count
pageControl.addTarget(self, action: #selector(pageControlTapHandler(sender:)), for: .allEvents)
pageControl.isUserInteractionEnabled = false
pageControl.pageIndicatorTintColor = .systemGray
pageControl.currentPageIndicatorTintColor = .systemBlue
pageControl.backgroundColor = .white
return pageControl
}()
private lazy var directionsButtonsStackView: UIStackView = {
let view = UIStackView()
view.axis = .horizontal
view.distribution = .fillEqually
view.backgroundColor = .red
return view
}()
private lazy var buttonJump = UIButton()
private lazy var buttonBefore = UIButton()
private lazy var buttonNext = UIButton()
private var titleJumpButton: String! = ""
private let maxDimmedAlpha: CGFloat = 0.6
open var pages: Array<PageModel>!
private var currentPage: Int = 0
init?(listPages: Array<PageModel>, titleJumpButton: String) {
super.init(nibName: nil, bundle: nil)
self.pages = listPages
self.titleJumpButton = titleJumpButton
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc func pageControlTapHandler(sender: UIPageControl) {
scrollView.scrollTo(horizontalPage: sender.currentPage)
}
open override func viewDidLoad() {
super.viewDidLoad()
setupView()
addViewComponents()
setupConstraints()
}
private func setupView() {
self.buttonJump = PageButton(frame: .zero).build(
context: self,
title: titleJumpButton!,
selector: #selector(actionJumpPressed)
)
self.buttonBefore = PageButton(frame: .zero).build(
context: self,
title: "Before",
selector: #selector(actionBeforePressed)
)
self.buttonBefore.backgroundColor = .white
self.buttonNext = PageButton(frame: .zero).build(
context: self,
title: "Next",
selector: #selector(actionNextPressed)
)
self.buttonJump.setTitle(titleJumpButton, for: .normal)
}
private func addViewComponents() {
view.addSubview(dimmedView)
containerView.addSubview(scrollView)
containerView.addSubview(pageControl)
directionsButtonsStackView.addArrangedSubview(buttonBefore)
directionsButtonsStackView.addArrangedSubview(buttonNext)
containerView.addSubview(directionsButtonsStackView)
containerView.addSubview(buttonJump)
view.addSubview(containerView)
}
private func setupConstraints() {
dimmedView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.bottom.equalToSuperview()
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
}
containerView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(100)
make.bottom.equalToSuperview().inset(100)
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.centerX.equalToSuperview()
make.centerY.equalToSuperview()
make.margins.equalTo(20)
}
scrollView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.bottom.equalTo(pageControl.snp.top)
make.leading.equalTo(containerView.snp.leading)
make.trailing.equalTo(containerView.snp.trailing)
}
pageControl.snp.makeConstraints { make in
make.bottom.equalTo(directionsButtonsStackView.snp.top)
make.leading.equalTo(containerView.snp.leading).offset(20)
make.trailing.equalTo(containerView.snp.trailing).inset(20)
make.height.equalTo(30)
make.centerX.equalToSuperview()
}
directionsButtonsStackView.snp.makeConstraints { make in
make.bottom.equalTo(buttonJump.snp.top)
make.leading.equalTo(containerView.snp.leading).offset(20)
make.trailing.equalTo(containerView.snp.trailing).inset(20)
make.height.equalTo(60)
make.width.greaterThanOrEqualTo(0)
make.centerX.equalToSuperview()
}
buttonJump.snp.makeConstraints { make in
make.bottom.equalToSuperview().inset(10)
make.leading.equalTo(containerView).offset(20)
make.trailing.equalTo(containerView).inset(20)
make.centerX.equalToSuperview()
make.width.greaterThanOrEqualTo(0)
make.height.equalTo(50)
}
}
#objc private func actionJumpPressed() {
self.dismiss(animated: true, completion: nil)
}
#objc private func actionBeforePressed() {
if currentPage == 0 {
return
} else {
currentPage -= 1
pageControl.currentPage = currentPage
}
}
#objc private func actionNextPressed() {
if currentPage == pages.count {
return
} else {
currentPage += 1
pageControl.currentPage = currentPage
}
}
}
extension PagerViewController: UIScrollViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = Int(round(scrollView.contentOffset.x / view.frame.width))
pageControl.currentPage = pageIndex
currentPage = pageIndex
}
}
extension UIScrollView {
func scrollTo(horizontalPage: Int? = 0) {
var frame: CGRect = self.frame
frame.origin.x = frame.size.width * CGFloat(horizontalPage ?? 0)
self.scrollRectToVisible(frame, animated: true)
}
}
I had the same issue once with a collectionView. You have to turn off the .isPagingEnabled, scroll the scrollview where you want and turn it back on the paging.
func scrollTo(horizontalPage: Int? = 0) {
scrollView.isPagingEnabled = false
var frame: CGRect = self.frame
frame.origin.x = frame.size.width * CGFloat(horizontalPage ?? 0)
self.scrollRectToVisible(frame, animated: true)
scrollView.isPagingEnabled = true
}

Custom resuable UIActivityIndicatorView Class programmatically

I'm new in making views programmatically.
I'm trying to make UIActivityIndicatorView class to make it reusable for me.
This is the class I made:
class ActivityIndicator: UIActivityIndicatorView {
let indicator = UIActivityIndicatorView()
let indicatorContainer = UIView()
func setupIndicatorView() {
indicatorContainer.isHidden = false
indicator.isHidden = false
indicator.style = .large
indicator.color = .white
indicator.startAnimating()
indicator.hidesWhenStopped = true
indicator.translatesAutoresizingMaskIntoConstraints = false
indicatorContainer.backgroundColor = .darkGray
indicatorContainer.alpha = 0.7
indicatorContainer.layer.cornerRadius = 8.0
indicatorContainer.translatesAutoresizingMaskIntoConstraints = false
addSubview(indicatorContainer)
indicatorContainer.addSubview(indicator)
func setupIndicatorContainerConstraints() {
NSLayoutConstraint.activate([
indicatorContainer.centerXAnchor.constraint(equalTo: centerXAnchor),
indicatorContainer.centerYAnchor.constraint(equalTo: centerYAnchor),
indicatorContainer.widthAnchor.constraint(equalToConstant: frame.width / 5),
indicatorContainer.heightAnchor.constraint(equalToConstant: frame.width / 5)
])
}
func setupIndicatorViewConstraints() {
NSLayoutConstraint.activate([
indicator.centerXAnchor.constraint(equalTo: indicatorContainer.centerXAnchor),
indicator.centerYAnchor.constraint(equalTo: indicatorContainer.centerYAnchor)
])
}
setupIndicatorContainerConstraints()
setupIndicatorViewConstraints()
}
func hideIndicatorView() {
indicatorContainer.isHidden = true
indicator.stopAnimating()
indicator.isHidden = true
indicatorContainer.removeFromSuperview()
indicator.removeFromSuperview()
}
}
When I'm trying to make an instance from this class, it doesn't work in any other controller. Like this:
class SignInViewController: UIViewController {
let indicator = ActivityIndicator()
lazy var mainView: SignInView = {
let view = SignInView(delegate: self, frame: self.view.frame)
view.backgroundColor = .white
return view
}()
override func loadView() {
super.loadView()
view = mainView
}
func loginButtonTapped() {
indicator.setupIndicatorView()
}
}
I searched a lot to understand how to make it work but I haven't found a way.
You don't add it to vc's view
indicator.setupIndicatorView()
so consider
setupIndicatorView(_ view:UIView) {
.....
.....
// add it here
addSubview(indicatorContainer)
indicatorContainer.addSubview(indicator)
view.addSubview(self)
}

What error am I making when trying to pass data between ViewControllers using closures?

My main View Controller has an embedded UITabbarController in it. There are 2 subVCs: viewControllerONE & viewControllerTWO.
viewControllerONE displays a label showing the user's current score, and viewControllerTWO displays a button, pressing which should display an error window on viewControllerONE.
(For the sake of simplicity, the user has to manually navigate to viewControllerONE using the tab bar to see the error, ie, pressing the button on viewControllerTWO doesn't take you to viewControllerONE and then display the errorWindow.)
The error window is a simple UIView class.
From SO, I have learnt that the best way to pass data in swift isn't delegates but closures, as the former is more of an objective C design, and so I've used closures to pass data between view controllers.
So here is my viewControllerONE code:
class ViewControllerONE: UIViewController {
var score = 10
lazy var scoreLabel: UILabel = {
let label = UILabel()
label.text = String(score)
label.font = .systemFont(ofSize: 80)
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(scoreLabel)
let VC = ViewControllerTWO()
VC.callback = { [weak self ] in
let error = errorView()
self?.view.addSubview(error)
}
NSLayoutConstraint.activate([
scoreLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
scoreLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
}
}
and here is my viewControllerTWO code:
class ViewControllerTWO: UIViewController {
var callback: (() -> Void)?
let buttonTwo: UIButton = {
let button = UIButton()
button.setTitle("HIT THIS BUTTON!", for: .normal)
button.backgroundColor = .systemBlue
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(buttonTwoPressed), for: .touchUpInside)
button.layer.cornerRadius = 8
return button
}()
#objc func buttonTwoPressed() {
print("PRESSEDDDD")
callback?()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(buttonTwo)
NSLayoutConstraint.activate([
buttonTwo.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonTwo.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
And here is the error view:
class ErrorView: UIView {
fileprivate let dismissButton: UIButton = {
let button = UIButton()
button.setTitle("DISMISS!!!!", for: .normal)
button.backgroundColor = .systemBlue
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(dismissButtonPressed), for: .touchUpInside)
button.layer.cornerRadius = 12
return button
}()
#objc func dismissButtonPressed() {
self.errorGoAway()
}
fileprivate let errorViewBox: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .white
v.layer.cornerRadius = 24
return v
}()
#objc fileprivate func errorGoAway() {
self.alpha = 0
}
#objc fileprivate func errorShow() {
self.alpha = 1
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(errorGoAway)))
self.backgroundColor = UIColor.gray
self.backgroundColor?.withAlphaComponent(0.8)
self.frame = UIScreen.main.bounds
self.addSubview(errorViewBox)
errorViewBox.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
errorViewBox.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
errorViewBox.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.7).isActive = true
errorViewBox.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 0.45).isActive = true
errorViewBox.addSubview(dismissButton)
dismissButton.leadingAnchor.constraint(equalTo: errorViewBox.leadingAnchor).isActive = true
dismissButton.trailingAnchor.constraint(equalTo: errorViewBox.trailingAnchor).isActive = true
dismissButton.centerYAnchor.constraint(equalTo: errorViewBox.centerYAnchor).isActive = true
dismissButton.heightAnchor.constraint(equalTo: errorViewBox.heightAnchor, multiplier: 0.15).isActive = true
errorShow()
}
You need to get your controller from tabBarController instead of create new instance:
class ViewControllerONE: UIViewController {
var score = 10
lazy var scoreLabel: UILabel = {
let label = UILabel()
label.text = String(score)
label.font = .systemFont(ofSize: 80)
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.textColor = .blue
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(scoreLabel)
var VC: ViewControllerTWO?
let arrayOfVC = self.tabBarController?.viewControllers ?? []
for item in arrayOfVC {
if let secondVC = item as? ViewControllerTWO {
VC = secondVC
break
}
}
VC?.callback = { [weak self ] in
let error = ErrorView()
self?.view.addSubview(error)
}
NSLayoutConstraint.activate([
scoreLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
scoreLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
}
}

Resources