I have a TableViewHeader and want to animate it so it looks like it is shrinking when I have rows in my table. I have tried numerous things but it doesn't want to move. The console output shows it was resized but I still see it as normal on the screen.
Why is the animation not working? Am I overlooking something?
- (void)setProperHeader
{
UIView *tempView = nil;
CGRect offsets;
if ([appointmentsList count] == 0) {
NSLog(#"List Count 0");
tempView = [[self.storyboard instantiateViewControllerWithIdentifier:#"ExistingAppointmentsViewController"] viewWithTag:400];
offsets = CGRectMake(tempView.frame.origin.x, tempView.frame.origin.y, tempView.frame.size.width, tempView.frame.size.height);
tempView.frame = CGRectMake(offsets.origin.x, offsets.origin.y, offsets.size.width, 0);
} else {
NSLog(#"List Count is %i", [appointmentsList count]);
tempView= self.tableView.tableHeaderView;
offsets = CGRectMake(tempView.frame.origin.x, tempView.frame.origin.y, tempView.frame.size.width, 0);
}
NSLog(#"TableView Frame: %#", NSStringFromCGRect(self.tableView.tableHeaderView.frame));
NSLog(#"Offsets %#", NSStringFromCGRect(offsets));
NSLog(#"Temp: %#", tempView);
// if (tempView != self.tableView.tableHeaderView) {
[self.tableView setTableHeaderView:tempView];
[UIView animateWithDuration:1.0f
animations:^{
tempView.frame = offsets;
}
completion:^(BOOL finished) {
NSLog(#"Complete tempView: %#", tempView);
NSLog(#"Complete tableHeader: %#", self.tableView.tableHeaderView);
[self.tableView setNeedsLayout];
[self.tableView reloadData];
}];
// }
}
The [self.tableView setNeedsLayout] was added in as a test to see if that would make it work.
Console Output
2013-09-25 16:04:32.301 App[63910:a0b] List Count is 2
2013-09-25 16:04:32.301 App[63910:a0b] TableView Frame: {{0, 0}, {320, 91}}
2013-09-25 16:04:32.301 App[63910:a0b] Offsets {{0, 0}, {320, 0}}
2013-09-25 16:04:32.302 App[63910:a0b] Temp: <UIView: 0xa568560; frame = (0 0; 320 91); autoresize = W+H; tag = 400; layer = <CALayer: 0xa5685c0>>
2013-09-25 16:04:33.313 App[63910:a0b] Complete tempView: <UIView: 0xa568560; frame = (0 0; 320 0); autoresize = W+H; tag = 400; layer = <CALayer: 0xa5685c0>>
2013-09-25 16:04:33.313 App[63910:a0b] Complete tableHeader: <UIView: 0xa568560; frame = (0 0; 320 0); autoresize = W+H; tag = 400; layer = <CALayer: 0xa5685c0>>
Related
I change the UITableView with following code,
CHANGE_FRAME_HEIGHT(header, CGRectGetMaxY(_lbFollowing.frame)+8)
_tableView.tableHeaderView= header;
but the tableivew's contentSize increase 0.5 every i call those code
2015-11-17 12:30:41.881 yueban[42934:3092288] -[UserInfoHeaderView layoutSelfView] [Line 245] <UITableView: 0x61d00023e680; frame = (0 0; 320 519); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x604000298610>; layer = <CALayer: 0x6030002737c0>; contentOffset: {0, 0}; contentSize: {320, 474.00299978256226}>
<UserInfoHeaderView: 0x6160001d8880; frame = (0 0; 320 246.5); layer = <CALayer: 0x603000272f50>>
2015-11-17 12:30:41.903 yueban[42934:3092288] -[UserInfoHeaderView layoutSelfView] [Line 247] <UITableView: 0x61d00023e680; frame = (0 0; 320 519); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x604000298610>; layer = <CALayer: 0x6030002737c0>; contentOffset: {0, 0}; contentSize: {320, 474.50299978256226}>
why ??
Got answer. I need call reloadData after reset the tableHeaderView
_tableView.tableHeaderView=self;
[_tableView reloadData];
Flowing code should be called once in viewDidLoad method.
I think, your code is right, but not in right position.
CHANGE_FRAME_HEIGHT(header, CGRectGetMaxY(_lbFollowing.frame)+8);
self.tableView.tableHeaderView = header;
I am trying to loop all my subviews and print them in NSLog.
I have developed this recursive method:
- (void)allSubViews:(UIView*)mainV
{
for (UIView *view in mainV.subviews) {
NSLog(#"%#", view);
if ([[view subviews]count]>0) {
[self allSubViews:view];
}
}
}
which I call from MainViewController.m:
[self allSubViews:self.myView];
The result is:
2015-09-12 11:18:48.919 Profile-Statistics[3153:506562] <_UILayoutGuide: 0x7fc70bf1c330; frame = (0 0; 0 0); hidden = YES;
layer = >
2015-09-12 11:18:48.919 Profile-Statistics[3153:506562] <_UILayoutGuide: 0x7fc70bf1ced0; frame = (0 0; 0 0); hidden = YES;
layer = >
My View has Top and Bottom Layout Guide and a View which has 3 UIButtons, 1 ImageView and 1 UIView.
Did I miss something here?
Update:
Screenshot of StoryBoard
For what it's worth, I tried this in a sample project with a bunch of subviews and it worked as expected.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (IBAction)printButtonTapped:(id)sender {
[self allSubviews:self.view];
}
- (void) allSubviews:(UIView*) parent {
NSLog(#"%#", parent);
for (UIView *child in parent.subviews) {
[self allSubviews:child];
}
}
#end
Console output is:
2015-09-13 22:06:00.904 RecursivePrint[66243:3455899] <UIView: 0x7fa902e0e6e0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fa902e15030>>
2015-09-13 22:06:00.905 RecursivePrint[66243:3455899] <UIView: 0x7fa902e0e840; frame = (70 56; 452 337); autoresize = RM+BM; layer = <CALayer: 0x7fa902e15050>>
2015-09-13 22:06:00.905 RecursivePrint[66243:3455899] <UIView: 0x7fa902e24c90; frame = (31 33; 153 160); autoresize = RM+BM; layer = <CALayer: 0x7fa902e21f00>>
2015-09-13 22:06:00.906 RecursivePrint[66243:3455899] <UIView: 0x7fa902e24fc0; frame = (219 41; 153 160); autoresize = RM+BM; layer = <CALayer: 0x7fa902e1ec10>>
2015-09-13 22:06:00.906 RecursivePrint[66243:3455899] <UIButton: 0x7fa902d177e0; frame = (164.5 603; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fa902d16c80>>
2015-09-13 22:06:00.907 RecursivePrint[66243:3455899] <UIButtonLabel: 0x7fa902d1f010; frame = (0 6; 46 18); text = 'Button'; alpha = 0.2; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fa902d1f670>>
2015-09-13 22:06:00.907 RecursivePrint[66243:3455899] <_UILayoutGuide: 0x7fa902e25ed0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7fa902e21b20>>
2015-09-13 22:06:00.907 RecursivePrint[66243:3455899] <_UILayoutGuide: 0x7fa902f77ec0; frame = (0 667; 0 0); hidden = YES; layer = <CALayer: 0x7fa902f09f70>>
As a side note, this is the first time in over a year that I've tried to do something in Objective-C. The Swift version seems so much easier to understand:
import UIKit
class ViewController: UIViewController {
#IBAction func printButtonTapped(sender: UIButton) {
printSubviews(self.view)
}
}
func printSubviews(parent:UIView) {
print(parent)
for child in parent.subviews {
printSubviews(child)
}
}
In addition, the Swift version of printSubviews is defined as a function, not a method so you don't call it from self, you just call it with the top level view you want to start with.
I am trying to create a grid like menu that can be shown if rightBarButton is being tapped. It seems that the layout is correct (see pic below), but the cell (each of which is a UIButton) doesn't responds to user tapping.
The dropdown (the part that is marked with red frame) is composed of two views. One is GridCell and the other GridCollection. GridCell is simple a view containing a UIButton that occupies the whole of its container. GridCollection init GridCells and positions them in order.
The following is the code extracted from GridCell
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (id)initWithColor:(UIColor *)color image:(UIImage *) cellImage title:(NSString *) title {
self = [self init];
if(self) {
self.backgroundColor = color;
self.image = cellImage;
self.title = title;
if(title == nil) self.title = #"default";
}
return self;
}
- (void)updateConstraints {
[super updateConstraints];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
//button should fill container
UIButton *button = [[[UIButton alloc] init] autorelease];
self.cellButton = button;
[self.cellButton addTarget:self action:#selector(cellTapped) forControlEvents:UIControlEventTouchUpInside];
[self.cellButton setTitle:self.title forState:UIControlStateNormal];
[self.cellButton setTitle:#"pressed" forState:UIControlStateHighlighted];
[self.cellButton setTitleColor:[UIColor blueColor] forState:UIControlStateHighlighted];
[self.cellButton setBackgroundImage:self.image forState:UIControlStateNormal];
[self.cellButton setUserInteractionEnabled:YES];
[self.cellButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.cellButton];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[_cellButton]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_cellButton)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[_cellButton]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_cellButton)]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:60]];
}
- (void)cellTapped {
NSLog(#"cell %d pressed ", self.tag);
}
- (void)layoutSubviews {
[super layoutSubviews];
NSLog(#"Printing button's frame: %#", NSStringFromCGRect(self.cellButton.frame));
}
The following is the code extracted from GridCollection
- (void)updateConstraints {
[super updateConstraints];
GridCell *previousCell = nil;
GridCell *firstCell = nil;
for (int i = 1; i <= self.numberOfCells; ++i) {
GridCell *cell = [[[GridCell alloc] initWithColor:i % 2 == 0 ? [UIColor brownColor] : [UIColor grayColor] image:nil title:[NSString stringWithFormat:#"Cell %d", i]] autorelease];
cell.tag = i;
[self addSubview:cell];
[cell setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addConstraint:[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1 constant:self.superview.frame.size.width/4]];
if (!previousCell) { //pin to top left
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[cell]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cell)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[cell]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cell)]];
firstCell = cell;
} else { //pin to previous
if(i % 4 == 1 && i != 1) {
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[firstCell][cell]" options:0 metrics:nil views:#{#"cell" : cell, #"firstCell" : firstCell}]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[cell]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cell)]];
} else {
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[previousCell]-0-[cell]" options:NSLayoutFormatAlignAllTop metrics:nil views:NSDictionaryOfVariableBindings(previousCell, cell)]];
}
}
previousCell = cell;
}
[self layoutIfNeeded];
}
For debugging purpose, I've put NSLog(#"Printing button's frame: %#", NSStringFromCGRect(self.cellButton.frame)) in GridCell's layoutSubview method. And I found that they all return 0,0 for button's origin. And I think perhaps this is the reason why my UIButton in the cell did not respond, is that right?
2014-08-04 21:36:42.837 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
2014-08-04 21:36:42.838 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
2014-08-04 21:36:42.839 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
2014-08-04 21:36:42.840 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
2014-08-04 21:36:42.840 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
2014-08-04 21:36:42.841 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
2014-08-04 21:36:42.842 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
2014-08-04 21:36:42.843 projectName[38661:60b] Printing button's frame: {{0, 0}, {80, 60}}
I am wondering how can I position cells' origin correctly in this occasion.
Thanks in advance.
That could be due by one of those problems:
The button is hosted outside the bounds of its superview. That also means if the superview has bounds {0,0}
you are loading cells from a xib, but the root view of these cells is not a UICollectionViewCell
Try to add into the reusable cell and not the button
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(cellTapped)];
[cell addGestureRecognizer:tap];
also
_tableview.scrollEnabled = YES;
The easiest way to identify a grid of buttons is to assign different numbers to their tag properties.
myButton[0].tag = 0, mybutton[1].tag = 1; etc. Then look at the tag of the pressed button in the action method.
After printing my view hierarchies, I found that it's because I did not assign height to my parent view gridview. Giving a height to that view solved this problem.
<GridView: 0x9b625a0; frame = (0 64; 320 0); tag = 100; layer = <CALayer: 0x8e4e720>>
| <GridCell: 0x8e56db0; frame = (0 0; 80 60); tag = 1; layer = <CALayer: 0x8c680c0>>
| | <UIButton: 0x8ca6170; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8caea80>; layer = <CALayer: 0x8ca6260>>
| <GridCell: 0x8ca3ae0; frame = (80 0; 80 60); tag = 2; layer = <CALayer: 0x8ca47b0>>
| | <UIButton: 0x8e57990; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8e57a80>; layer = <CALayer: 0x8e57680>>
| <GridCell: 0x8cae620; frame = (160 0; 80 60); tag = 3; layer = <CALayer: 0x8ca7450>>
| | <UIButton: 0x8e58490; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8e585d0>; layer = <CALayer: 0x8e58450>>
| <GridCell: 0x8caf4d0; frame = (240 0; 80 60); tag = 4; layer = <CALayer: 0x8c657d0>>
| | <UIButton: 0x8e58fc0; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8e59100>; layer = <CALayer: 0x8e58f80>>
| <GridCell: 0x8ca82e0; frame = (0 60; 80 60); tag = 5; layer = <CALayer: 0x8cb5450>>
| | <UIButton: 0x8e59af0; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8e59c30>; layer = <CALayer: 0x8e59ab0>>
| <GridCell: 0x8caed70; frame = (80 60; 80 60); tag = 6; layer = <CALayer: 0x8caedf0>>
| | <UIButton: 0x8e5a620; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8e5a760>; layer = <CALayer: 0x8e5a5e0>>
| <GridCell: 0x8caf260; frame = (160 60; 80 60); tag = 7; layer = <CALayer: 0x8caf300>>
| | <UIButton: 0x8e5b170; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8e5b2b0>; layer = <CALayer: 0x8e5b130>>
| <GridCell: 0x8cb0cc0; frame = (240 60; 80 60); tag = 8; layer = <CALayer: 0x8cb0d60>>
| | <UIButton: 0x8e5bca0; frame = (0 0; 80 60); opaque = NO; gestureRecognizers = <NSArray: 0x8e5bde0>; layer = <CALayer: 0x8e5bc60>>
I'm hoping now apps for IOS 7 are being accepted by Apple we can talk about it?
I'm trying to fix my app so it works on IOS 7 and have made some very good progress this evening. I have two outstanding issues, but will post them separately. The first issue is this line (I added a log line after to debug it) ...
NSIndexPath *indexPath = [settingsTableView indexPathForCell:(UITableViewCell *)[sender superview]];
NSLog(#"Changed %# <-**-> %#", [sender superview], indexPath );
The log shows ....
IOS7
2013-09-11 22:18:02.985 BusTimes[21013:a0b] Changed <UITableViewCellScrollView: 0xbfc1c80; frame = (0 0; 320 44); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0xbfc1e70>; layer = <CALayer: 0xbfc1540>; contentOffset: {0, 0}> <-**-> (null)
2013-09-11 22:18:08.577 BusTimes[21013:a0b] Changed <UITableViewCellScrollView: 0xbfc62d0; frame = (0 0; 320 44); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0xbfc64c0>; layer = <CALayer: 0xbfc5b90>; contentOffset: {0, 0}> <-**-> (null)
IOS 6
2013-09-11 22:25:34.495 BusTimes[2116:907] Changed <UITableViewCell: 0x20862f40; frame = (0 179; 320 44); text = 'Reminder Mins: 5'; autoresize = W; layer = <CALayer: 0x208523d0>> <-**-> <NSIndexPath 0x20861430> 2 indexes [0, 3]
2013-09-11 22:25:47.499 BusTimes[2116:907] Changed <UITableViewCell: 0x20865180; frame = (0 223; 320 44); text = 'AutoRefresh Secs: 60'; autoresize = W; layer = <CALayer: 0x20865340>> <-**-> <NSIndexPath 0x2085c0d0> 2 indexes [0, 4]
So on IOS 7 indexPath is always (null) and .section and .row are always 0. But this works fine on IOS 6 and returns .section 0 and row 3, and .row 4. Can anyone suggest how I might get IOS 7 to behave in the same way for me?
Many Thanks in advance.
Plasma
* SOLUTION - I changed my code to this following the comments *
UIView *view = sender;
while (![view isKindOfClass:[UITableViewCell class]]) {
view = [view superview];
}
NSIndexPath *indexPath = [settingsTableView indexPathForCell:(UITableViewCell *)view];
It's usually safer to make no assumptions about the view hierarchy of a cell. In the past, I've used a category with methods like this on UIView to find the superview which is a cell:
- (UIView*)ancestorOrSelfWithClass:(Class)cls {
if ([self isKindOfClass:cls]) {
return self;
} else if (self.superview) {
return [self.superview ancestorOrSelfWithClass:cls];
} else {
return nil;
}
}
So you'll ask for [sender ancestorOrSelfWithClass:[UITableViewCell class]] to get the actual cell, and it'll work no matter what hierarchy exists within the cell.
I have a series of UIViews inside a UIScrollView which I am attempting to resize when the root view controller receives willAnimateRotationToInterfaceOrientation:duration:
Here is the code...
(Panel is just an extended UIView; panels is an NSMutableArray of Panels held by an extended UIScrollView)
for(Panel * panel in panels)
{
panel.bounds = CGRectMake(panel.bounds.origin.x,
panel.bounds.origin.y,
self.bounds.size.width,
panel.bounds.size.height);
}
NSLog(#"%#", [panels description]);
The self.bounds.size.width is the UIScrollView (I've extended the class).
Here is the result of NSLog when the device is oriented to landscape...
"<Panel: 0x74324d0; frame = (-80 0; 480 50); animations = { bounds=<CABasicAnimation: 0xe1339d0>; }; layer = <CALayer: 0x7432530>>",
"<Panel: 0x7435ce0; frame = (-80 53; 480 50); animations = { bounds=<CABasicAnimation: 0xe133a90>; }; layer = <CALayer: 0x7435d40>>",
"<Panel: 0x7438e20; frame = (-80 106; 480 50); animations = { bounds=<CABasicAnimation: 0xe133ab0>; }; layer = <CALayer: 0x7438e80>>",
"<Panel: 0x7438eb0; frame = (-80 159; 480 50); animations = { bounds=<CABasicAnimation: 0x714f890>; }; layer = <CALayer: 0x7438f10>>",
"<Panel: 0x7438f40; frame = (-80 212; 480 50); animations = { bounds=<CABasicAnimation: 0x742ffd0>; }; layer = <CALayer: 0x7438fa0>>"
And when it's changed back to portrait...
"<Panel: 0x7480350; frame = (0 0; 320 50); animations = { bounds=<CABasicAnimation: 0x74a3b40>; }; layer = <CALayer: 0x74803b0>>",
"<Panel: 0x7483c90; frame = (0 53; 320 50); animations = { bounds=<CABasicAnimation: 0x74a3bd0>; }; layer = <CALayer: 0x7483cf0>>",
"<Panel: 0x7486dd0; frame = (0 106; 320 50); animations = { bounds=<CABasicAnimation: 0x74a3c60>; }; layer = <CALayer: 0x7486e30>>",
"<Panel: 0x7486e60; frame = (0 159; 320 50); animations = { bounds=<CABasicAnimation: 0x74a3cf0>; }; layer = <CALayer: 0x7486ec0>>",
"<Panel: 0x7486ef0; frame = (0 212; 320 50); animations = { bounds=<CABasicAnimation: 0x74a3d80>; }; layer = <CALayer: 0x7486f50>>"
I don't see any reason why the bounds.origin.x should ever be anything other than what it starts at (0). It must be something obvious, but I just can't see it - maybe some fresh eyes will see what I'm doing wrong.
I think you should have a look at Difference between frame and bounds
You have to set frame not bounds, as setting the bounds changes frame of view in its superView.
Hope this will help.