Scroll to cell but no select - swift

I have a UIViewController with a UIBarButtonItem "Edit".When I tap "Edit" I push another controller with some data.I have 2 UICollectionView inside my controller and they scroll to cells with a specific NSIndexPath.For example in this image:
It works if I can see cells (from 1.0/5.0 to 2.5/5.0) but if the item of my IndexPath is 6 for example, my collectionView scrolls to the 6th cell (4.0/5.0) but it doesn't select it, and I got this result(as you can see cell's background is not black, so it is not selected):
This is my code:
var index = NSIndexPath(item: indexPathSelected.item, section: 0)
ratingCollectionView.collectionView.selectItem(at: index as IndexPath, animated: true, scrollPosition: .centeredHorizontally)
ratingCollectionView.collectionView(collectionView, didSelectItemAt: index as IndexPath)

Related

how to show the middle cell of a collection view when my app starts

I have a collectionView embedded in a subview of the ViewController. The collectionView has 12 cells. Each cell takes up the whole width and height of the collection view, so that I can achieve the pagination affect. However, when the app starts, I want to show the middle cell like the 6th or 7th one of my collectionView.
P.S. I have the collectionView in a wrapper view, not in my viewController.
In my WrapperView, I added the following method but as this method is called after the collectionView is added, it shows a sudden jump.
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
let indexPath = IndexPath(row: 6, section: 0)
DispatchQueue.main.async {
self.calendarCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false)
}
}
If I could do it before the collection view appear on the screen, I may be able to fix that problem, but I can't find which method is called before the didAddSubview(_:) method in UIView Life Cycle.
Can anyone give me hint on how to solve this.
After your data source has loaded use:
func selectItem(at indexPath: IndexPath?,
animated: Bool,
scrollPosition: UICollectionView.ScrollPosition)
https://developer.apple.com/documentation/uikit/uicollectionview/1618057-selectitem
Probably best used before the view appears so trigger in viewWillAppear or viewDidLoad

Swift 3 - Scroll to top of Tableview on Tabbar Switch

I have a few UITableViewController's set up as child-views of UINavigationController's that are all part of a single UITabBarController. One of these UITableViewController's updates a tableViewController that is part of a different UITableViewController on a button press, which then switches the currently selected tab via:
self.tabBarController?.selectedIndex = 1
I would like the tableView in the newly selected index, in this case 1,to scroll back to the top automatically on changing between the tabViews. I have tries simply adding :
self.tableView.setContentOffset(CGPoint.zero, animated: true)
To viewWillAppear() but this doesn't seem to work. If you scroll to the bottom of the tableView on index 1, then tab over to the tabBarController that updates that index(say index 0), update the index and get switched back to index 1, the tableview for index 1 remains on the same row as when you originally were viewing it. The data is properly loaded, but the actual UI is still on the row you left at. I would like to implement it so that switching between tabs automatically scrolls to the top.
You can try using IndexPath and scroll to index 0 of section 0 :
let indexPath = IndexPath(row: 0, section: sectionIndex) // set row = 0 and section = 0
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
You can use scrollToRow(at:at:animated:).
You can add this to the viewWillAppear(_ animated: Bool) function:
let indexPath = IndexPath(item: 0, section: 0)
tableView.scrollToRow(at: indexPath, at: .top, animated: false)

How does changing the intrinsicContentSize of a UITableViewCell work?

I made a UITableView with cells that expand when you tap on them. It is modeled off the following project: https://github.com/rushisangani/TableViewCellExpand
Basically, the cell's container view has two subviews which act as containers for the expanded/contracted states - "front" and "back", each of which is constrained to the top, bottom, leading, and trailing edges of the cell's main content view. To make the cell expand or contract, I just toggle the isActive property on the bottom constraint of the front and back views. This works, but only if I reload the cell when it is tapped. If I just change the constraints and then try to call invalidateIntrinsicContentSize(), nothing happens.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
// Expand/contract the cell and invalidate size (doesn't work)
// let cell = tableView.cellForRow(at: indexPath) as! ExpandingCell
// cell.tap()
// cell.invalidateIntrinsicContentSize()
// Keep track of the selected index and configure the expand/contract state when the cell is remade
tableView.deselectRow(at: indexPath, animated: false)
expandedIndexPath = indexPath
if(!expandedIndexPathArray.contains(indexPath)){
expandedIndexPathArray.append(indexPath)
}
else{
expandedIndexPathArray = expandedIndexPathArray.filter({$0 != indexPath})
}
// Whenever a cell's intrinsicContentSize changes, it must be reloaded
tableView.reloadRows(at: [indexPath], with: .none)
}
What's going on behind the scenes? Why can't the cell recalculate its size without being reloaded?
If you want to contract/expand cells based on their intrinsic content size, you need to do the following 3 steps:
Configure the table view:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
For static table view controller, you will need to implement heightForRowAtIndexPath and return UITableViewAutomaticDimension.
Update cell constraints to reflect contracted/expanded state
Ask the table view to reflect changes:
tableView.beginUpdates()
tableView.endUpdates()

