I am trying to achieve an effect that when detail button is pressed, details will slide in to ALL cells of tableView. So far I have achieved this trough iterating through the visible cells of the table view. Each cell has a detail label that is off screen that slides in with animation. This is how it looks:
Before Detail Button Pressed
After detail button pressed
Of cours since I am iterating through the visible cells, the cells at the bottom dont have the details when scrolling down after having pressed the detail button. I am aware of the fact that the cells that are not shown on screen is not in memory, but maybe there is an another approach to this?
EDIT
Here is the code that executes when user presses "Details" button
let animationDuration = 0.4
for cell in myTableView.visibleCells {
let cell = cell as! MainCell
if !detailView {
sender.tintColor = UIColor.gray
detailView = true
UIView.animate(withDuration: animationDuration, animations: ({
cell.noteLbl.center.x = cell.noteLbl.center.x + 100
}))
UIView.animate(withDuration: animationDuration, animations: ({
cell.accessoryLbl.center.x = cell.accessoryLbl.center.x + 100
}))
UIView.animate(withDuration: animationDuration, animations: ({
cell.timeLbl.center.x = cell.timeLbl.center.x + 100
}))
} else {
detailView = false
sender.tintColor = UIColor.white
UIView.animate(withDuration: animationDuration, animations: ({
cell.noteLbl.center.x = cell.noteLbl.center.x - 100
}))
UIView.animate(withDuration: animationDuration, animations: ({
cell.accessoryLbl.center.x = cell.accessoryLbl.center.x - 100
}))
UIView.animate(withDuration: animationDuration, animations: ({
cell.timeLbl.center.x = cell.timeLbl.center.x - 100
}))
}
}
Code for the cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainCell") as! MainCell
let shiftForRow = shifts[indexPath.section][indexPath.row]
cell.noteLbl.text = shiftForRow.note
cell.dateLbl.text = shiftForRow.date
cell.accessoryLbl.text = calcTotalHours(STField: shiftForRow.startingTime!, ETField: shiftForRow.endingTime!, lunchTime: shiftForRow.lunchTime!)
cell.timeLbl.text = shiftForRow.startingTime! + " - " + shiftForRow.endingTime!
return cell
}
As you scroll a table view (and when initially displayed), the cellForRowAt method is called for each cell that needs to be displayed.
At the moment your cellForRowAt only shows your cells in their "normal" layout as if the detail button has never been pressed. You need to update your cellForRowAt method so it configures the cell based on whether details should be shown or not.
You probably need a flag to track whether details are currently being shown or not. Toggle that flag based on the detail button being pressed.
Then, based on that state of that flag, your cellForRowAt method needs to setup the cell appropriately.
Related
No action is performed on UITableViewCell when blinking animation is implemented, it starts blinking that is fine but not clickable or swipable. I have tried some solutions but unable to fix it. Code is below.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.backgroundColor = UIColor.colorWithHexString(hexStr: "#FDFAEB")
cell.blink()
return cell
}
Animation extension code:
extension UIView {
func blink() {
self.alpha = 0.5;
UIView.animate(withDuration: 0.7, //Time duration you want,
delay: 0.0,
options: [.curveEaseInOut, .autoreverse, .repeat],
animations: { [weak self] in self?.alpha = 1.0 },
completion: { [weak self] _ in self?.alpha = 0.8 })
}
}
Please tell me, what is the reason, and how can I fix this?
By default user interaction is disabled during animations. you need to add the .allowUserInteraction option to your set of options.
(And note that if you're animating a view's position the user won't be able to tap on the view as it moves. Behind the scenes, a view jumps to it's destination position as soon as the animation begins. It only appears to move across the screen. If you want to handle tapping on a view as it moves across the screen it's a lot more complicated.)
I am making an app using swift.
I have a UITableView consisting of 5 different rows.
I have a UILabel on each row of the table. (This label provides the title of the row)
This UILabel is animated so it enters the screen from left to right on each row.
My problem is that when I run my animation all 5 UILabels enter their row at the same time. I want to put a delay between the each UILabels animation. That is I want the UILabel on the first row to enter the screen first, then 1 second later I want the UILabel on the second row to enter the screen, then 1 second later the 3rd UILabel ...etc.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell!
let imageView = cell.viewWithTag(1) as! UIImageView
imageView.image = UIImage(named: imageArray[indexPath.row])
let imageText = cell.viewWithTag(2) as! UILabel
imageText.text = sectionName[indexPath.row]
imageText.textAlignment = .Center
//starting position for animation of imageText
imageText.center.x = self.view.frame.width - 500
//animating UILables comming into screen
UIView.animateWithDuration(3, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [], animations: ({
imageText.center.x = ((self.view.frame.width) / 1)
}), completion: nil)
return cell
}
Add a delay based on the index path. The 1 in the delay is the number of seconds you want between animations.
let delay = 1 * indexPath.row
UIView.animateWithDuration(3, delay: delay, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [], animations: ({
imageText.center.x = ((self.view.frame.width) / 1)
}), completion: nil)
I'm assuming that the 5 rows are all that the table view will need to display and that all are on screen at all times, meaning, you don't need to consider how to handle the animation as the rows scroll. If scrolling is a consideration, then this will likely need to change to only animate in when the table view is initially displayed.
I'm adding simple stack animation to my tableViewCell which animates like cells are being add to a stack. When I tap the UIButton that segues me to the tableView I first see a static cell which has my values and then after a small gap my animation works. I don't know why my tableView shows that cell before animation ? Here is my code for the VC :
override func viewDidAppear(_ animated: Bool) {
animateTable()
}
func animateTable() {
let cells = tableView.visibleCells
let tableHeight: CGFloat = tableView.bounds.size.height
for i in cells {
let cell: UITableViewCell = i as UITableViewCell
cell.transform = CGAffineTransform(translationX: 0, y: tableHeight)
}
var index = 0
for a in cells {
let cell: UITableViewCell = a as UITableViewCell
UIView.animate(withDuration: 1, delay: 0.05 * Double(index), usingSpringWithDamping: 0.9, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
cell.transform = CGAffineTransform(translationX: 0, y: 0);
}, completion: nil)
index += 1
}
}
When your view appears, it would have the UITableView data already populated via a call to reloadData. You do the animation only after the view appears. So at that point, you'll see the existing data for a fraction of a second and then the animation would kick in.
If you don't want the data to appear at all before the animation runs, you might want to not show data as soon as the view loads by doing something like the following - this might not be the best solution, but it is the easiest to implement:
1: Add a new variable to indicate whether you've run the animation or not.
var wasAnimated = false
2: Check this variable in numberOfRowsInSection and return 0 if the animation has not run yet.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if !wasAnimated {
return 0
}
// Rest of the original code
}
3: Set the flag at the beginning of animateTable and then reloadData before you execute the rest of the animation code.
func animateTable() {
wasAnimated = true
tableView.reloadData()
// The rest of the original code
}
That should get you the behaviour you wanted :)
I have a UITableView that detects a swipe from left to right. I want to show a delete button when the user does the swipe by changing the constant of the width constraint on it. But no matter what I try to do the button won't animate or change width at all. The only way I can get the button to display the constraint change is by reloading the row.
This is what I have right now. Every answer I see contains this method of animating constraints.
func TableViewSwipeRight(gesture: UIGestureRecognizer)
{
let point = gesture.location(in: favoriteStationsTableview)
let indexPath = favoriteStationsTableview.indexPathForRow(at: point)
if let indexPath = indexPath {
if let favoriteCell = favoriteStationsTableview.dequeueReusableCell(withIdentifier: FavoriteCell.GetReuseId(), for: indexPath) as? FavoriteCell {
self.view.layoutIfNeeded()
favoriteCell.deleteBtnConstraint.constant = 50
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})
}
}
}
You need to get the cell at the given indexPath and not dequeue it (as it won't be part of the tableview at this point.)
if let indexPath = indexPath {
if let favoriteCell = favoriteStationsTableview.cellForRowAtIndexPath(indexPath) as? FavoriteCell
{
}
I haven't been able to find any examples of this online. How can I achieve the following effect? Instead of the standard slide-to-left effect when tapping a table row, I'd like the view controller transition animation to look like the following:
User taps a cell in the table
The cell starts growing to fill the screen, pushing other rows above and below it "offscreen".
As the cell grows, cells elements (text, images, etc.) cross-fade into the new view's contents until the new view completely fills the screen.
I'd like to also be able to interactively transition back into the table view by dragging up from the bottom edge, such that the reverse of the above is achieved. i.e. view starts shrinking back into a normal table view cell as the "offscreen" cells animate back into position.
I've thought about taking a snapshot of the table and splitting it up at the points above and below the cell, and animating these snapshots offscreen as part of a custom view controller transition. Is there a better way? Ideally I'd like to not take snapshots, as I may want to have animations, etc., still happening in the table view rows as they fade offscreen.
First thing first, i have seen your post today and his is written in swift programming language.
the follwing code is to expand the selected cell to the full screen, where the subviews will fade out and background image will expands.
First complete cellForRowAtIndexPath, then in didSelectRowAtIndexPath,
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
isSelected = true
selectedCellIndex = indexPath.row
tableView.beginUpdates()
var cellSelected: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cellSelected.frame = tableCities.rectForRowAtIndexPath(indexPath)
println("cell frame: \(cellSelected) and center: \(cellSelected.center)")
let newCell = cellSelected.frame.origin.y - tableOffset
println("new cell origin: \(newCell)")
var tempFrame: CGRect = cellSelected.frame
variableHeight = cellSelected.frame.origin.y - tableOffset
tempFrame.size.height = self.view.frame.height
println("contentoffset: \(tableView.contentOffset)")
let offset = tableView.contentOffset.y
println("cell tag: \(cellSelected.contentView.tag)")
let viewCell: UIView? = cellSelected.contentView.viewWithTag(cellSelected.contentView.tag)
println("label: \(viewCell)")
viewCell!.alpha = 1
UIView.animateWithDuration(5.0, delay: 0.1, options: UIViewAnimationOptions.BeginFromCurrentState, animations: {
tableView.setContentOffset(CGPointMake(0, offset + self.variableHeight), animated: false)
tableView.contentInset = UIEdgeInsetsMake(0, 0, self.variableHeight, 0)
tableView.endUpdates()
cellSelected.frame = tempFrame
viewCell!.alpha = 0
println("contentoffset: \(tableView.contentOffset)")
}, completion: nil)
}
then update your heightForRowAtIndexPath, as
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if isSelected && (selectedCellIndex == indexPath.row) {
return self.view.frame.height
}else {
return 100
}
}
Ignore this if already solved. and this might be helpful to others.