I would like to resize my tableView cell when the user selects a row, the cell becomes smaller then larger again. This is what I have tried so far:
#pragma mark UITableView Delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// My animation
cell.contentView.transform = CGAffineTransformMakeScale(0.95,0.95);
cell.contentView.alpha = 1.f;
[UIView beginAnimations:#"button" context:nil];
[UIView setAnimationDuration:0.2];
cell.contentView.transform = CGAffineTransformMakeScale(1,1);
cell.contentView.alpha = 1.0f;
[UIView commitAnimations];
}
This is my tableView data source:
#pragma mark UITableView Datasource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Set up cell
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.font = [UIFont fontWithName:#"HelveticaNeue" size:21];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.highlightedTextColor = [UIColor lightGrayColor];
cell.selectedBackgroundView = [[UIView alloc] init];
}
// Images in my cell
NSArray *images = #[#"Songs", #"Albums", #"Artists", #"Playlists"];
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:images[indexPath.row]]];
cellImage.frame = CGRectMake(0, 0, 90, 90);
[cell addSubview:cellImage];
return cell;
}
But this does not work. The image in the cell simply stays the same size. Any ideas? Thanks.
I seriously advise going with a UICollectionView for something like this. With it, you only have to call performBatchUpdates and you can put any frame setting inside of it's block. It's practically magic!
I don't know if you can or should do what you ask about, but if you can it would probably be with a custom UITableViewCell. But, you might be able to fake it with a custom cell, maybe with a UIView that holds all the cell's contents. The UIView would animate inside the cell, and if you are not showing separators on the table it could look like the cell itself is animating. So basically you're hiding the actual cell, and using a UIView in the cell to simulate animating the cell. Maybe like this:
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.customCell.frame = CGRectMake(110, 20, 100, 20);
} completion:^(BOOL finished) {
[UIView animateWithDuration:SLIDE_TIME delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.customCell.frame = CGRectMake(0, 0, 320, 60);
} completion:^(BOOL finished) {
}];
}];
Related
I am trying to put animation in a UITableViewCell. Animation is that onClick table view cell change the frame of tableCell into tableview frame.
I have the following code:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell*cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell*cell = [tableView cellForRowAtIndexPath:indexPath];
if(cell.frame.size.height == tableView.bounds.size.height){
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}else{
cell.frame = tableView.bounds;
[[cell superview] bringSubviewToFront:cell];
}
[UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.5 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
}
It works fine but after change cell's frame I am able to tap another cells also which I don't want. How can I achieve this?
One of the possible solution would be to declare a variable that will hold an array of indexPath of expanded cell like this
// Will hold the indexPath of expanded cell
var expandedCell : [IndexPath] = []
Second thing would be adding and removing the the cell that are/aren't expanded and to do that you have to update your UITableView Delegate didSelectRowAt
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let index = expandedCell.firstIndex { (localIndexPath) -> Bool in
return indexPath == localIndexPath
}
if let index = index {
expandedCell.remove(at: index)
} else {
expandedCell.append(indexPath)
}
tableviewMessageList.reloadRows(at: [indexPath], with: .fade)
}
And in the end you have to add another UITableView Delegate heightForRowAt to return the height of the cell if the cell's indexPath is in array it will return the expanded size else return the normal size of your cell like this:-
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if expandedCell.contains(indexPath) {
return tableView.frame.height
}
return 200.0 //NormalHeight
}
Note: My answer is in Swift but the same principle will apply for Objective-C you just need to change the Syntax.
Overall, I think a better approach to this would be to use a separate view to display the cell details full screen, although you may have some restrictions that require you to do it this way. That being said, find my answer below.
This is what I gather your current problem is:
You'd like to show the cell expanded, and when in that expanded state touches are going through the cell view and hitting the table view behind it and re-triggering didSelectRowAtIndexPath: tableview delegate method (on other cells than the expanded one).
These are a couple of the possible solutions I see:
Add a tap gesture recognizer to the cell when it's expanded so it will absorb the touch, then remove the gesture recognizer once it's consumed.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapOnExpandedCell:)];
[cell addGestureRecognizer:tap];
cell.frame = tableView.bounds;
[[cell superview] bringSubviewToFront:cell];
UIView *bgView = [[UIView alloc] init];
bgView.backgroundColor = [UIColor purpleColor];
cell.selectedBackgroundView = bgView;
[UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.5 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
-(void)didTapOnExpandedCell:(UIGestureRecognizer *)recognizer {
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.tableView.indexPathForSelectedRow];
// do whatever you were planning on doing when tapping on the
// expanded cell
[self.tableView reloadRowsAtIndexPaths:#[self.tableView.indexPathForSelectedRow] withRowAnimation:UITableViewRowAnimationNone];
[cell removeGestureRecognizer:recognizer];
}
Subclass UITableViewCell and override touchesBegan:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
R4NTableViewCell *cell = (R4NTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.frame = tableView.bounds;
[[cell superview] bringSubviewToFront:cell];
UIView *bgView = [[UIView alloc] init];
bgView.backgroundColor = [UIColor purpleColor];
cell.selectedBackgroundView = bgView;
[UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.5 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
// in R4NTableViewCell.m implementation override touchesBegan
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// if we're not selected, don't intercept the touch so the tableview can handle it
// calling back to super will give the default tableview behavior and get our delegate callback
if (self.selected == NO) {
self.frameBeforeExpansion = self.frame;
[super touchesBegan:touches withEvent:event];
} else { // we're in the expanded state so intercept the touch
NSSet <UITouch *> *singleTouches = [[event allTouches] objectsPassingTest:^BOOL(UITouch * _Nonnull obj, BOOL * _Nonnull stop) {
return obj.tapCount == 1;
}];
if (singleTouches.count > 0) {
// the user single tapped our view
[UIView animateWithDuration:1.0 delay:0.0 usingSpringWithDamping:0.7 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.frame = self.frameBeforeExpansion;
[self.superview layoutIfNeeded];
} completion:^(BOOL finished) {
[self setSelected:NO];
self.backgroundView.backgroundColor = [UIColor greenColor];
}];
}
}
}
One additional thing I didn't really understand from your explanation (as the comments mentioned) is what you expect to happen when the user taps the expanded tableview cell.
I have a tableviewcontroller and a custom cell. What i wanna do is when i tap the cell, the cell is supposed to exapand and a view (graph view actually) is supposed to become subviewed inside the cell. Now the problem is that everything works fine but the graph is duplicated on some other cells as well.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ProductsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (cell == nil)
{
NSLog(#"empty cell");
}
//Product Label
cell.productNameLabel.text = #"something";
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPathforChart = indexPath;
[self performSelector:#selector(addChart:) withObject:indexPath afterDelay:0.2];
[tableView beginUpdates];
[tableView endUpdates];
[tableView scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionTop animated:YES];
}
-(void)addChart:(NSIndexPath*)indexPath
{
BEMSimpleLineGraphView *myGraph = [[BEMSimpleLineGraphView alloc] initWithFrame:CGRectMake(0, 60, screenSize.width, 200)];
myGraph.dataSource = self;
myGraph.delegate = self;
myGraph.interpolateNullValues = YES;
myGraph.enableTouchReport = YES;
myGraph.tag = 100;
myGraph.animationGraphStyle = BEMLineAnimationDraw;
myGraph.enablePopUpReport = YES;
myGraph.enableXAxisLabel = YES;
myGraph.colorXaxisLabel = [UIColor darkGrayColor];
ProductsTableViewCell *cell = (ProductsTableViewCell*)[self.tableView cellForRowAtIndexPath:indexPath];
[cell.contentView addSubview:myGraph];
[cell setNeedsLayout];
[cell setNeedsDisplay];
myGraph.colorTop = [UIColor clearColor];
myGraph.colorBottom = [UIColor clearColor];
myGraph.colorLine = [UIColor darkGrayColor];
myGraph.colorPoint = [UIColor lightGrayColor];
}
This is caused by cell re-use.
ProductsTableViewCell *cell = (ProductsTableViewCell*)[self.tableView
cellForRowAtIndexPath:indexPath];
[cell.contentView addSubview:myGraph];
You added myGraph as a subview in the cell without removing it when the cell is re-used by some other index path while you scroll the table view.
The most appropriate way should be having a custom view inside the cell for drawing your graph, instead of adding/removing the graph view when needed. For the sake of scrolling performance, you may also cache the graph in case it will be used when user scrolls back and forth.
Cells are reused, so before loading a new cell you should implement the method prepareForReuse and add/remove or hidden/unhidden the views your cell requires.
So basically, ProductsTableViewCell should implement the method prepareForReuse. The easiest way to remove your BEMSimpleLineGraphView based on your code would be:
- (void) prepareForReuse{
UIView *v = [cell.contentView viewWithTag:100];
if ( v ) {
[v removeFromSuperView];
}
}
However, I don't consider using viewWithTag is the best solution so I would change the code into something similar to:
tableviewcontroller
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ProductsTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
[cell addChart];
[tableView endUpdates];
[tableView scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionTop animated:YES];
}
ProductsTableViewCell
#interface DLSContactUsViewController ()
#property (strong,nonatomic) BEMSimpleLineGraphView *myGraph;
#end
-(void)addChart
{
if ( ![self.myGraph isDescendantOfView] ){
[self.contentView addSubview:self.myGraph];
[self setNeedsLayout];
[self setNeedsDisplay];
}
}
- (BEMSimpleLineGraphView*) myGraph{
if ( !_myGraph ) {
_myGraph = [[BEMSimpleLineGraphView alloc] initWithFrame:CGRectMake(0, 60, screenSize.width, 200)];
_myGraph.dataSource = self;
_myGraph.delegate = self;
_myGraph.interpolateNullValues = YES;
_myGraph.enableTouchReport = YES;
_myGraph.tag = 100;
_myGraph.animationGraphStyle = BEMLineAnimationDraw;
_myGraph.enablePopUpReport = YES;
_myGraph.enableXAxisLabel = YES;
_myGraph.colorXaxisLabel = [UIColor darkGrayColor];
_myGraph.colorTop = [UIColor clearColor];
_myGraph.colorBottom = [UIColor clearColor];
_myGraph.colorLine = [UIColor darkGrayColor];
_myGraph.colorPoint = [UIColor lightGrayColor];
}
return _myGraph;
}
- (void) prepareForReuse{
if ( [self.myGraph isDescendantOfView] && !self.isSelected ) {
[myGraph removeFromSuperView];
}
}
I'd like to have a slide in from bottom animation on my UITableview when the View appears. So inside the viewDidAppear Methode I created the following Animation
[UIView animateWithDuration:10.0f // for testing purposes big value
delay:0.0f
usingSpringWithDamping:0.7f // 0...1
initialSpringVelocity:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[tv_team setAlpha:1.0f];
tv_teamsVerticalConstraint.constant = 0;
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
}
];
that works perfectly fine for the UITableView itself, however I dynamically add labels and buttons to each UITableViewCell like so
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"teamCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
//}
[cell.contentView setBackgroundColor:[[ColorSchema sharedColorSchema] color_background]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
UIView *vw_centered = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 480, 70)];
vw_centered.autoresizingMask = (
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin
);
[vw_centered setBackgroundColor:[[ColorSchema sharedColorSchema] color_darkerbackground]];
[vw_centered.layer setCornerRadius:5.0f];
[vw_centered setTag:1];
//... more Labels
// Button to change the teamMembers
UIButton *btn_setPlayers = [UIButton buttonWithType:UIButtonTypeCustom];
btn_setPlayers.frame = CGRectMake(340.0, 39.0, 120.0, 19.0);
[btn_setPlayers setBackgroundColor:[[ColorSchema sharedColorSchema] color_darkgray]];
[btn_setPlayers setTag:indexPath.row];
[btn_setPlayers.titleLabel setFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:9.0]];
[btn_setPlayers setTitleColor:[[ColorSchema sharedColorSchema] color_orangeSolid] forState:UIControlStateNormal];
[btn_setPlayers setTitle:#"Change Team Members" forState:UIControlStateNormal];
[btn_setPlayers addTarget:self action:#selector(changeTeamMembers:) forControlEvents:UIControlEventTouchUpInside];
[btn_setPlayers.layer setCornerRadius:5.0f];
[vw_centered addSubview:btn_setPlayers];
[cell.contentView addSubview:vw_centered];
return cell;
}
problem is, that the created button slides in from the left until it reaches the frame location on the second, third, ... cell (not the first - probably because thats the prototype cell)
How can I stop that animation?
im running xcode 6 ios 8.1
You can avoid unwanted animations by wrapping the changes in performWithoutAnimation:
[UIView performWithoutAnimation:^{
// changes
}];
So try setting your button's frame in one of these.
i have this code, I want to animate this. Some one helps me please.? When i run the code it shows it normally !! i just want to show it as an animated textLabel. which slowly comes in.
somebody please help me out, there is animation property for cell.ImageView is available. but not for textLabel.
cell.textLabel.frame = CGRectMake(55, 143, 88, 24);
i tried this , but its not working,
[UIView animateWithDuration:0.036 animations:^{
cell.textLabel.frame = CGRectMake(55, 143, 88, 24);
} completion:nil];
[UIView commitAnimations];
May be you are looking for,
[UIView animateWithDuration:0.25 animations:^{
cell.textLabel.frame = CGRectMake(55, 143, 88, 24);
}];
[UIView animateWithDuration:0.25 animations:^{
cell.textLabel.frame = CGRectMake(55, 143, 88, 24);
//You should force them to layout subviews again
[cell layoutSubviews];
}];
The alpha property of a UILabel is animatable. You can set the alpha to be 0 (totally transparent) when you create it, and then animate the alpha to 1.0 (totally opaque). This can be achieved like this:
First set the alpha of your cells textLabel to 0.0 in tableView:cellForRowAtIndexPath:, as well as whatever other code you want here as well.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"Cell %lu", indexPath.row];
cell.textLabel.alpha = 0.0;
return cell;
}
Then you can animate it with a class method on UIView called animateWithDuration. I put it didSelectRowAtIndexPath just for this example, but you should be able to do it wherever you need to.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[UIView animateWithDuration:1.0 animations:^{
cell.textLabel.alpha = 1.0;
}];
}
How do I create a good looking drop down menu in iOS. It should open when the user clicks a button in the navigation bar.
I tried creating a table, but got the error Static table views are only valid when embedded in UITableViewController instances. If I use UITableViewController, then it has to be full width.
Maybe you could try using a CollectionView instead of TableView, and if you need sopport for iOS 4+, PSTCollectionView is a good option :)
What I did is added a Button and on button tap one table view is shown, whenever any row is selected that row title is set to button title.
- (void)addOrganizationButton {
self.organizationButton = [UIUtils createButtonWithFrame:CGRectMake(203,115,451,38)
titleText:#"Organization"
type:UIButtonTypeCustom
normalImage:nil selectedImage:nil
target:self
view:self.registerView
tag:0
selector:#selector(organizationButtonTap)];
self.organizationButton.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
[self.organizationButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
self.organizationButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
self.organizationButton.layer.borderWidth = 1;
}
//Show table view on button tap
- (void)organizationButtonTap {
self.organizationTable = [[UITableView alloc]initWithFrame:CGRectMake(203,153, 451,220)];
self.organizationTable.layer.borderWidth = 1;
self.organizationTable.dataSource = self;
self.organizationTable.delegate = self;
[UIView animateWithDuration:1
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
CGRect frame = self.organizationTable.frame;
frame.size.height = 220;
self.organizationTable.frame = frame;
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
[self.registerView addSubview:self.organizationTable];
}
//Table view delegates
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;//to be changed
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return 3;//get dictionary count
}
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
NSString *cellIdentifier=#"Cell Identifier";
cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil){
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.textLabel.text = [NSString stringWithFormat:
#"Section %ld, Cell %ld",
(long)indexPath.section,
(long)indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.organizationButton setTitle:#"faf" forState:UIControlStateNormal];
[UIView animateWithDuration:1
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
CGRect frame = self.organizationTable.frame;
frame.size.height = 0;
self.organizationTable.frame = frame;
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}
You can prepare a custom view for that and add it as a subview in your ViewController.
Use UIView animations for simulating "drop down" effect.