I am testing the swiping controller/gesture from Jake Spracher with his SnapchatSwipeView (https://github.com/jakespracher/Snapchat-Swipe-View )
I have setup a topVC,leftVC,rightVC and middleVC(the main VC).
I manage to capture when the user swipe from the center to the rightVC or to the left VC, with this :
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if delegate != nil && !delegate!.outerScrollViewShouldScroll() && !directionLockDisabled {
let newOffset = CGPoint(x: self.initialContentOffset.x, y: self.initialContentOffset.y)
self.scrollView!.setContentOffset(newOffset, animated: false)
}
if (scrollView.contentOffset) == CGPoint(x: 750.0, y: 0.0) {
print ("TEST OK LEFT!")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadRinkbox"), object: nil)
}
if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) {
print ("TEST OK LEFT!")
}
if (scrollView.contentOffset) == CGPoint(x: -750.0, y: 0.0) {
print ("TEST OK RIGHT")
}
if (scrollView.contentOffset) == CGPoint(x: 375, y: 0.0) {
print ("TEST OK!")
}
}
But I cannot manage to capture when the user swipe from the centerVC to the topVC, and from topVC to centerVC. I have tried a lot of things but I didn't manage to do it.
My code is for swift 4.
For clarity, I put here the two full swift files. Many, million thanks for those that can help me !
ContainerViewController.swift
//
// ContainerViewController.swift
// SnapchatSwipeView
//
// Created by Jake Spracher on 8/9/15.
// Copyright (c) 2015 Jake Spracher. All rights reserved.
//
import UIKit
import AVFoundation
protocol SnapContainerViewControllerDelegate {
// print "Snapcontainerview"
func outerScrollViewShouldScroll() -> Bool
}
class SnapContainerViewController: UIViewController, UIScrollViewDelegate {
var captureSession : AVCaptureSession!
private var current: UIViewController
// print "2"
var deeplink: DeeplinkType? {
didSet {
handleDeeplink()
}
}
init() {
current = SplashViewController()
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var topVc: UIViewController?
var leftVc: UIViewController!
var middleVc: UIViewController!
var rightVc: UIViewController!
var bottomVc: UIViewController?
var directionLockDisabled: Bool!
var horizontalViews = [UIViewController]()
var veritcalViews = [UIViewController]()
var initialContentOffset = CGPoint() // scrollView initial offset
var middleVertScrollVc: VerticalScrollViewController!
var scrollView: UIScrollView!
var delegate: SnapContainerViewControllerDelegate?
class func containerViewWith(_ leftVC: UIViewController,
middleVC: UIViewController,
rightVC: UIViewController,
topVC: UIViewController?=nil,
bottomVC: UIViewController?=nil,
directionLockDisabled: Bool?=false) -> SnapContainerViewController {
let container = SnapContainerViewController()
container.directionLockDisabled = directionLockDisabled
container.topVc = topVC
container.leftVc = leftVC
container.middleVc = middleVC
container.rightVc = rightVC
container.bottomVc = bottomVC
return container
}
var scrollOffSetClosure: ((_ offset: CGFloat) -> Void)?
// code truncated for brevity
func scrollViewDidScroll2(_ scrollView: UIScrollView) {
scrollOffSetClosure!(scrollView.contentOffset.x)
print("test here")
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
print("end scroll")
}
override func viewDidLoad() {
super.viewDidLoad()
addChildViewController(current)
current.view.frame = view.bounds
view.addSubview(current.view)
current.didMove(toParentViewController: self)
}
func setupVerticalScrollView() {
middleVertScrollVc = VerticalScrollViewController.verticalScrollVcWith(middleVc: middleVc as! Camera,
topVc: topVc,
bottomVc: bottomVc)
delegate = middleVertScrollVc
}
func setupHorizontalScrollView() {
scrollView = UIScrollView()
scrollView.isPagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.bounces = false
print ("6")
let view = (
x: self.view.bounds.origin.x,
y: self.view.bounds.origin.y,
width: self.view.bounds.width,
height: self.view.bounds.height
)
scrollView.frame = CGRect(x: view.x,
y: view.y,
width: view.width,
height: view.height
)
self.view.addSubview(scrollView)
let scrollWidth = 3 * view.width
let scrollHeight = view.height
scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight)
leftVc.view.frame = CGRect(x: 0,
y: 0,
width: view.width,
height: view.height
)
middleVertScrollVc.view.frame = CGRect(x: view.width,
y: 0,
width: view.width,
height: view.height
)
rightVc.view.frame = CGRect(x: 2 * view.width,
y: 0,
width: view.width,
height: view.height
)
addChildViewController(leftVc)
addChildViewController(middleVertScrollVc)
addChildViewController(rightVc)
scrollView.addSubview(leftVc.view)
scrollView.addSubview(middleVertScrollVc.view)
scrollView.addSubview(rightVc.view)
leftVc.didMove(toParentViewController: self)
middleVertScrollVc.didMove(toParentViewController: self)
rightVc.didMove(toParentViewController: self)
scrollView.contentOffset.x = middleVertScrollVc.view.frame.origin.x
scrollView.delegate = self
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
// print ("Scrollviewvillbegindragging scrollView.contentOffset \(scrollView.contentOffset)")
self.initialContentOffset = scrollView.contentOffset
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if delegate != nil && !delegate!.outerScrollViewShouldScroll() && !directionLockDisabled {
let newOffset = CGPoint(x: self.initialContentOffset.x, y: self.initialContentOffset.y)
// print(newOffset.x)
//print(newOffset.y)
// Setting the new offset to the scrollView makes it behave like a proper
// directional lock, that allows you to scroll in only one direction at any given time
self.scrollView!.setContentOffset(newOffset, animated: false)
// print ("newOffset \(newOffset)")
// tell child views they have appeared / disappeared
}
if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("aaa!")}
if (scrollView.contentOffset) == CGPoint(x: 0.0, y: -667.0) {print ("bbb!")}
if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 375) {print ("aaccca!")}
if (scrollView.contentOffset) == CGPoint(x: 0.0, y: -375) {print ("ddddd!")}
if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) {print ("eeeeeee!")}
// if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("ffffff!")}
// if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("aggggggggaa!")}
// print ("scrollViewDidScroll scrollView.contentOffset \(scrollView.contentOffset)")
// scrollView.contentOffset
if (scrollView.contentOffset) == CGPoint(x: 750.0, y: 0.0) {
print ("TEST OK LEFT!")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadRinkbox"), object: nil)
}
if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) {
print ("TEST OK RIGHT!")
}
if (scrollView.contentOffset) == CGPoint(x: -750.0, y: 0.0) {
print ("TEST OK LEFT")
}
if (scrollView.contentOffset) == CGPoint(x: 375, y: 0.0) {
print ("TEST LEFT/RIGHT OK!")
}
}
private func animateFadeTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
print ("Ca va dans animateFadeTransition")
current.willMove(toParentViewController: nil)
addChildViewController(new)
transition(from: current, to: new, duration: 0.3, options: [.transitionCrossDissolve, .curveEaseOut], animations: {
}) { completed in
self.current.removeFromParentViewController()
new.didMove(toParentViewController: self)
self.current = new
completion?()
}
}
private func animateDismissTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
print ("Ca va dans animateDismissTransition")
let initialFrame = CGRect(x: -view.bounds.width, y: 0, width: view.bounds.width, height: view.bounds.height)
current.willMove(toParentViewController: nil)
addChildViewController(new)
new.view.frame = initialFrame
transition(from: current, to: new, duration: 0.3, options: [], animations: {
new.view.frame = self.view.bounds
}) { completed in
self.current.removeFromParentViewController()
new.didMove(toParentViewController: self)
self.current = new
completion?()
}
}
}
and VerticalScrollViewController
/ MiddleScrollViewController.swift
// SnapchatSwipeView
//
// Created by Jake Spracher on 12/14/15.
// Copyright © 2015 Jake Spracher. All rights reserved.
//
import UIKit
class VerticalScrollViewController: UIViewController, SnapContainerViewControllerDelegate {
var topVc: UIViewController!
var middleVc: UIViewController!
var bottomVc: UIViewController!
var scrollView: UIScrollView!
class func verticalScrollVcWith(middleVc: UIViewController,
topVc: UIViewController?=nil,
bottomVc: UIViewController?=nil) -> VerticalScrollViewController {
let middleScrollVc = VerticalScrollViewController()
middleScrollVc.topVc = topVc
middleScrollVc.middleVc = middleVc
middleScrollVc.bottomVc = bottomVc
return middleScrollVc
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view:
setupScrollView()
}
func setupScrollView() {
scrollView = UIScrollView()
scrollView.isPagingEnabled = true
scrollView.showsVerticalScrollIndicator = false
scrollView.bounces = false
let view = (
x: self.view.bounds.origin.x,
y: self.view.bounds.origin.y,
width: self.view.bounds.width,
height: self.view.bounds.height
)
scrollView.frame = CGRect(x: view.x, y: view.y, width: view.width, height: view.height)
self.view.addSubview(scrollView)
let scrollWidth: CGFloat = view.width
var scrollHeight: CGFloat
switch (topVc, bottomVc) {
case (nil, nil):
scrollHeight = view.height
middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
addChildViewController(middleVc)
scrollView.addSubview(middleVc.view)
middleVc.didMove(toParentViewController: self)
case (_?, nil):
scrollHeight = 2 * view.height
topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height)
addChildViewController(topVc)
addChildViewController(middleVc)
scrollView.addSubview(topVc.view)
scrollView.addSubview(middleVc.view)
topVc.didMove(toParentViewController: self)
middleVc.didMove(toParentViewController: self)
scrollView.contentOffset.y = middleVc.view.frame.origin.y
case (nil, _?):
scrollHeight = 2 * view.height
middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
bottomVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height)
addChildViewController(middleVc)
addChildViewController(bottomVc)
scrollView.addSubview(middleVc.view)
scrollView.addSubview(bottomVc.view)
middleVc.didMove(toParentViewController: self)
bottomVc.didMove(toParentViewController: self)
scrollView.contentOffset.y = 0
default:
scrollHeight = 3 * view.height
topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height)
bottomVc.view.frame = CGRect(x: 0, y: 2 * view.height, width: view.width, height: view.height)
addChildViewController(topVc)
addChildViewController(middleVc)
addChildViewController(bottomVc)
scrollView.addSubview(topVc.view)
scrollView.addSubview(middleVc.view)
scrollView.addSubview(bottomVc.view)
topVc.didMove(toParentViewController: self)
middleVc.didMove(toParentViewController: self)
bottomVc.didMove(toParentViewController: self)
scrollView.contentOffset.y = middleVc.view.frame.origin.y
}
scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight)
}
// MARK: - SnapContainerViewControllerDelegate Methods
func outerScrollViewShouldScroll() -> Bool {
if scrollView.contentOffset.y < middleVc.view.frame.origin.y || scrollView.contentOffset.y > 2*middleVc.view.frame.origin.y {
return false
} else {
return true
}
}
}
In MiddleScrollViewController.swift, make the controller conform to UIScrollViewDelegate:
class VerticalScrollViewController: UIViewController,
SnapContainerViewControllerDelegate,
UIScrollViewDelegate {
In that class, in setupScrollView(), set the delegate:
func setupScrollView() {
scrollView = UIScrollView()
// set the delegate to self
scrollView.delegate = self
// the rest of the existing code...
Still in that class, implement didScroll (or whatever other delegate funcs you want to handle):
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("Vertical Scroll - contentOffset:", scrollView.contentOffset)
}
Now you should get lots of print lines in the debug console when you scroll vertically:
Vertical Scroll - contentOffset: (0.0, 561.0)
Vertical Scroll - contentOffset: (0.0, 560.0)
Vertical Scroll - contentOffset: (0.0, 559.0)
Vertical Scroll - contentOffset: (0.0, 558.0)
If you want your SnapContainerViewController class to be informed when vertical scrolling takes place, you'll probably want to use a new protocol/delegate so VerticalScrollViewController can send that information.
Related
I have mocked up a simple example of what I am trying to accomplish:
A ViewController contains 4 "drop zone" UIImageViews (e.g. dropZone1). A 5th UIImageView (playerCard) can be dragged and dropped onto any of the drop zones, but nowhere else.
I cannot figure out the way to determine which of the 4 drop zones is where the user has dragged and dropped the playerCard.
My thought was to set some sort of variable in dropInteraction canHandle and then use that in dropInteraction performDrop to take the appropriate action. But I can't figure out how to do it.
class ViewController: UIViewController {
let bounds = UIScreen.main.bounds
let imageViewWidth: CGFloat = 100
let imageViewHeight: CGFloat = 200
let inset: CGFloat = 40
var arrayDropZones = [DropZoneCard]()
var initialFrame: CGRect {
get {
return CGRect(x: bounds.width - imageViewWidth,
y: bounds.height - imageViewHeight,
width: imageViewWidth,
height: imageViewHeight
)
}
}
override func viewDidLoad() {
super.viewDidLoad()
addDropZones()
addNewCard()
}
}
extension ViewController {
func addDropZones() {
let dropZone1 = getDropZoneCard()
dropZone1.frame = CGRect(x: inset, y: inset, width: imageViewWidth, height: imageViewHeight)
let dropZone2 = getDropZoneCard()
let x = bounds.width - imageViewWidth - inset
dropZone2.frame = CGRect(x: x, y: inset, width: imageViewWidth, height: imageViewHeight)
let dropZone3 = getDropZoneCard()
let y = inset + imageViewHeight + inset
dropZone3.frame = CGRect(x: inset, y: y, width: imageViewWidth, height: imageViewHeight)
let dropZone4 = getDropZoneCard()
dropZone4.frame = CGRect(x: x, y: y, width: imageViewWidth, height: imageViewHeight)
[dropZone1, dropZone2, dropZone3, dropZone4].forEach {
view.addSubview($0)
self.arrayDropZones.append($0)
}
}
func getNewCard() -> UIImageView {
let imageView = UIImageView()
imageView.isUserInteractionEnabled = true
imageView.backgroundColor = .green
imageView.frame = initialFrame
let panGesture = UIPanGestureRecognizer(target: self, action:(#selector(handleGesture(_:))))
imageView.addGestureRecognizer(panGesture)
return imageView
}
func getDropZoneCard() -> DropZoneCard {
let dropZone = DropZoneCard()
dropZone.isUserInteractionEnabled = true
dropZone.backgroundColor = .yellow
return dropZone
}
func addNewCard() {
let imageView = getNewCard()
view.addSubview(imageView)
}
#objc func handleGesture(_ recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
if recognizer.state == .ended {
let point = view.center
for dropZone in arrayDropZones {
if dropZone.frame.contains(point) {
dropZone.append(card: view)
addNewCard()
return
}
}
view.frame = initialFrame
}
}
recognizer.setTranslation(.zero, in: view)
}
}
class DropZoneCard: UIImageView {
private(set) var arrayCards = [UIView]()
func append(card: UIView) {
arrayCards.append(card)
card.isUserInteractionEnabled = false
card.frame = frame
}
}
I've got multiple UIImageViews, spread across in a view.
#IBOutlet var leftIVs: [UIImageView]!
#IBOutlet var topIVs: [UIImageView]!
#IBOutlet var rightIVs: [UIImageView]!
I'm trying to create a function using UIView.animate... functions and 'transform' property which brings all of these UIImageViews at the center of the superview. I'm using the following code:
let performInitialTransformation: ((UIImageView)->()) = { (card) in
let cardCenter = CGPoint(x: card.frame.midX, y: card.frame.midY)
let viewCenter = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.midY)
let deltaPoint = cardCenter - viewCenter //also tried (viewCenter - cardCenter)
UIView.animate(withDuration: 0.5, animations: {
card.transform = CGAffineTransform.init(translationX: deltaPoint.x, y: deltaPoint.y)
}) { (done) in
}
}
for card in topIVs {
performInitialTransformation(card)
}
for card in leftIVs {
performInitialTransformation(card)
}
for card in rightIVs {
performInitialTransformation(card)
}
I'm using this static function:
extension CGPoint {
static func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
return CGPoint(x: rhs.x - lhs.x, y: rhs.y - lhs.y)
}
}
NOTE: Also, I will be bringing those images back to there original position afterward for which I will use CGAffineTransform.identity
The images are not being shown in the center. How can I achieve this? Thanks in advance!
I think your problem was that you didn't reduce the size of the image view so that they stack at the exact centre of the screen.
let deltaX = (self.view.center.x - card.frame.minX) - card.frame.width/2
let deltaY = (self.view.center.y - card.frame.minY) - card.frame.height/2
UIView.animate(withDuration: 1) {
card.transform = .init(translationX: deltaX, y: deltaY)
}
What is about to use center
UIView.animate(withDuration: 0.5) {
images.forEach { $0.center = superview.center }
}
The full example
var subviewes = [UIView]()
var view = UIView(frame: CGRect.init(x: 0, y: 0, width: 30, height: 30))
view.backgroundColor = .yellow
subviewes.append(view)
view = UIView(frame: CGRect.init(x: 0, y: 0, width: 20, height: 20))
view.backgroundColor = .green
subviewes.append(view)
view = UIView(frame: CGRect.init(x: 0, y: 0, width: 10, height: 10))
view.backgroundColor = .red
subviewes.append(view)
subviewes.forEach { self.view.addSubview($0) }
UIView.animate(withDuration: 0.5) {
subviewes.forEach { $0.center = self.view.center }
}
I have a 'UISegmentedControl' which is programatically added in the view controller named SegmentControllForRides. (i added UISegmentedControl programatically because segment items will be changed some time 2 or 3.UISegmentedControl have three items. items names are ["Request","Upcoming", "Past"]. Each segment will show a viewController.view and hide the others. Each view controller have an API call. My problem is when first the SegmentControllForRides shows it calls the all three (child) viewcontroller API's( i think because views are hidden but loaded in controller thats why API calls goes to server). Each view controller has a UITableView and in UITableViewCell there is a UICollectionView. I tried to call (again) API when view is shown, in that case API call goes but UICollectionView got messed. It shows data of the other cell. For this i tried to
DispatchQueue.main.async {
reloadCollectionView()
}
but this does not help.
I want to call API when child view is shown (not on the SegmentControllForRides load). It is also necessary because first controller API response have the effect of the second controller API call. So Kindly guide me how to call API after the view shown.
I will try provide any further detail.
Here is my class.
import UIKit
class SegmentControllForRides: UIViewController {
// MARK: - Variables
var controller: UIViewController!
var requestedRideViewController: RequestedRideViewController!
var upcomingRideViewController: UpcomingRideViewController!
var myRideViewControllerUpcoming: UIViewController!
var myRideViewControllerPast: UIViewController!
var segmentControll: UISegmentedControl!
var sideMenuOpen = false
// MARK: - Outlets
// MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
configure()
}
override func viewWillDisappear(_ animated: Bool) {
if sideMenuOpen {
openCloseSideMenu()
}
}
// MARK: - Actions & Events
#IBAction func segmentControllChanged(_ sender: UISegmentedControl) {
if UserDefaults.standard.bool(forKey: User.isAppUsingAsPassenger) {
switch segmentControll.selectedSegmentIndex {
case 0:
print("segment 1")
myRideViewControllerUpcoming.view.isHidden = false
myRideViewControllerUpcoming.didMove(toParent: self)
myRideViewControllerPast.view.isHidden = true
case 1:
print("segment 2")
myRideViewControllerUpcoming.view.isHidden = true
myRideViewControllerPast.view.isHidden = false
myRideViewControllerPast.didMove(toParent: self)
default:
break
}
} else {
switch segmentControll.selectedSegmentIndex {
case 0:
print("segment 1")
requestedRideViewController.view.isHidden = false
requestedRideViewController.didMove(toParent: self)
upcomingRideViewController.view.isHidden = true
myRideViewControllerPast.view.isHidden = true
case 1:
print("segment 2")
requestedRideViewController.view.isHidden = true
upcomingRideViewController.view.isHidden = false
// upcomingRideViewController.getUpcomingRide()
upcomingRideViewController.didMove(toParent: self)
myRideViewControllerPast.view.isHidden = true
// let myClass : UpcomingRideViewController = self.children[1] as! UpcomingRideViewController
// myClass.myRideTableView.reloadData()
// myClass.getUpcomingRide()
// myClass.viewWillAppear(false)
case 2:
print("Segment 3")
requestedRideViewController.view.isHidden = true
upcomingRideViewController.view.isHidden = true
myRideViewControllerPast.view.isHidden = false
myRideViewControllerPast.didMove(toParent: self)
default:
break
}
}
}
#IBAction func sideMenuClicked(_ sender: UIBarButtonItem) {
openCloseSideMenu()
}
#objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == .right {
print("Swipe Right")
if !sideMenuOpen {
openCloseSideMenu()
}
} else if gesture.direction == .left {
print("Swipe Left")
if sideMenuOpen {
openCloseSideMenu()
}
}
}
// MARK: - Helper Methods
private func configure() {
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeLeft.direction = .left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
controller = storyboard!.instantiateViewController(withIdentifier: "SideMenuViewController")
if UserDefaults.standard.bool(forKey: User.isAppUsingAsPassenger) {
let segmentItems = ["Upcoming", "Past"]
segmentControll = UISegmentedControl(items: segmentItems)
segmentControll.frame = CGRect(x:0 ,y: 0, width: view.frame.width, height: 30)
segmentControll.addTarget(self, action: #selector(segmentControllChanged), for: .valueChanged)
segmentControll.selectedSegmentIndex = 0
segmentControll.backgroundColor = .rideelyGray
if #available(iOS 13.0, *) {
segmentControll.selectedSegmentTintColor = .rideelyYellow
} else {
// Fallback on earlier versions
}
view.addSubview(segmentControll)
myRideViewControllerUpcoming = storyboard!.instantiateViewController(withIdentifier: "MyRideViewController")
addChild(myRideViewControllerUpcoming)
myRideViewControllerUpcoming.view.frame = CGRect(x: 0, y: 30, width: view.frame.width, height: view.frame.height - 30) // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
view.addSubview(myRideViewControllerUpcoming.view)
myRideViewControllerUpcoming.didMove(toParent: self)
myRideViewControllerUpcoming.view.frame = CGRect(x: 0 - self.view.frame.width, y: 30, width: view.frame.width, height: view.frame.height - 30)
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.myRideViewControllerUpcoming.view.frame = CGRect(x: 0, y: 30, width: self.view.frame.width, height: self.view.frame.height - 30)
}, completion:nil)
myRideViewControllerUpcoming.view.isHidden = false
myRideViewControllerPast = storyboard!.instantiateViewController(withIdentifier: "MyRideViewController")
addChild(myRideViewControllerPast)
myRideViewControllerPast.view.frame = CGRect(x: 0, y: 30, width: view.frame.width, height: view.frame.height - 30) // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
view.addSubview(myRideViewControllerPast.view)
myRideViewControllerPast.didMove(toParent: self)
myRideViewControllerPast.view.frame = CGRect(x: 0 - self.view.frame.width, y: 30, width: view.frame.width, height: view.frame.height - 30)
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.myRideViewControllerPast.view.frame = CGRect(x: 0, y: 30, width: self.view.frame.width, height: self.view.frame.height - 30)
}, completion:nil)
myRideViewControllerPast.view.isHidden = true
} else {
let segmentItems = ["Request","Upcoming", "Past"]
segmentControll = UISegmentedControl(items: segmentItems)
segmentControll.frame = CGRect(x:0 ,y: 0, width: view.frame.width, height: 30)
segmentControll.addTarget(self, action: #selector(segmentControllChanged), for: .valueChanged)
segmentControll.selectedSegmentIndex = 0
segmentControll.backgroundColor = .rideelyGray
if #available(iOS 13.0, *) {
segmentControll.selectedSegmentTintColor = .rideelyYellow
} else {
// Fallback on earlier versions
}
view.addSubview(segmentControll)
requestedRideViewController = (storyboard!.instantiateViewController(withIdentifier: "RequestedRideViewController") as! RequestedRideViewController)
addChild(requestedRideViewController)
requestedRideViewController.view.frame = CGRect(x: 0, y: 30, width: view.frame.width, height: view.frame.height) // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
view.addSubview(requestedRideViewController.view)
requestedRideViewController.didMove(toParent: self)
requestedRideViewController.view.frame = CGRect(x: 0 - self.view.frame.width, y: 30, width: view.frame.width, height: view.frame.height)
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.requestedRideViewController.view.frame = CGRect(x: 0, y: 30, width: self.view.frame.width, height: self.view.frame.height - 30)
}, completion:nil)
requestedRideViewController.view.isHidden = false
upcomingRideViewController = (storyboard!.instantiateViewController(withIdentifier: "UpcomingRideViewController") as! UpcomingRideViewController)
addChild(upcomingRideViewController)
upcomingRideViewController.view.frame = CGRect(x: 0, y: 30, width: view.frame.width, height: view.frame.height - 30) // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
view.addSubview(upcomingRideViewController.view)
upcomingRideViewController.didMove(toParent: self)
upcomingRideViewController.view.frame = CGRect(x: 0 - self.view.frame.width, y: 30, width: view.frame.width, height: view.frame.height)
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.upcomingRideViewController.view.frame = CGRect(x: 0, y: 30, width: self.view.frame.width, height: self.view.frame.height - 30)
}, completion:nil)
upcomingRideViewController.view.isHidden = true
myRideViewControllerPast = storyboard!.instantiateViewController(withIdentifier: "MyRideViewController")
addChild(myRideViewControllerPast)
myRideViewControllerPast.view.frame = CGRect(x: 0, y: 30, width: view.frame.width, height: view.frame.height - 30) // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
view.addSubview(myRideViewControllerPast.view)
myRideViewControllerPast.didMove(toParent: self)
myRideViewControllerPast.view.frame = CGRect(x: 0 - self.view.frame.width, y: 30, width: view.frame.width, height: view.frame.height - 30)
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.myRideViewControllerPast.view.frame = CGRect(x: 0, y: 30, width: self.view.frame.width, height: self.view.frame.height - 30)
}, completion:nil)
myRideViewControllerPast.view.isHidden = true
}
}
private func openCloseSideMenu() {
if sideMenuOpen {
sideMenuOpen = false
controller.removeFromParent()
controller.view.removeFromSuperview()
} else {
sideMenuOpen = true
addChild(controller)
controller.view.frame = CGRect(x: 0, y: 0, width: view.frame.width * 0.8, height: view.frame.height) // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
view.addSubview(controller.view)
controller.didMove(toParent: self)
controller.view.frame = CGRect(x: 0 - self.view.frame.width, y: 0, width: view.frame.width * 0.8, height: view.frame.height)
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.controller.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width * 0.8, height: self.view.frame.height)
}, completion:nil)
}
}
}
You need to configure your api calls in segmentControllChanged, there are many ways you can achieve this . One way that will best suit is
You can use flag for each controller to check when the segment is scrolled then only you hit the api explicitly otherwise don't hit it.
1 example for this
CODE -
switch segmentControll.selectedSegmentIndex {
case 1:
print("segment 1")
myRideViewControllerUpcoming.isVisible = true
// call your myRideViewControllerUpcoming api method here
}
I want to add UITableView on top of UIView which is a subclass of GooeySlideMenu. As in example shown in git I created UITableView instead of UIButtons but delegate methods are not called.
Below is my code for reference:
class GooeySlideMenu: UIView {
fileprivate var _option: MenuOptions
fileprivate var keyWindow: UIWindow?
fileprivate var blurView: UIVisualEffectView!
fileprivate var helperSideView: UIView!
fileprivate var helperCenterView: UIView!
fileprivate var diff: CGFloat = 0.0
fileprivate var triggered: Bool = false
fileprivate var displayLink: CADisplayLink?
fileprivate var animationCount: Int = 0
fileprivate var myTableView: tableViewCustomClass = tableViewCustomClass()
init(options: MenuOptions) {
_option = options
if let kWindow = UIApplication.shared.keyWindow{
keyWindow = kWindow
let frame = CGRect(
x: -kWindow.frame.size.width/2 - options.menuBlankWidth,
y: 0,
width: kWindow.frame.size.width/2 + options.menuBlankWidth,
height: kWindow.frame.size.height)
super.init(frame:frame)
} else {
super.init(frame:CGRect.zero)
}
setUpViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: frame.width-_option.menuBlankWidth, y: 0))
path.addQuadCurve(to: CGPoint(x: frame.width-_option.menuBlankWidth, y: frame.height), controlPoint: CGPoint(x: frame.width-_option.menuBlankWidth+diff, y: frame.height/2))
path.addLine(to: CGPoint(x: 0, y: frame.height))
path.close()
let context = UIGraphicsGetCurrentContext()
context?.addPath(path.cgPath)
_option.menuColor.set()
context?.fillPath()
}
func trigger() {
if !triggered {
if let keyWindow = keyWindow {
keyWindow.insertSubview(blurView, belowSubview: self)
UIView.animate(withDuration: 0.3, animations: { [weak self] () -> Void in
self?.frame = CGRect(
x: 0,
y: 0,
width: keyWindow.frame.size.width/2 + (self?._option.menuBlankWidth)!,
height: keyWindow.frame.size.height)
})
beforeAnimation()
UIView.animate(withDuration: 0.7, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.9, options: [.beginFromCurrentState,.allowUserInteraction], animations: { [weak self] () -> Void in
self?.helperSideView.center = CGPoint(x: keyWindow.center.x, y: (self?.helperSideView.frame.size.height)!/2);
}, completion: { [weak self] (finish) -> Void in
self?.finishAnimation()
})
UIView.animate(withDuration: 0.3, animations: { [weak self] () -> Void in
self?.blurView.alpha = 1.0
})
beforeAnimation()
UIView.animate(withDuration: 0.7, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 2.0, options: [.beginFromCurrentState,.allowUserInteraction], animations: { [weak self] () -> Void in
self?.helperCenterView.center = keyWindow.center
}, completion: { [weak self] (finished) -> Void in
if finished {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(GooeySlideMenu.tapToUntrigger))
self?.blurView.addGestureRecognizer(tapGesture)
self?.finishAnimation()
}
})
// animateButtons()
myTableView.reloadData()
triggered = true
}
} else {
tapToUntrigger()
}
}
}
extension GooeySlideMenu {
fileprivate func setUpViews() {
if let keyWindow = keyWindow {
blurView = UIVisualEffectView(effect: UIBlurEffect(style: _option.blurStyle))
blurView.frame = keyWindow.frame
blurView.alpha = 0.0
helperSideView = UIView(frame: CGRect(x: -40, y: 0, width: 40, height: 40))
helperSideView.backgroundColor = UIColor.red
helperSideView.isHidden = true
keyWindow.addSubview(helperSideView)
helperCenterView = UIView(frame: CGRect(x: -40, y: keyWindow.frame.height/2 - 20, width: 40, height: 40))
helperCenterView.backgroundColor = UIColor.yellow
helperCenterView.isHidden = true
keyWindow.addSubview(helperCenterView)
backgroundColor = UIColor.clear
keyWindow.insertSubview(self, belowSubview: helperSideView)
addUItableView()
// addButton()
}
}
fileprivate func addUItableView(){
myTableView.frame = CGRect(x: 0, y: 20, width: 300, height: 200)
myTableView.backgroundColor = UIColor.white
myTableView.delegate = tableViewCustomClass() as? UITableViewDelegate
myTableView.dataSource = tableViewCustomClass() as? UITableViewDataSource
addSubview(myTableView)
}
You need to declared tableview's delegate on tableViewCustomClass's class instead of GooeySlideMenu class .
In tableViewCustomClass
self.delegate = self in tableViewCustomClass's initialiser method
I have a very simple sample that allows to drag an UIView around. When touch up, I will have an inertia effect on the dragging direction for a second. While if I touch down again, I need to stop all the inertia animation and start to do another drag. Here is my code, the "clearAllAnimations" doesn't stop my animation. How could I implement that?
import UIKit
class ViewController: UIViewController {
var tile : UIView = UIView()
var labelView = UITextView()
var displayLink : CADisplayLink?
override func viewDidLoad() {
super.viewDidLoad()
tile.frame = CGRect(x: 0, y: 0, width: 256, height: 256)
tile.backgroundColor = UIColor.redColor()
view.addSubview(tile)
var panGesture = UIPanGestureRecognizer(target: self, action: Selector("panHandler:"))
view.addGestureRecognizer(panGesture)
labelView.frame = CGRect(x: 0, y: 100, width: view.frame.width, height: 44)
labelView.backgroundColor = UIColor.clearColor()
view.addSubview(labelView)
}
func panHandler (p: UIPanGestureRecognizer!) {
var translation = p.translationInView(view)
if (p.state == UIGestureRecognizerState.Began) {
self.tile.layer.removeAllAnimations()
}
else if (p.state == UIGestureRecognizerState.Changed) {
var offsetX = translation.x
var offsetY = translation.y
var newLeft = tile.frame.minX + offsetX
var newTop = tile.frame.minY + offsetY
self.tile.frame = CGRect(x: newLeft, y: newTop, width: self.tile.frame.width, height: self.tile.frame.height)
labelView.text = "x: \(newLeft); y: \(newTop)"
p.setTranslation(CGPoint.zeroPoint, inView: view)
}
else if (p.state == UIGestureRecognizerState.Ended) {
var inertia = p.velocityInView(view)
var offsetX = inertia.x * 0.2
var offsetY = inertia.y * 0.2
var newLeft = tile.frame.minX + offsetX
var newTop = tile.frame.minY + offsetY
UIView.animateWithDuration(1, delay: 0, options:UIViewAnimationOptions.CurveEaseOut, animations: {_ in
self.tile.frame = CGRect(x: newLeft, y: newTop, width: self.tile.frame.width, height: self.tile.frame.height)
}, completion: nil)
}
}
}
Setting UIViewAnimationOptions.AllowUserInteraction does the trick. The new code to start animation is this:
UIView.animateWithDuration(animationDuration, delay: 0, options:UIViewAnimationOptions.CurveEaseOut | UIViewAnimationOptions.AllowUserInteraction | UIViewAnimationOptions.BeginFromCurrentState, animations: {_ in
self.tile.frame = CGRect(x: newLeft, y: newTop, width: self.tile.frame.width, height: self.tile.frame.height)
}, completion: nil)