I have two questions :
1- Is it possible to know if a cell indexPath.row has changed in a UITableView ? for example if I have an element at index (0) and then I add another one, the first element will be at index (1). Is it possible to detect this change ?
2- Is it possible to fnd the index of an element by the cell title ? for example I have X,Y,Z element in the tableview and I want to know in which cell 'X' is placed ?
thanks guys,
Generally speaking, it's common practice to isolate model and view. What I mean by this, is separate the storage of the data and the view that's rendering it.
For example, you may be creating a table view of color names. Therefore, you could store an array of color names as a property of your view controller
class UIColorViewController: UITableViewController{
let colors = ["Black", "Blue", "Yellow"]
As I'm sure you're doing, you can assign the view controller as the data source of the table view so you can tell it how many sections you want, the number of rows you want in a section, and what to render onto a cell.
In this elementary example, the number of sections could be 1 and the number of rows in this section would be the length of the colors array. Now when rendering data onto the cell, you simply index the colors array by the index path.
fun tableView(UITableView, cellForRowAt: IndexPath){
var color = colors[indexPath.row]
cell = //dequeue cell
cell.textLabel?.text = color
return cell
}
So by separating the data from the view, if you want to find what cell a particular value is at, you can simply search through the array where the color is at and the index returned would be equivalent to what cell this color is or will be at depending on if that cell has been rendered onto the screen yet.
For example using the colors array, if I were looking for "Blue"
for (index, color) in self.colors.enumerated{
if color == 'Blue'{
print("Found Blue at index \(index)")
}
}
When you want to add a cell or delete a cell, you simply modify the colors array which is storing the model data, perform the appropriate table view related action, and the invariant remains that the index of the color in the array would be equivalent to the index of the cell in the table view.
Related
I have a tableview. Some cells contain images, other text.
I want to be able to collapse and expand the cells. In order to be able to do so I did the following:
I created a variable isExpanded = true
In cellForRowAt I check if the cell contains text and then...
if textIsExpanded {
cell.textLabel?.sizeToFit()
cell.textLabel?.numberOfLines = 0
}
so that the cell can be as tall as the text inside of it.
In the action I toggle textIsExpanded and reload the table:
textIsExpanded.toggle()
table.reloadData()
This procedure perfectly works with tableviews only containing text.
Something that would work was expanding the if statement and in the false branch calling:
cell.textLabel?.invalidateIntrinsicContentSize()
cell.textLabel?.layoutIfNeeded()
BUT this doesn't work when I toggle the variable, this only works on launch.
How can I collapse and expand back the cells in my tableview?
Create your cell with a stack of two views, Upper view and lower View, Add a Bool key to your Model isExpandable that is triggered and changed on didSelect and check on this to hide or show your view, EIther keep the text as text or TextView up to you.
I have a UICollection View and am creating a custom animation when a user taps on a cell.
There are three columns in the collection view. Is there a quick way to figure out, given a index path, the column that was tapped?
If you have a single section, you can just use modulo arithmetic on the item of the index path.
let column = indexPath.item % 3 // gives a value from 0 to 2
Yes. Assuming you setup the columns as sections in the collection view, you should just be able to check the section of the indexpath.
An IndexPath is primarily made of two parts, a row, and a section. If you have 3 sections than indexPath.section == 0 is the first column, indexPath.section == 1 is the second, and indexPath.section == 2 is the third
I need to display a dynamic table view inside a cell (of a static table). Using sections instead will not be enough for me. But I don't want this table to be scrollable, so the entire table must appear at once. The problem is that this table size [and rows count, and each row size] varies according to the content being shown. How can I associate the cell (which holds the table) autoresizing property with a table inside that must show all content at once?
Currently I have the tableView inside the cell, and constraints bonds it to all the 4 sides. The first table (not the one inside the cell) rowHeight property is set to UITableViewAutomaticDimension, but the table inside the cell doesn't appear entirely.
If I set the static cell height to a value greater than the tableView(inside cell) height, the whole table appears, and also an extra space beneath it (as the table is bounded to 4 sides of the cell)
So, any ideas on how to show this entire table inside a cell that dynamically has the perfect size for it ?
ps: I tried using collection view inside the cell. Unfortunately it doesn't serve my purpose.
Thanks!
Update
I tried to create a class for the inner table and use (as pointed by iamirzhan) contentSize didSet, like so:
override var contentSize:CGSize {
didSet {
self.invalidateIntrinsicContentSize()
}
}
I then used this method to call a function that resizes the cell that holds the table: self.frame.size.height = table.contentSize.height. The function is on this cell's own class.
This worked, the table now appears entirely. The problem is that it overlaps the cell underneath it, so i'm still looking for a solution.
I don't see why this requires 2 tableviews. The static portion should be uitableviewheaderfooters or just a UIStackView. But to answer your question simply query your child tableView for its size and return this in tableView:heightForRowAtIndexPath: for the outer tableview. The height of the child tableView is simply the sum of the hieght of all of its children (including any headers/footers). This is usually not difficult to calculate unless you are using something like a webview where you need to actually load the content and get the size asynchronously. You can calculate the size of elements that are based on their intrinsic content size with UIView.sizeThatFits(_:). The other elements should have fixed sizes or constants in the storyboard that you can sum up.
For inner tableView you should write such implementation.
Firstly, disable the scrollEnable flag
Then you should override the intrinsicContentSize method of tableView
Your inner tableView custom class:
class IntrinsicTableView: UITableView {
override var contentSize:CGSize {
didSet {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
}
Now, delete the height constraint, and the height will be calculating by its content.
I have a view which displays the music interests that a user has. Since the text of each interest can be different in length, I have used a UICollectionView to render these items.
The problem is that I would like to limit the size of the list to just 7 lines. If there is more items than can fit, I need to show an item [...] at the end to indicate that there is more items.
In the example above, I would change the word "Grimes" for "...".
Is there any way, with dynamic sized UICollectionView cells, to know HOW MANY items fit into the given space, before it gets rendered on the screen, and thus be able to change the last item to "..." (either by removing the extra items and adding a new one, or by updating the last cell title).
You could also handle it after the fact by allowing the collectionview to lay itself out and determine it's last cell, then grab the last cell in the collectionView's .visibleCells array.
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadData];
} completion:^(BOOL finished) {
UICollectionViewCell *targetCell = self.collectionView.visibleCells.lastObject;
targetCell.backgroundColor = [UIColor blueColor];//or whatever needs to change
}];
I assume you already have a method to calculate the dimension of each item. It's not that hard to implement this behavior by yourself.
You need a method to estimate the size (or rows) needs for a list of items. Something like:
func preProcessList(originalList: [Item]) -> (displayList: [Item], needThreeDots: Bool)
I'm working with a UITableView, and as far as I understand it has grey or blue selection of rows. Is there a way to override UITableView cell selection behavior (define a "selected" style)?
If there is not, would a vertical collection view work as an imitation of a table view with custom selection?
According to the UITableViewCell Class reference, you are limited to:
UITableViewCellSelectionStyle
The style of selected cells.
Declaration
SWIFT
enum UITableViewCellSelectionStyle : Int {
case None
case Blue
case Gray
case Default
}
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewCell_Class/#//apple_ref/swift/enum/UITableViewCellSelectionStyle
So you would have to develop your own custom action on selection to change the background color.