How to pass images to a NewViewController from ScrollView with Page Control in Swift - swift

I am trying to make the images clickable and pass them to a new view controller with more details. I am using UIScrollView with UIPageController inside my HomeViewController.
I was trying to research but couldn't find any specific examples. I am thinking maybe pass it with segue but I can't figure out how. Any ideas are welcome. Thanks in advance. This is my code:
class HomeViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var pageControl: UIPageControl!
#IBOutlet var topScrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
pageScrollView()
}
func pageScrollView() {
self.topScrollView.isUserInteractionEnabled = true
self.topScrollView.addGestureRecognizer(UITapGestureRecognizer())
self.topScrollView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 200)
let scrollViewWidth:CGFloat = self.topScrollView.frame.width
let scrollViewHeight:CGFloat = self.topScrollView.frame.height
let imgOne = UIImageView(frame: CGRect(x:0, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgOne.image = UIImage(named: "img1")
let imgTwo = UIImageView(frame: CGRect(x:scrollViewWidth, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgTwo.image = UIImage(named: "img2")
let imgThree = UIImageView(frame: CGRect(x:scrollViewWidth*2, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgThree.image = UIImage(named: "img3")
let imgFour = UIImageView(frame: CGRect(x:scrollViewWidth*3, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgFour.image = UIImage(named: "img4")
let imgFive = UIImageView(frame: CGRect(x:scrollViewWidth*4, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgFive.image = UIImage(named: "img5")
self.topScrollView.addSubview(imgOne)
self.topScrollView.addSubview(imgTwo)
self.topScrollView.addSubview(imgThree)
self.topScrollView.addSubview(imgFour)
self.topScrollView.addSubview(imgFive)
self.topScrollView.contentSize = CGSize(width:self.topScrollView.frame.width * 5, height:self.topScrollView.frame.height)
self.pageControl.currentPage = 0
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth:CGFloat = scrollView.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
// Change the indicator
self.pageControl.currentPage = Int(currentPage)
}
}

I figure it out. Hope it helps someone else. I added:
#objc var imgOne = UIImageView()
#objc var imgTwo = UIImageView()
#objc var imgThree = UIImageView()
#objc var imgFour = UIImageView()
#objc var imgFive = UIImageView()
#objc func imageTapped(_sender:UITapGestureRecognizer) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "DetailsMapsViewController") as! DetailsMapsViewController
vc.restaurantMaps = self.restaurantArray[_sender.view!.tag]
self.navigationController?.pushViewController(vc, animated: true)
}
imgOne.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(HomeViewController.imageTapped)))
imgTwo.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(HomeViewController.imageTapped)))
imgThree.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(HomeViewController.imageTapped)))
imgFour.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(HomeViewController.imageTapped)))
imgFive.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(HomeViewController.imageTapped)))
imgOne.tag = 0
imgTwo.tag = 1
imgThree.tag = 2
imgFour.tag = 3
imgFive.tag = 4

Related

How to present image in full screen in UIPageViewController?

I'm trying to present full images in UIPageViewController. Each image is in separate view controller. I set contentMode to scaleAspectFill. The problem is that when I scroll back, two images merge like this https://i.imgur.com/CSgJLWq.png. I also tried to give width to every image but nothing changes
private lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "onboarding-concert")
imageView.contentMode = .scaleAspectFill
//imageView.frame.size.width = 400
return imageView
}()
private func setUI() {
view.addSubview(imageView)
imageView.snp.makeConstraints { make in
make.left.equalToSuperview()
make.right.equalToSuperview()
make.top.equalToSuperview()
make.bottom.equalToSuperview()
}
view.addSubview(label)
label.snp.makeConstraints { make in
make.top.equalToSuperview().inset(90)
make.left.equalToSuperview().inset(40)
}
}
UIPageViewController code
class OnboardingViewController: UIPageViewController {
var pages = [UIViewController]()
let pageControl = UIPageControl()
let initialPage = 0
var pageControlBottomAnchor: NSLayoutConstraint?
override func viewDidLoad() {
setup()
style()
layout()
}
func setup() {
dataSource = self
delegate = self
pageControl.addTarget(self, action: #selector(pageControlTapped(_:)), for: .valueChanged)
let page1 = FirstPageViewController()
let page2 = SecondPageViewController()
let page3 = ThirdPageViewController()
pages.append(page1)
pages.append(page2)
pages.append(page3)
setViewControllers([pages[initialPage]], direction: .forward, animated: true, completion: nil)
}
func style() {
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.currentPageIndicatorTintColor = .black
pageControl.pageIndicatorTintColor = .systemGray2
pageControl.numberOfPages = pages.count
pageControl.currentPage = initialPage
pageControl.isUserInteractionEnabled = false
}
func layout() {
view.addSubview(pageControl)
pageControl.snp.makeConstraints { make in
make.width.equalToSuperview()
make.height.equalTo(20)
make.centerX.equalToSuperview()
}
pageControlBottomAnchor = view.bottomAnchor.constraint(equalToSystemSpacingBelow: pageControl.bottomAnchor, multiplier: 2)
pageControlBottomAnchor?.isActive = true
}
#objc func pageControlTapped(_ sender: UIPageControl) {
setViewControllers([pages[sender.currentPage]], direction: .forward, animated: true, completion: nil)
}
}

