Swipe left or right to load the view controller with the collection view cell highlight
You should just add UISwipeGestureRecognizer
to the main view controller's view.
The main view controller would be responsible for managing the gesture's calls
Basically in code:
in viewDidLoad
:
let swipeToLeft = UISwipeGestureRecognizer(target: self, action: #selector(changePageOnSwipe(_:)))
let swipeToRight = UISwipeGestureRecognizer(target: self, action: #selector(changePageOnSwipe(_:)))
swipeToLeft.direction = .right
swipeToRight.direction = .left
self.contentSubView.addGestureRecognizer(swipeToLeft) // Gesture are added to the top view that should handle them
self.contentSubView.addGestureRecognizer(swipeToRight)
Since you will have to move from a VC at an index to another index you might need a property for keeping track of the currently selected view controller:
var currentIndexPath: IndexPath?
And you can change the value of it each time a new VC is selected. So:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
self.currentIndexPath = indexPath
// ... Other settings
}
add the changePageOnSwipe(_ gesture: UISwipeGestureRecognizer)
method in your main ViewController. Since it is the "chief" view controller who possesses the collectionView
, it will handle the swipes and tell its children to appear:
func changePageOnSwipe(_ gesture: UISwipeGestureRecognizer) {
guard let indexPath = self.currentIndexPath else {
// When the page loads and there is no current selected VC, the swipe will not work
// unless you set an initial value for self.currentIndexPath
return
}
var newIndex = indexPath // if self.collectionview.indexPathsForSelectedItems is not empty, you can also use it instead of having a self.currentIndexPath property
// move in the opposite direction for the movement to be intuitive
// So swiping " <-- " should show index on the right (row + 1)
if gesture.direction == .left {
newIndex = IndexPath(row: newIndex.row+1, section: newIndex.section)
} else {
newIndex = IndexPath(row: newIndex.row-1, section: self.currentIndexPath!.section)
}
if canPresentPageAt(indexPath: newIndex) {
// Programmatically select the item and make the collectionView scroll to the correct number
self.collectionview.selectItem(at: newIndex, animated: true, scrollPosition: UICollectionViewScrollPosition.centeredHorizontally)
// The delegate method is not automatically called when you select programmatically
self.collectionView(self.collectionview, didSelectItemAt: newIndex!)
} else {
// Do something when the landing page is invalid (like if the swipe would got to page at index -1 ...)
// You could choose to direct the user to the opposite side of the collection view (like the VC at index self.items.count-1
print("You are tying to navigate to an invalid page")
}
}
and since you are doing the swipe programmatically, you have to make sure that the swipe is valid before trying to actually move. You have to add safety checks:
/** You can use an helper method for those checks
*/
func canPresentPageAt(indexPath: IndexPath) -> Bool {
// Do necessary checks to ensure that the user can indeed go to the desired page
// Like: check if you have a non-nil ViewController at the given index. (If you haven't implemented index 3,4,5,... it should return false)
//
// This method can be called either from a swipe
// or another way when you need it
if indexPath.row < 0 || indexPath.row >= self.items.count {
print("You are trying to go to a non existing page")
return false
} else {
print("If you haven't implemented a VC for page 4 it will crash here")
return true;
}
}
Finally, you can set a default indexPath for self.currentIndexPath
in viewDidLoad
so that the user can already swipe when he lands on your main VC without having selected another VC in the collectionView.
Note: If you happen to have gesture recognisers in the sub-ViewControllers, some gestures may conflict and you would have to learn how to resolve such conflicts with delegate methods such as gestureRecognizer(_:shouldRequireFailureOf:)
.
How to show different view controller on did select of collectionv view cell
do like
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
based on your comment remove the subviews before add on your myview
for subview in contentSubView.subviews {
subview.removeFromSuperview()
}
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
var controller: UIViewController!
if indexPath.item == 0 {
if let allCollectionViewController = alertStoryBoard.instantiateViewController(withIdentifier:"firstvc") as? firstvc {
controller = allCollectionViewController
}
} else if indexPath.item == 1 {
if let allCollec = alertStoryBoard.instantiateViewController(withIdentifier:"secondvc") as? secondvc {
controller = allCollec
}
}else if indexPath.item == 2 {
if let wController = alertStoryBoard.instantiateViewController(withIdentifier:"Thirdvc") as? Thirdvc {
controller = wController
}
}
addChildViewController(controller)
// Add the child's View as a subview
contentSubView.addSubview(controller.view)
controller.view.frame = contentSubView.bounds
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// tell the childviewcontroller it's contained in it's parent
controller.didMove(toParentViewController: self)
}
button click function in custom cell based on obtained indexpath of current cell
There is a simple way to make this work:
In your cellForRowAtIndexPath
method, you can set a tag to your button with the current row value like:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = //cell
cell.myButton.tag = indexPath.row
cell.myButton.addTarget(self, action: #selector(ViewController.getDirection(_:)), forControlEvents: UIControlEvents.TouchUpInside)
}
and on your function
func getDirection(sender: UIButton) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: mapvc2 = storyboard.instantiateViewControllerWithIdentifier("mapvc2") as! mapvc2
let indexPathRow = sender.tag
let DestinationLocation = CLLocationCoordinate2D(latitude: val[indexPathRow].latlng[0] as! Double, longitude: val[indexPathRow].latlng[1] as! Double)
vc.PlotRoute(DestinationLocation)
vc.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "< back", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(ContainerViewController.goBack))
let navController = UINavigationController(rootViewController: vc)
dispatch_async(dispatch_get_main_queue(),{
self.presentViewController(navController, animated: true, completion: nil)
})
}
It is result you expect ?
UITapGesture not arriving at UICollectionView (collection view is subview of TableViewCell)
It was a face palm issue... had another gesture recognizer on top of everything else that was grabbing the taps. Works perfectly as expected without that.
Swift: Add border to one side of a table View cell
You could try using CALayer or override drawRect
and draw a line where you want.
Here is an example using CALayer
private func addRightBorder() {
let border = CALayer()
let borderWidth: CGFloat = 5
// Set the color your want
border.backgroundColor = UIColor.red.cgColor
// Create a rect only on the right of the view
border.frame = CGRect(x: bounds.maxX - borderWidth,
y: 0,
width: borderWidth,
height: bounds.maxY)
layer.addSublayer(border)
}
Update
Based on Duncan's valid comments:
Note that if your app supports device rotation (or iPad multitasking),
you need to add logic that detects layout changes and moves the border
layer. Thus for a full implementation you'll probably need to save the
border layer as an instance var and add code to adjust its position on
layout changes.
Here are some changes that hopefully handle this scenario:
// Persist the CALayer
var rightBorder: CALayer?
let borderWidth: CGFloat = 5
override func layoutSubviews() {
super.layoutSubviews()
// Add right border if we haven't already
if rightBorder == nil {
addRightBorder()
}
// Update the frames based on the current bounds
rightBorder?.frame = CGRect(x: bounds.maxX - borderWidth,
y: 0,
width: borderWidth,
height: bounds.maxY)
}
private func addRightBorder() {
rightBorder = CALayer()
rightBorder!.backgroundColor = UIColor.red.cgColor
layer.addSublayer(rightBorder!)
}
tableView(_:commit:forRowAt:) not being triggered
Credit to @DonMag: feel free to post it and I'll make it as the answer.
Removed the whole method ViewDidLayoutSubview
//Automatic TableView height fit to its content
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//Initialize the tableView with automatic fit for its height based on its content
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: tableView.frame.size.width, height: tableView.contentSize.height)
//Update the table with the actual height needed
tableView.reloadData()
}
I just needed to remove the tableView.reloadData() and it will work like a charm.
How to automatically scrolling collectionviewcell to nearest cell(previous or next) when selecting a cell
You can just scroll to that indexPath
on didSelectItemAt
Method
var selectedIndex = 0
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "tabCell", for: indexPath) as! tabCollectionViewCell
cell.tabLabel.text = self.tabArray[indexPath.item]
if self.selectedIndex == indexpath.item {
cell.bottomView.isHidden = false
} else {
cell.bottomView.isHidden = true
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.selectedIndex = indexpath.item
self.tabCollectionView.reloadData()
tabCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
Hope this Help!
CollectionView move to next cell automatically swift
Below is code you can try :
/**
Scroll to Next Cell
*/
func scrollToNextCell(){
//get Collection View Instance
let collectionView:UICollectionView;
//get cell size
let cellSize = CGSizeMake(self.view.frame.width, self.view.frame.height);
//get current content Offset of the Collection view
let contentOffset = collectionView.contentOffset;
//scroll to next cell
collectionView.scrollRectToVisible(CGRectMake(contentOffset.x + cellSize.width, contentOffset.y, cellSize.width, cellSize.height), animated: true);
}
/**
Invokes Timer to start Automatic Animation with repeat enabled
*/
func startTimer() {
let timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("scrollToNextCell"), userInfo: nil, repeats: true);
}
Related Topics
Uitapgesturerecognizer on Uiimageview Within Uitablevlewcell Not Getting Called
Is Wkwebview Designed as a Replacement of Uiwebview
Fonts Not Displaying in Interface Builder
Disable iOS Simulator 'Connect Hardware Keyboard' Programmatically
How to Change a Swiftui Color to Uicolor
How to Call Https Url in Uiwebview
How to Add Custom Text in Nsdateformatter's Format String
Nsdata to Nsstring with JSON Response
Xcode 5/iOS 7 - Localization Not Working in Simulator
iOS Unrecognized Selector Sent to Instance in Swift
Apple MACh-O Linker (Id) Warning:Building for MACosx, But Linking Against Dylib Built for iOS
Drawing with Cgpath to Svg Output
Get Sms Broadcast with Text Body Without Jailbreak But Private Frameworks in iOS
Simple Uitableview in Swift - Unexpectedly Found Nil
How to Run Multiple iOS Simulators at Once