Returning to the same scroll position of UICollectionView after tapping a cell

I have a UICollectionView that is populated with all photos from the devices photo library. After a cell (photo) is tapped, it segues to a view controller that allows for editing. On this view, there is an "Add Photo" button to return the user back to the UICollectionView (to select another photo). I need for the scroll position to "focus" the previous tapped cell in the center of the view without any animations or jumping.
I have tried saving the tapped indexPath as a variable, then on viewDidAppear, scroll to that indexPath with scrollToItemAtIndexPath. The problem is I can't figure out how to update a variable (to save indexPath) on cell tap. I tried this in didSelectItemAtIndexPath, but the value never actually saves.
var cellTappedIndexPath = Int()
Inside didSelectItemAtIndexPath:
cellTappedIndexPath = indexPath.row
The value for cellTappedIndexPath never saves.
Just for testing out scrollToItemAtIndexPath, I have added the following to viewDidAppear:
customViewCollectionView.scrollToItemAtIndexPath(NSIndexPath(forItem: 25, inSection: 0), atScrollPosition: UICollectionViewScrollPosition.CenteredVertically, animated: false)
// 25 is just a number I have set for testing. Ultimately, I would like this to be the saved indexPath of the last tapped cell.
This causes the collectionView to "jump" to cell 25 once it's fully loaded. If I set animated to true, it loads at the top, then scrolls down to cell 25. Not my desired result.
I just want to be able to do 2 things here.
1 - Save the cell tapped as a variable.
2 - use scrollToItemAtIndexPath (with the variable in #1) so the view just loads up instantly with the last cell tapped right into the middle, No animations or anything.
Let me know if further clarification is needed. THANKS!
You could save the selected indexPathreceived when the collectionview cell is tapped and use it when required.
var selectedIndexPath: NSIndexPath?
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedIndexPath = indexPath
}
func scrollToCell(){
if let index = selectedIndexPath{
customViewCollectionView.scrollToItemAtIndexPath(index, atScrollPosition: .CenteredVertically, animated: false)
}else{
print("A cell hasnt been selected yet")
}
}

Swift - Button action not triggered in table view cell

I have a ViewController who contains a TableView. I want in each cell, a red button who did something (let's say 'hello' for test), or when I touch the cell anywhere but not on the button I perform a segue.
But even when I touch the button, it's the segue who perform. I tried some search on SF but none of the questions help me...
I don't know if that's usual but when I touch the cell, all the row white background become gray, even the background of the red button.
In storyboard I have this cell hierarchy :
The user interaction is enabled on both cell and button.
In the questions I found they said, on the cell set 'accessory' on 'disclosure indicator', I did it, but if it's possible I would like to keep it at 'None'.
Also I set a custom class for the cell, here is the code :
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var rentButton: UIButton? // I use this class for 2 tableview almost similar, but in the other I don't have the redButton, that's why I put an '?'
}
I also set the delegate and datasource of the tableView to my ViewController, here is the code of my view controller :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MyTableViewCell
cell.rentButton!.tag = indexPath.row
cell.rentButton!.addTarget(self, action: #selector(MyViewController.rent(_:)), forControlEvents: .TouchUpInside)
return cell
}
// Rent() is never called:
func rent(sender: UIButton) {
print("here \(sender.tag)")
}
EDIT : The solution was to put out the button from the conainer view !
You can stop the segue from actioning when the button is pressed by performing it programatically. You can do the following:
Remove your segue that goes from the cell to another view controller and change it go from the TableViewController to the other view controller
Create a variable in your TableViewController class such as: var buttonPressed = false
In your button action set buttonPressed to true
In didSelectRow, check that buttonPressed is not true then performSegue and change buttonPressed to false, else do nothing
As discussed, move the button from the container to the content view