UIScrollView not zooming: What am I missing? - swift

I can scroll, but not zoom. I've seen a lot of identical looking code while searching, but still there's no zoom.
The pinchGestureRecognizer is not nil.
viewForZoomingInScrollView(scrollView: UIScrollView) is not being called.
scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) reports scale = 1.0.
What am I missing here?
(We need to do this programmatically rather than in IB).
import UIKit
class ScrollViewController: UIViewController, UIScrollViewDelegate {
var scrollView: UIScrollView!
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView = UIImageView(image: UIImage(named: "image.png"))
scrollView = UIScrollView(frame: view.bounds)
scrollView.backgroundColor = UIColor.black
scrollView.contentSize = imageView.bounds.size
scrollView.contentOffset = CGPoint(x: 1000, y: 450)
scrollView.addSubview(imageView)
view.addSubview(scrollView)
scrollView.delegate = self
scrollView.minimumZoomScale = 0.1
scrollView.maximumZoomScale = 4.0
scrollView.zoomScale = 1.0
}
//delegate
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
}

Did you convert your codes from an older version of Swift? Because the delegate function for returning the view for zooming is now
func viewForZooming(in scrollView: UIScrollView) -> UIView?

Related

Card Slide Gallery in UIViewController

Is there a way to implement a card sliding gallery in a UIViewController? The gallery is not supposed to have images but buttons. I'm thinking the app "Bumble" for example when it comes to their subscription process. You can swipe through 2 cards to choose your subscription model. This has to be implemented in a UIViewController .. Any chance to get this done?
You can try using UICollectionView to emulate how bumble cardview works
make the scroll direction to horizontal and disable the scroll indicator
and then, add UICollectionViewDelegateFlowLayout protocol and use these two bad boys
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
}
what the two of them do is detect when the scroll gesture is decelerating and end of the scroll gesture. You can try to engineered the movement
here's an example how I implement it
private lazy var collectionView:UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
//layout.itemSize = CGSize(width: 330, height: 150)
layout.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 70, width: UIScreen.main.bounds.width, height: 150),collectionViewLayout: layout)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell2")
collectionView.showsHorizontalScrollIndicator = false
collectionView.backgroundColor = .clear
return collectionView
}()
delegate :
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.collectionView.scrollToNearestVisibleCollectionViewCell()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.collectionView.scrollToNearestVisibleCollectionViewCell()
}
}

How to Programmatically Scroll iOS WKWebView, swift 4

So my question is: After a website(any websites on the www) has been loaded up in my iOS webview app how to make the app Programmatically Scroll vertically to any of the contents thats out of view?
// ViewController.swift
// myWebView
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
#IBOutlet weak var myWebView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear( animated )
let urlString:String = "https://www.apple.com"
let url:URL = URL(string: urlString)!
let urlRequest:URLRequest = URLRequest(url: url)
myWebView.load(urlRequest)
}
func webViewDidFinishLoad(_ webView: WKWebView) {
let scrollPoint = CGPoint(x: 0, y: webView.scrollView.contentSize.height - webView.frame.size.height)
webView.scrollView.setContentOffset(scrollPoint, animated: true )
}
}
This will also account for the possible horizontal offset of the origin of the scrollView:
var scrollPoint = self.view.convert(CGPoint(x: 0, y: 0), to: webView.scrollView)
scrollPoint = CGPoint(x: scrollPoint.x, y: webView.scrollView.contentSize.height - webView.frame.size.height)
webView.scrollView.setContentOffset(scrollPoint, animated: true)
You can manipulate the Scroll View of the webview. Below there's an example to scroll to the bottom of the view:
let scrollPoint = CGPoint(x: 0, y: yourWebView.scrollView.contentSize.height - webView.frame.size.height)
webView.scrollView.setContentOffset(scrollPoint, animated: true)
If you want to get notify your wbeview reach to top or bottom use this extension, I made it long time ago for wkwebview. webview reach top or bottom

Custom Tab Bar Menu with horizontal swipe

Just a quick question regarding implementation.
I am trying to recreate this:
https://i.imgur.com/lFXKFXl.mp4
I am wondering if I have to do it from scratch using a UICollectionView, there's a built-in Xcode method, or there is a library online somewhere.
Note: I am not trying to create a tab bar menu at the bottom, but rather at the top underneath the navigation controller navbar with horizontal swipe features. Instagram also has this underneath the search tab.
Thank you!
You can animate your blue bar in following way
func scrollViewDidScroll(_ scrollView: UIScrollView) {
blueBarViewLeadingConstraint.constant = scrollView.contentOffset.x / (scrollView.bounds.width / (TabBarView.frame.size.width / numberOfTab))
}
You can use a UIScrollView and add child viewcontrollers to it. I made an extension to UIViewController that easily allows you to create a swipe view.
extension UIViewController {
public func addViewControllerToContainer(viewController: UIViewController, count: CGFloat = 0, container: UIScrollView, heightDecrease: CGFloat = 0, startIndex: CGFloat = 0) {
let multiplier: CGFloat = count
addChildViewController(viewController)
container.addSubview(viewController.view)
container.contentSize.width += viewController.view.frame.width
container.contentSize.height = viewController.view.frame.height - heightDecrease
container.frame = CGRect(x: viewController.view.frame.origin.x, y: viewController.view.frame.origin.y, width: viewController.view.frame.width, height: viewController.view.frame.height - heightDecrease)
container.frame.origin.y += heightDecrease
container.contentOffset.x = container.frame.width * startIndex
viewController.view.frame.size.width = container.frame.width
viewController.view.frame.size.height = container.frame.height
viewController.view.frame.size.height -= heightDecrease
viewController.view.frame.origin.x = container.frame.width * multiplier
}
public func addViewControllersToContainer(viewControllers: [UIViewController], container: UIScrollView, heightDecrease: CGFloat = 0, startIndex: CGFloat) {
var count: CGFloat = 0
for viewController in viewControllers {
addViewControllerToContainer(viewController: viewController, count: count, container: container, heightDecrease: heightDecrease, startIndex: startIndex)
count += 1
}
}
}
class MainSwipeViewController: UIViewController {
let viewControllers: [UIViewController] = [VC1, VC2, VC3] // view controllers swiped between
let startIndex: CGFloat = 0 // which viewController to begin at (0 means first)
let mainScrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.backgroundColor = .lightGray
scrollView.isPagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.bounces = false
scrollView.contentInsetAdjustmentBehavior = .never
scrollView.backgroundColor = UIColor.clear
return scrollView
}()
private func addViewControllers(_ vc: UIViewController, viewControllers: [UIViewController], startIndex: CGFloat = 0) {
view.addSubview(mainScrollView)
addViewControllersToContainer(viewControllers: viewControllers, container: mainScrollView, startIndex: startIndex)
}
override func viewDidLoad() {
super.viewDidLoad()
addViewControllers(self, viewControllers: viewControllers, startIndex: startIndex)
}
}
As for the tabbar menu, you can easily create that by implementing UIScrollViewDelegate in MainSwipeViewController
extension MainSwipeViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffset = scrollView.contentOffset.x / view.frame.width
}
}
contentOffset is the interval of your swipe and increases by one everytime you swipe. This will help you animate the blue bar in your menu.