Button action in CollectionView cell swift

I have a button in my CollectionViewCell and I added an action to the button but the action does not get triggered. I am currently using the cell independently.
class BalanceCell: UICollectionViewCell {
lazy var toggleBtn: ToggleButton = {
let view = ToggleButton()
view.isUserInteractionEnabled = true
view.addTarget(self, action: #selector(onTapped), for: .touchUpInside)
return view
}()
lazy var titleLabel: LabelX = {
let view = LabelX()
view.text = "My Available Balance"
view.font = .systemFont(ofSize: 16, weight: .regular)
return view
}()
lazy var amountLabel: TextFieldX = {
let view = TextFieldX()
view.isSecureTextEntry = true
view.text = "N000,000.00"
view.textAlignment = .center
view.font = .systemFont(ofSize: 26, weight: .medium)
return view
}()
private lazy var stackView: StackViewX = {
let view = StackViewX(arrangedSubviews: [titleLabel, amountLabel])
view.alignment = .center
view.axis = .vertical
view.distribution = .fillProportionally
view.spacing = 4
return view
}()
lazy var bgImageView: ImageViewX = {
let view = ImageViewX()
view.backgroundColor = R.color.roundEdgeButtonBgColor()
return view
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func layoutSubviews() {
super.layoutSubviews()
setupViewHierarchy()
setupConstraints()
setupProperties()
translatesAutoresizingMaskIntoConstraints = false
}
func setupViewHierarchy() {
addSubview(bgImageView)
bgImageView.addSubviews([stackView, toggleBtn])
}
func setupConstraints() {
bgImageView.fillToSuperview()
stackView.centerInSuperview()
toggleBtn.anchor(verticalY: bgImageView.centerYAnchor, horizontalX: nil, paddingX: 0, paddingY: 0, width: 24, height: 24, enableInsets: false)
toggleBtn.rightAnchor.constraint(equalTo: stackView.leftAnchor, constant: -18).isActive = true
}
func setupProperties() {
bgImageView.backgroundColor = .red
bgImageView.layer.cornerRadius = 15
layer.cornerRadius = 15
}
func setup(with title: String, amount: String, bgImageViewColor: UIColor) {
titleLabel.text = title
amountLabel.text = amount
bgImageView.backgroundColor = bgImageViewColor
}
#objc private func onTapped() {
self.setSecureMode(self.toggleBtn.isSecure)
}
private func setSecureMode(_ secure: Bool) {
amountLabel.isSecureTextEntry = secure
let tempText = amountLabel.text
amountLabel.text = tempText
}
}
This is the way I use it.
lazy var balacnceView: BalanceCell = {
let view = BalanceCell()
return view
}()
ANy help as to why the Togelbutton is not getting called is appritiatedswift
The default value of isUserInteractionEnabled property is true in UIButton. You do not need to set this property to true.
However, the default value of isUserInteractionEnabled property is false in UIImageView. If you want to enable action in UIImageView (or in subviews of UIImageView), then set isUserInteractionEnabled to true.
In your code, you have put all subviews inside bgImageView. Just add this line of code:
bgImageView.isUserInteractionEnabled = true

UITapGestureRecognizer for UILabel inside of a StackView

I have a Stack View with two labels, one of which once tapped, suppose to lead to another view.
Here the code of my UIView subclass where labels and a StackView are setup:
import UIKit
import SnapKit
class WelcomeView: UIView {
weak var coordinator: MainCoordinator?
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "backGroundImage")
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
return imageView
}()
private let questionLabel: UILabel = {
let questionLabel = UILabel()
questionLabel.text = "Don't have an Account?"
questionLabel.font = UIFont(name: "Avenir Next Regular", size: 17)
questionLabel.textColor = .black
return questionLabel
}()
private let signUpLabel: UILabel = {
let signUpLabel = UILabel()
let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.signUpTapped(tapGesture:)))
signUpLabel.text = "Sign Up"
signUpLabel.font = UIFont(name: "Avenir Next Regular", size: 17)
signUpLabel.textColor = .black
signUpLabel.highlightedTextColor = .link
signUpLabel.isHighlighted = true
signUpLabel.isUserInteractionEnabled = true
signUpLabel.addGestureRecognizer(tap)
return signUpLabel
}()
lazy var signUpstackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [questionLabel, signUpLabel])
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fill
stackView.spacing = 8
stackView.isUserInteractionEnabled = true
return stackView
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
addSubViews()
}
func addSubViews() {
self.backgroundColor = .white
self.addSubview(imageView)
self.addSubview(btnSignIn)
self.addSubview(signUpstackView)
setConstraints()
}
func setConstraints() {
imageView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
btnSignIn.snp.makeConstraints { (make) in
make.height.equalTo(60)
make.bottomMargin.equalTo(-50)
make.leftMargin.equalTo(28)
make.rightMargin.equalTo(-28)
}
signUpstackView.snp.makeConstraints { (make) in
make.height.equalTo(24)
make.centerX.equalTo(self)
make.top.equalTo(btnSignIn).offset(70)
}
}
}
I added UITapGestureRecognizer in signUpLabel.
And here is the code from my ViewController containing my IBAction function signUpTapped which is specified in UITapGestureRecognizer:
class ViewController: UIViewController {
var welcomeView = WelcomeView()
override func loadView() {
view = welcomeView
}
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func signUpTapped(tapGesture:UITapGestureRecognizer) {
print("Tapped")
}
}
For some reason nothing is happened when I try to click on my SignUp Label. Is this an issue because my UILabel is inside of a StackView?
You need
Sol 1
let tap = UITapGestureRecognizer(target: self, action: #selector(self.signUpTapped(tapGesture:)))
then inside the view class
weak var delegate:ViewController?
#objc func signUpTapped(tapGesture:UITapGestureRecognizer) {
print("Tapped")
delegate?.tapped()
}
var welcomeView = WelcomeView()
override func loadView() {
welcomeView.delegate = self
view = welcomeView
}
func tapped(){}
Sol 2
weak var delegate:ViewController?
init(frame: CGRect,delegate:ViewController) {
super.init(frame: frame)
self.delegate = delegate
addSubViews()
}
With
let tap = delegate(target:delegate!, action: #selector(delegate!.signUpTapped(tapGesture:)))
and inside the vc
#objc func signUpTapped(tapGesture:UITapGestureRecognizer) {
print("Tapped")
}

