what's wrong with this assign? - ios

I am using GMGridView in my project. And in - (GMGridViewCell *)GMGridView:(GMGridView *)gridView cellForItemAtIndex:(NSInteger)index method, i write a snippet which is out of my expectation. The snippet is as follows:
if (!cell)
{
cell = [[GMGridViewCell alloc] init];
ThumbImageView *view = [[ThumbImageView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
[view setBackgroundColor:DEFAULT_BACKGROUND_COLOR];
[view setImage:[UIImage imageWithContentsOfFile:path]];
view.userInteractionEnabled = YES;
view.layer.shadowOffset = CGSizeMake(8, 8);
view.layer.shadowOpacity = 0.5;
NSLog(#"view frame width:%f,height:%f",view.frame.size.width,view.frame.size.height);
cell.contentView = view;
NSLog(#"cell.contentView frame width:%f,height:%f",cell.contentView.frame.size.width,cell.contentView.frame.size.height);
}
when it runs the output is as follows:
2013-06-03 11:02:05.508 XXX[71692:707] view frame width:115.000000,height:180.000000
2013-06-03 11:02:05.511 XXX[71692:707] cell.contentView frame width:0.000000,height:0.000000
why assign view to cell.contentView, cell.contentView.frame.size still be zero? and also cell.contentView can display the image properly. what's the reason? I am totally confused:(.

Check the docs:
contentView
Returns the content view of the cell object. (read-only)
#property(nonatomic, readonly, retain) UIView *contentView
contentView is a readonly property. You can't assign it.

The problem is probably that you've created new views, and you're looking at the frame of one of those views before the run loop has reached its layout phase.
When you create the GMGridViewCell, it starts with a default frame and bounds of CGRectZero. When you set its content view, it sets the content view's frame to its (the cell's) bounds. So even though you set the content view's frame directly using initWithFrame:, the frame gets changed to CGRectZero when you set the view as the cell's content view.
Since the cell isn't a subview of the grid view yet, there's no way to ask the grid view to lay out the cell by the time you're trying to log the content view's frame. If the grid view is using a constant size for all cells, and you know what that size is, you could manually set the cell to that size before setting the cell's content view. Otherwise, you need to wait until after the grid view's layoutSubviews method has run to check the content view's frame.

Related

Making a UIView keep its size when used as a table header view

If I use the following code to add a tableHeaderView to a table...
UILabel *label = [UILabel new];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.text = #"Hello, world!";
self.tableView.tableHeaderView = label;
The result is that the content of the table is pushed down by the height of the label.
This is fine and is what I want.
However, when I use my own custom view (set up in code) which has its own subviews etc... then the content of the table is not pushed down and the header view overlaps onto the content.
I'm not using AutoLayout to place the subviews of my custom view because of the nature of the view it doesn't really work as an AutoLayout view.
The frame of my custom view is (0, 0, 0, 0) with the content of the header view being drawn outside its bounds.
I have implemented the - (CGSize)sizeThatFitsSize:(CGSize)size method of my custom view but that hasn't changed anything.
Is there something else I need to implement also?
Example
If I use the following code to put a label inside my custom view...
- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
UILabel *label = [UILabel new];
label.text = #"Hello, world!";
[label sizeToFit];
[self addSubview:label];
label.frame = CGRectMake(0, 0, CGRectGetWidth(label.bounds), CGRectGetHeight(label.bounds));
}
return self;
}
Then the label appears in the same place as before but the content is not pushed down.
The frame of the view when you set it as the table header view is the size that the table view allocates and maintains for the view.
So, you need to determine the required size for your header view and change it's frame before setting it.
The table view will not make and queries or size changes for you. Autoresizing rules do apply so if the table view frame changes the header view will be resized according to the rules you specify. This may lead to different issues.

Why is my UIView's frame changing unexpectedly after the embedded UITableView is interacted with?

Consider the following UIView "MainView":
The view includes a Container View which in turn houses a UITableView controller. The container view's y coordinate starts just beneath the gradient bar. The UITableView includes the section footer at very bottom with the 'STU' label and 'chart' button.
When the UIView loads, and up-to-and-until any interaction with the tableView, MainView's dimensions are:
Frame: 0.000000x, 0.000000y, 568.000000w, 268.000000h
I have a delegate protocol set up such that tapping the chart button in the tableView will create a new view in MainView for a shadow effect via a method performing:
CGRect newFrame = self.view.frame; // self = MainView
newFrame.size.width = 100;
newFrame.size.height = 50;
UIView *backgroundShadowView = [[UIView alloc] initWithFrame:newFrame];
backgroundShadowView.backgroundColor = [UIColor blackColor];
// Do Animation
The important part above is the 'newFrame' CGRect. For some reason after interacting with the table view by tapping the chart button, or even scrolling or tapping a row, self.view.frame suddenly has the following dimensions:
Frame: 0.000000x, 52.000000y, 568.000000w, 268.000000h
And so the shadow view appears as follows, with a y origin much farther down than where it would be expected to start, just above the gradient bar.
I've adjusted the width and height of the "shadowview" for this question; normally it would be 568x268, but would extend 52 units off screen on the bottom because of this issue.
52 units is exactly the height of the statusbar (20) + navigationbar_in_landscape (32).
Of course I could manually adjust the frame dimensions, but I do not want to. I want to know why the view's frame is changing unexpectedly.
For the life of me, I cannot figure out why the view becomes suddenly offset. Any help is appreciated!!
Two comments.
(1)
This code was probably always wrong:
CGRect newFrame = self.view.frame; // self = MainView
newFrame.size.width = 100;
newFrame.size.height = 50;
UIView *backgroundShadowView = [[UIView alloc] initWithFrame:newFrame];
You surely want to define backgroundShadowView's frame in terms of self.view's bounds, not its frame as you are doing in the first line here.
(2)
The change in self.view.frame is probably illusory. You are probably checking this initially in viewDidLoad. But that is too soon; the view has not yet been added to the interface, and so it has not yet been resized to fit the surroundings.

UIView Subview don't show up when the frame is set manually

I want to set the frame of a subview manually.
So I just create a CGRect with CGRectMake and use the new CGRect for the frame of the subview. The problem is that the subview don't show up.
When I just use the view.bounds property of the parent view and assign this as frame to the subview then everything shows up.
I also ensured that the frame is in the displayed area.
frame = CGRectMake(0, 0, 100, 100);
[self.view addSubview:[[UIView alloc] initWithFrame:frame]];
Good way to set subview's frame is
subview.frame = CGRectMake(0, 0,
CGRectGetWidth(self.view.bounds),
CGRectGetHeight(self.view.bounds));
Refer to link
All the values less than CGRectGetWidth(self.view.bounds) & CGRectGetHeight(self.view.bounds) should work fine
The code in your question will create a view to which you have no reference. This means it has no background colour, contents or other means to see it, and you have no means to set it. You've added the view, but it is invisible.
Create and configure the view first, assigning it to a local variable, before adding it as a subview. As part of this configuration, give the view a background colour or some subviews.

Best way to redraw a custom view when orientation changes

I have a custom view:
-(id)initWithFrame:(CGRect)frame
{
CGRect frameRect = CGRectMake(0, NAVIGATION_BAR_HEIGHT , frame.size.width, 4 * ROW_HEIGHT + NAVIGATION_BAR_HEIGHT + MESSAGE_BODY_PADDING);
self = [super initWithFrame:frameRect];
if (self) {
_selectionViewWidth = &frame.size.width;
[self initView];
}
return self;
}
-(void)initView
{
CGRect sectionSize = CGRectMake(0, 0 , *(_selectionViewWidth), ROW_HEIGHT * 4);
_selectionView = [[UIView alloc] initWithFrame:sectionSize];
[_selectionView setBackgroundColor:[UIColor clearColor]];
That I use in a View Controller the next way:
_mailAttributesView = [[MailAttributesView alloc]initWithFrame:self.view.frame];
_mailAttributesView.delegate = self;
[self.view addSubview:_mailAttributesView];
So when orientation changes from P to L I have the next problem:
What's the best way to get orientation change callback and redraw my custom view?
You likely need to override your UIView layoutSubviews method and proceed to manually layout your subviews (looks like to/from/cc/subject controls) there.
Or, you could better configure your subview spring/struts (or autolayout constraints) for automatic layout. You could do this in code or via a nib or storyboard.
EDIT: additional info since you seem not to be getting layoutSubviews on orientation change.
My guess is that the viewcontroller-view isn't resizing/repositioning your MailAttributes view either.
It's also not clear when/where you add your MailAttributesView to the veiwcontroller view. If you're doing it in viewDidLoad your viewcontroller view may or may not have a valid frame size (depending if it was loaded from a nib or not). It's best not to depend on the viewcontroller-view frame for layout purposes in viewDidLoad.
Rather, layout any viewcontroller-view subviews in viewWillLayoutSubviews. There your viewcontroller-view frame will be set.
Others may point out that you can set your autoresizingFlags in viewDidLoad for any subviews, but there are gotcha's with this. Primarily if the parent view has zero size, and your subviews are to be inset but have springs/struts defined to glue them to the parent view edges.
The best solution overall IMO is to setup autolayout constraints for everything contained in your viewcontroller view, on down.

Resizing subview with superview's frame change

I have a UIImageView aSuper; This view is changing its sizes when i flip it i.e. it is taking sizes of next frame and next frame and so on.
Now this UIImageView contains a subview which is also imageview. I will call it bSubView.
Now i want to resize this bSubView every time its parent's view frame changes.
Code is :- Here invisibleView is subview and viewHolder is parent view. parent view is changing right but problem is with subview.
UIImage *image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageString1]]];
UIImageView *viewHolder=[[UIImageView alloc] initWithFrame:CGRectMake(510, 200, 20, 20)];
invisibleView=[[UIImageView alloc] init];
invisibleView.image=image;
invisibleView.frame=viewHolder.bounds;
viewHolder.autoresizesSubviews=YES;
[ invisibleView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
invisibleView.contentMode=UIViewContentModeCenter;
viewHolder.image=[UIImage imageNamed:#"EmptyPlanet"];
[viewHolder addSubview:invisibleView];
[self.view addSubview:viewHolder];
Many Thanks in advance.
you can use the inherited method -(void)layoutsubviews
This method is called on the super view when its frame changes. In that method you can configure your subviews
Another option is to use autolayout when configuring the subviews.

Resources