Animate a slide-in details view within a UITableViewCell - ios

I have a UITableViewCell that is using auto-layout. When a user selects the cell, I want to display extra information in a details view that slides downwards, extending the bottom of the cell.
I'm having trouble figuring out the correct way to do this.
The transitionFromView:toView:duration:options:completion: method does not seem appropriate, because I am not replacing one view with another.
The transitionWithView:duration:options:animations:completion: method seemed like it should do the trick, but I can't figure out the correct way to achieve my goals using it.
This is what I tried initially (C#, but Objective-C/Swift equivalents should be obvious):
private void AnimateDetailsIntoView()
{
this.detailsView.Hidden = true;
this.ContentView.ConstrainLayout(() =>
this.detailsView.Top() == this.nameLabel.Bottom() &&
this.detailsView.Bottom() == this.ContentView.Bottom() - Layout.StandardSiblingViewSpacing &&
this.detailsView.Left() == this.nameLabel.Left() &&
this.detailsView.Right() == this.nameLabel.Right());
this.AddSubview(this.detailsView);
UIView.Transition(
this,
0.2,
UIViewAnimationOptions.ShowHideTransitionViews | UIViewAnimationOptions.TransitionFlipFromBottom,
() => { },
() => { });
}
This results in the table cell "spinning around", but the details view does not actually show. Even if I remove the line that hides detailsView, I still don't see it after the animation.
I suspect this is layout related, but am unsure how to "grow" the cell vertically.
Can anyone tell me what I'm doing wrong?
PS. I realize there's more to do once I get the initial animation working. I'll have to animate any previously selected cell up and remove its details panel.

As per the OP wants to expand and collapse the cell, following are the procedure to achieve it:-
Design your whole detail cell in a single prototype cell.
Now tableView heightForRowAtIndexPath: specify 2 sizes one for collapse cell and another size for (expanded)detailed cell,by giving a condition something like BOOL variable"isExpanded".
Now on didSelect of tableView or in the button's action if you are using button in cell, just store the value of indexpath.row to determine which row to expand and add this code to reload the row, this will easily do the animation trick of expand
[tbl beginUpdates];
[tbl reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationBottom];
[tbl endUpdates];
Same goes for collapsing a cell, just some logic tweaks, which you can easily do.

Related

Expand and collapse cells in tableview

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.

How to add unique insets to specific UITableViewCells?

I have a UITableView whose insetsContentViewsToSafeArea property is set to false - this makes the tableView span the width of the screen.
The amount and different types of cells are driven by the server, so there's no way of knowing the content of the tableView.
What I'd like to to:
Assign unique insets to certain cells only.
I can't post a screenshot, so I'll try to make a quick doodle:
These three cells are all in the same UITableView:
|[This is one cell that goes edge-to-edge]|
|[Here's another one]|
|-----This cell needs its own insets-----|
Question:
What's the best way to achieve this?
What I've tried:
Overriding layoutMarginsDidChange
Trying to add layoutMargins directly in cellForRowAtIndexPath...
Create a UITableViewCell subclass for the cell with custom insets.
Then you have 2 options --
Add a subview to cell's contentView with constraints -- these will correspond to your desired insets. This view will act as your " pseudo contentView" (add cell content to it)
Play around with contentView's insets. (not sure if it'll work)
I hope this will get you started.
You can use the cell subclass for all cell cases too if you want -- with an enum style which you can set in cell for row.
enum Style {
case edgeToEdge
case withInset(inset: UIEdgeInset)
}
inside cell subclass
var insetStyle: Style = .edgeToEdge {
didSet {
//update the constraints of the pseudo content view
}
}

Limit number of UICollectionView with dynamic sized cells

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)

scrollup uitablviewcell partially visible

I need some help.
That i want to scrollup uitalbeview cell which is partially
displaying.See screen shot.
Here my tableview has a three section and u can see that in morning
section the row is displaying partially.I just want to move up that
kind of row.
I tried content offset but not getting any idea that how to get first
visible row offset so,i can calculate and move it up or down
.
Note: not for bottom row only top rows.
This is the default behavior of a UITableView. The section headers will stick at the top of the screen until the next section header will reach it. One easy work around is to not use headers at all and simply use two cells. You would then have to add code in your viewForCellAtIndexPath:
if(indexPath.row == 0) {
//setup a header cell
} else {
//setup a data cell
}

UITableView.ScrollRectToVisible() doesn't scroll to bottom

I have a table view containing a variable amount of sections and custom cells. On some occasions, a cell may resize within RowSelected(). Whenever that happens, I'd like to also make sure the cell is completely visible after resizing (enlarging) it.
I have that working in another table that just modifies the underlying data so that the table view source will provide a larger cell. I then reload the cell and scroll it visible like so:
// Modify data
//...
// Reload cell
tableView.ReloadRows(new NSIndexPath[] { indexPath }, UITableViewRowAnimation.None);
tableView.ScrollRectToVisible(tableView.CellAt(indexPath).Frame, true);
The problem arises in a table view where resizing may not only be triggered by RowSelected(), but also by events on UI elements within the cells.
The events then call a method to reload the cell:
void updateCell() {
if (cell.Superview != null) {
UITableView tableView = (UITableView)cell.Superview;
tableView.ReloadRows(new NSIndexPath[] { indexPath }, UITableViewRowAnimation.None);
// Get the new (possibly enlarged) frame
RectangleF frame = tableView.CellAt(indexPath).Frame;
Console.WriteLine("This really is the new large frame, height: {0}", frame.Height);
// Try to scroll it visible
tableView.ScrollRectToVisible(frame, true);
}
}
This scrolls fine for all cells but the bottom-most. It only makes the old frame of that cell visible. I double-checked that it really provides the new cell frame to ScrollRectToVisible().
So it seems ScrollRectToVisible() is bound to the old content size of the table - even after reloading rows. I tried to work around that by providing a new content size with the calculated difference in height. That does work but feels really hackish to me.
Is there some cleaner way to do things?
Thanks in advance
Instead using this:
tableView.ScrollRectToVisible(_: animated: )
Use it to scroll UITableView to bottom row:
tableView.scrollToRow(at: at: animated: )

Resources