Set initial ScrollView

I want to set "ViewController2" as initial page in the ScrollView but changing setContentOffset(CGPointMake(0,0), animated: false) sets the first page as initial, i tried modified it with different numbers but it just messed up the pages, any tips?
import UIKit
class ViewController: UIViewController {
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.bounces = false
scrollView.pagingEnabled = true
scrollView.setContentOffset(CGPointMake(0,0), animated: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidLayoutSubviews() {
initScrollView()
}
func initScrollView(){
let viewController1 = storyboard?.instantiateViewControllerWithIdentifier("ViewController1") as! ViewController1
viewController1.willMoveToParentViewController(self)
viewController1.view.frame = scrollView.bounds
let viewController2 = storyboard?.instantiateViewControllerWithIdentifier("ViewController2") as! ViewController2
viewController2.willMoveToParentViewController(self)
viewController2.view.frame.size = scrollView.frame.size
viewController2.view.frame.origin = CGPoint(x: view.frame.width, y: 0)
let viewController3 = storyboard?.instantiateViewControllerWithIdentifier("ViewController3") as! ViewController3
viewController3.willMoveToParentViewController(self)
viewController3.view.frame.size = scrollView.frame.size
viewController3.view.frame.origin = CGPoint(x: view.frame.width * 2, y: 0)
scrollView.contentSize = CGSize(width: 3 * scrollView.frame.width, height: scrollView.frame.height)
scrollView.addSubview(viewController3.view)
self.addChildViewController(viewController3)
viewController3.didMoveToParentViewController(self)
scrollView.addSubview(viewController2.view)
self.addChildViewController(viewController2)
viewController2.didMoveToParentViewController(self)
scrollView.addSubview(viewController1.view)
self.addChildViewController(viewController1)
viewController1.didMoveToParentViewController(self)
}}
Try to de-select the scroll view inset adjustment... in vc2:
By putting scrollView.setContentOffset(CGPointMake(375,0), animated: false) in viewDidlayoutSubViews it loads the next view, note that i am using iphone 4,7 inch screen so the width of a viewController is 375. change 375 to the width of your viewController, for example if you wanna load the last page first you do add 375 to 375 and so on..
override func viewDidLayoutSubviews() {
initScrollView()
scrollView.setContentOffset(CGPointMake(375,0), animated: false)
}

View does not animate

I have a view, which shall move up like a drawer from the bottom of the screen. But it does not do anything. It just sits there =)
Can anyone please tell me, why it is doing that?
This is my code:
import UIKit
class InfoPopUpVC: UIViewController {
var superView: UIView!
var labelText: String!
let textLabel = UILabel()
let height = CGFloat(80)
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.view.center.y = 50
})
}
override func viewDidLoad() {
super.viewDidLoad()
setupTextLabel()
view.frame = CGRectMake(0, superView.frame.maxY-height, superView.frame.width, height)
AnimationHelper.blurBackgroundForView(view)
view.backgroundColor = .greenColor()
}
func setupTextLabel(){
textLabel.text = labelText
textLabel.frame = CGRectMake(0, 0, view.frame.width, view.frame.height)
textLabel.numberOfLines = 3
textLabel.textAlignment = .Center
textLabel.frame.inset(dx: 10, dy: 8)
textLabel.sizeToFit()
textLabel.font = UIFont(name: "HelveticaNeue-Light", size: 17)
textLabel.textColor = .whiteColor()
view.addSubview(textLabel)
}
}
Try to put your code as follow inside viewDidAppear or viewWillAppear and with dispatch async. Otherwise your animation might not work.
override func viewDidAppear(animated: Bool) {
dispatch_async(dispatch_get_main_queue(), {
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.view.center.y = 50
})
})
}
You cannot animate a frame or similar property, if the UIViewis constrained using autolayout.
You have two options:
Get rid of autolayout and animate the frames Directory
Use autolayout and animate the constraints (e.g. via outlets)
See the following links for examples:
How do I animate constraint-changes
IOS: ANIMATING AUTOLAYOUT CONSTRAINTS