collectionview in tableviewcell. when tableview reuse cell. collectionview in tableivewcell keep position. this is bug? and how to separate for it. example : cell 1 and cell 10 is collectionview(horizontal). when i scroll cell 1, cell 10 also scroll same postion. please help me.
Create a Dictionary to remember the offset for each cell like:
var contentOffset: [Int: CGFloat] = [:]
When table view cell is being removed from screen store the offset of your collection view like
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? YouTableViewCell else {
return
}
contentOffset[indexPath.row] = cell.collectionView.contentOffset.x
}
Now when cell is about to display restore the content offset like:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? YouTableViewCell else {
return
}
cell.collectionView.contentOffset.x = contentOffset[indexPath.row] ?? 0
}
It is not a bug, when table cell being reused, it also reuse the content which is the collection view which is scrolled. Keep Googling and check out the links:
ios 8 Swift - TableView with embedded CollectionView
https://medium.com/#gargankit476/multiple-collection-view-in-uitableview-ced7909a5af3
Related
I'm having trouble with swiping between accessibility elements in a UITableView with VoiceOver on. When in a UITableView, the next/previous element in the table is focused when the user swipes right/left. The element is usually a UITableViewCell.
But I have custom cells that use subviews of the cell as accessibility elements, as in:
cell.isAccessibilityElement = false
cell.accessibilityElements = [element1, element2];
This works perfectly fine within the cell, but there's a problem swiping between cells. If the custom cell is at the bottom of the table view, it fails to focus on the next cell in the table view. Normally, using the cells themselves as accessibility elements, the table view will auto-scroll and focus on the next cell. But after the custom cell, it doesn't auto-scroll, as if there are no more cells in the table view.
See screenshot for clarification. When Label 9 is focused, the user can't swipe right to the next cells, even though there are more cells. They can still scroll though using 3 fingers, and then they'll be able to swipe to the next cells as normal.
This problem happens when using the code below. It uses a storyboard that only has a default UITableView with a default prototype cell with some UILabels added to it. So all the accessibility stuff is done here in the code.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let customRow = 5
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == self.customRow {
return UITableView.automaticDimension
} else {
return 120
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell
if indexPath.row == self.customRow {
cell = self.tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath)
cell.isAccessibilityElement = false
cell.accessibilityElements = cell.contentView.subviews
} else {
cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
var content = cell.defaultContentConfiguration()
content.text = "row \(indexPath.row)"
cell.contentConfiguration = content
}
return cell
}
}
I have a tableView and cells. The Cells are loaded from a xib and they have a label with automatic height. I need to narrow one cell if the user taps on it.
I have tried hiding - doesn't work
I have tried removeFromSuperView()- doesn't work
Is there any alternative?
When setting up your tableViewCell store the height anchor you want to update
var yourLabelHeightAnchor: NSLayoutConstraint?
private func setupLayout() {
yourLabelHeightAnchor = yourLabel.heightAnchor.constraint(equalToConstant: 50)
// Deactivate your height anchor as you want first the content to determine the height
yourLabelHeightAnchor?.isActive = false
}
When the user clicks on a cell, notify the tableView that the cell is going to change, and activate the height anchor of your cell.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourTableViewCellIdentifier") as? YourCell
self.tableView.beginUpdates()
cell?.yourLabelHeightAnchor?.isActive = true
self.tableView.endUpdates()
}
Did you try to do something like this:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var result: CGFloat
if (indexPath.row==0) {
result = 50 }
else {result = 130}
return result
}
This is just an example where height is changed for the first row. I tested on my application and it gave result like this.
I have collection view as rows of a tableview. The collection view only supports horizontal scrolling. When I scroll to the end of the collection view in the first row, and then scroll to the bottom of the tableview. The last collection view is also at the end position when I haven't even touched that yet.
I know that the issue is because of dequeueReusableCell of the tableview. I have tried using the prepareForReuse() in UITableViewCell.
I expect that whenever any other row of the table view should remain unaffected by the interaction done on rest of the table view rows.
You could store (and restore) the collection views' content offsets by using the table view's delegate methods:
var xOffsets: [IndexPath: CGFloat] = [:]
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
xOffsets[indexPath] = (cell as? TableViewCell)?.collectionView.contentOffset.x
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
(cell as? TableViewCell)?.collectionView.contentOffset.x = xOffsets[indexPath] ?? 0
}
Requirement :
I have a list of UITableviewCell loaded from a nib that I'm presenting on UITableview. The first time I open the UIViewController all cells are shown correctly and work as expected.
Issue :
If I navigate back to the parent and then open the UIViewController again the UITableviewCell are 'invisible'. I say invisible because with a breakpoint in cellForRowAt I can see that the table view does load all cells and the cells are valid.
Code :
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 13
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (project?.sliderData.sliders[indexPath.row].view)! as UITableViewCell
print(cell.contentView.subviews.count)
if let left = cell.viewWithTag(2) as? UILabel {
left.text = "left"
}
if let middle = cell.viewWithTag(3) as? UILabel {
middle.text = "middle"
}
if let right = cell.viewWithTag(4) as? UILabel {
right.text = "right"
}
return cell
}
Screen Shot Image
Expected observation :
I was thinking that maybe the subviews of the cells get released because I don't have any bindings to them in IB. To test this I'm printing the count of subviews and writing some text to the subview labels. And everything seems to go fine, the cells are loaded and the labels are there but the cells just don't show up.
But then, if I scroll the TableView up and down a little to get some cells updated those cells do appear at the top and bottom of the view as shown in the pic.
You need to call dequeueReusableCell(withIdentifier: "cell") inside your code then will show your table cell. It will reuse cell for your all numbers of row data content.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! UITableViewCell
return cell
}
More Details : How to create uitableview with multiple sections in iOS Swift.
Did not find reason why the tableView behaves the way it does so I solved the issue by dequeueing default cells. The views provided by the slider objects are added as subviews to the dequeued cells. Now the subviews can of course be any UIViews.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "sliderCell")
if cell == nil {
cell = UITableViewCell.init(style: .default, reuseIdentifier: "sliderCell")
}
cell?.addSubview((project?.sliderData.sliders[indexPath.row].view)!)
return cell!
}
I'm trying to implement an expanding cell using this
here is my heightForRowAt indexPath
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0 : return 70
case 1 :
let cell = self.tableView(tableView, cellForRowAt: indexPath)
if let datePickerCell = cell as? MyDatePickerCell {
return datePickerCell.datePickerHeight()
}
return 260
case 2 : return 80
default : return 60
}
}
The app gets stuck at
let cell = self.tableView(tableView, cellForRowAt: indexPath)
the UITableView is embeded in a modal UIViewController
why is this happening?
I think what is happening is that your tableView is looking for the heights of your cells before loading them in the first place. So you are trying to retrieve the cell before it is loaded, causing a crash.
To fix this you could create a dummy cell before loading the tableView and using that cell in heightForCell. That's more applicable for calculating variable heights for each cell though. In this case maybe hardcode the start height and then use the cell for heights after that.