Swipe Left or Right to Load the View Controller with the Collection View Cell Highlight

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



Leave a reply



Submit