use tag to combine #objc func methods

My code declares 2 different #objc func methods using UIPan gestureRecongnizzer. I would think there would be a way to use just 1 objc func method using a tag. All the function currently does is move the imageview around. I dont know if tag is the best way and I am open to other solutions I just want 1 func. Specifically look at pgGestureMethod and sgGestureMethod.
var pg = UIImageView()
var pgGesture = UIPanGestureRecognizer()
var pgCon = [NSLayoutConstraint]()
var sg = UIImageView()
var sgGesture = UIPanGestureRecognizer()
var sgCon = [NSLayoutConstraint]()
override func viewDidLoad() {
super.viewDidLoad()
[pg,sg].forEach({
$0.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview($0)
$0.isUserInteractionEnabled = true
})
pgGesture = UIPanGestureRecognizer(target: self, action: #selector(ViewController.pgGestureMethod(_:)))
pg.addGestureRecognizer(pgGesture)
sgGesture = UIPanGestureRecognizer(target: self, action: #selector(ViewController.sgGestureMethod(_:)))
sg.addGestureRecognizer(sgGesture)
}
#objc func pgGestureMethod(_ sender: UIPanGestureRecognizer){
self.view.bringSubviewToFront(pg)
let tranistioon = sender.translation(in: self.view)
pg.center = CGPoint(x: pg.center.x + tranistioon.x, y: pg.center.y + tranistioon.y)
sender.setTranslation(CGPoint.zero,in: self.view)
}
#objc func sgGestureMethod(_ sender: UIPanGestureRecognizer){
let tranistioon = sender.translation(in: self.view)
sg.center = CGPoint(x: sg.center.x + tranistioon.x, y: sg.center.y + tranistioon.y)
sender.setTranslation(CGPoint.zero,in: self.view)
}
Gesture recognisers have a view property that refers to the view to which they are added, so you don't even need a tag!
Just use one single action method like this:
#objc func pgGestureMethod(_ sender: UIPanGestureRecognizer){
// I replaced every "pg" with "sender.view!"
self.view.bringSubviewToFront(sender.view!)
let tranistioon = sender.translation(in: self.view)
sender.view!.center = CGPoint(x: sender.view!.center.x + tranistioon.x, y: sender.view!.center.y + tranistioon.y)
sender.setTranslation(CGPoint.zero,in: self.view)
}
If not writing self.view.bringSubviewToFront(sg) is actually intentional, you can simply check sender.view!:
#objc func pgGestureMethod(_ sender: UIPanGestureRecognizer){
if sender.view == pg {
self.view.bringSubviewToFront(pg)
}
let tranistioon = sender.translation(in: self.view)
sender.view!.center = CGPoint(x: sender.view!.center.x + tranistioon.x, y: sender.view!.center.y + tranistioon.y)
sender.setTranslation(CGPoint.zero,in: self.view)
}
welcome to the Stackoverflow.
So in your case, you can understand which gesture was called from parameter in gesture function.
class SomeViewController: UIViewController {
var pg = UIImageView()
var pgGesture = UIPanGestureRecognizer()
var pgCon = [NSLayoutConstraint]()
var sg = UIImageView()
var sgGesture = UIPanGestureRecognizer()
var sgCon = [NSLayoutConstraint]()
override func viewDidLoad() {
super.viewDidLoad()
[pg,sg].forEach {[unowned self] in
$0.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview($0)
$0.isUserInteractionEnabled = true
}
pgGesture = UIPanGestureRecognizer(target: self, action: #selector(gestureDidRecognize(_:)))
pg.addGestureRecognizer(pgGesture)
sgGesture = UIPanGestureRecognizer(target: self, action: #selector(gestureDidRecognize(_:)))
sg.addGestureRecognizer(sgGesture)
}
}
#objc private extension SomeViewController {
func gestureDidRecognize(_ gesture: UIPanGestureRecognizer){
guard let gestureView = gesture.view else { return }
let transition = gesture.translation(in: view)
switch gesture {
case pgGesture:
view.bringSubviewToFront(pg)
default: break
}
gestureView.center = CGPoint(
x: gestureView.center.x + transition.x,
y: gestureView.center.y + transition.y)
gesture.setTranslation(.zero, in: view)
}
}

UIVisualEffectView creating unwanted shadow while presenting new view

In my custom presentation transition I've created a new view controller which will pre presented on top of the current active view controller (see screenshot). Somehow there's a shadow behind the blue view controller and I have no idea where it's coming from. Is there a way to stop getting that shadow?
The project is completely empty and has only 2 empty view controllers.
This is the code I'm using:
class ViewController: UIViewController {
let transitionDelegate = TransitionManager()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellowColor()
let button = UIButton(type: .System)
button.frame = CGRectMake(10, 10, 50, 50)
button.addTarget(self, action: "test:", forControlEvents: .TouchUpInside)
button.backgroundColor = UIColor.redColor()
view.addSubview(button)
}
func test(sender: UIButton) {
let destination = UIViewController()
destination.view.backgroundColor = .blueColor()
destination.transitioningDelegate = transitionDelegate
destination.modalPresentationStyle = .Custom
presentViewController(destination, animated: true, completion: nil)
}
}
The code for presenting the view:
class PresentingTransition: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.3
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let presented = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let container = transitionContext.containerView()!
let durations = transitionDuration(transitionContext)
presented.view.alpha = 0
container.addSubview(presented.view)
UIView.animateWithDuration(durations, animations: { presented.view.alpha = 1 }) { transitionContext.completeTransition($0) }
}
}
The code for handling the presenting view controller:
class PresentationController: UIPresentationController {
var background: UIView!
override init(presentedViewController: UIViewController, presentingViewController: UIViewController) {
super.init(presentedViewController: presentedViewController, presentingViewController: presentingViewController)
prepareBackground()
}
func prepareBackground() {
self.background = UIView(frame: presentingViewController.view.bounds)
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
blur.frame = background.bounds
blur.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
background.addSubview(blur)
let tapRecognizer = UITapGestureRecognizer(target: self, action: "backgroundTapped:")
background.addGestureRecognizer(tapRecognizer)
}
func backgroundTapped(tapRecognizer: UITapGestureRecognizer) {
presentingViewController.dismissViewControllerAnimated(true, completion: nil)
}
override func presentationTransitionWillBegin() {
let container = containerView!
background.frame = container.bounds
background.alpha = 0.0
container.insertSubview(background, atIndex: 0)
presentedViewController.transitionCoordinator()?.animateAlongsideTransition({ _ in self.background.alpha = 1.0 }, completion: nil)
}
override func dismissalTransitionWillBegin() {
presentedViewController.transitionCoordinator()?.animateAlongsideTransition({ _ in self.background.alpha = 0.0 }, completion: nil)
}
override func frameOfPresentedViewInContainerView() -> CGRect {
return containerView!.bounds.insetBy(dx: 100, dy: 100)
}
override func containerViewWillLayoutSubviews() {
background.frame = containerView!.bounds
presentedView()!.frame = frameOfPresentedViewInContainerView()
}
}