UIView Content Clipping Not Working/UIView Resize Not Working - iphone

I ran into an issue where clipping of subviews is not working consistently (or potentially, the UIView resize isn't working). Here's the scenario:
I have a UIView (section above the line). The actual size is larger to accommodate search bar. I basically resize it on viewDidLoad.
When clicking on the text field, UIView expands and show a search bar
After search, I collapse the UIView, but found that the UIView is not collapsed in certain case (see first image). If I were to not hide the search bar, it will remain also.
Is there any reason why this issue occurs? I'm still trying to debug and see if there is anything that could have caused this issue (as something may reset to original size). It definitely does seem like everything is resized correctly since even the result table is moved correctly also. Something else must have triggered it after the expected resize. Any pointer is appreciated. I've only done iOS development for 5 days so I'm still not aware of a lot of things.
- (void)showAddressField
{
CGRect headerFrame = self.searchHeaderView.frame;
headerFrame.size.height = headerHeight + adjustmentSize;
self.searchHeaderView.frame = headerFrame;
CGRect tableFrame = resultTableView.frame;
tableFrame.size.height = tableHeight - adjustmentSize;
tableFrame.origin.y = headerFrame.size.height + statusBarHeight;
resultTableView.frame = tableFrame;
[self renderHeaderBorder:headerFrame.size.height - 1];
}
- (void)hideAddressField
{
CGRect headerFrame = self.searchHeaderView.frame;
headerFrame.size.height = headerHeight;
self.searchHeaderView.frame = headerFrame;
CGRect tableFrame = resultTableView.frame;
tableFrame.size.height = tableHeight;
tableFrame.origin.y = headerHeight + statusBarHeight;
resultTableView.frame = tableFrame;
[self renderHeaderBorder:headerHeight - 1];
}
EDITED
SearchHeaderView is just a UIView that is a subview of the main view. It's not a table header. I found that if I put a search bar in the table header, it behaves very unpredictably so I have a UIView containing the search portion and have a UITableView right below it.
Sorry, since I only have just over a week to get a rather massive app out from scratch, I didn't have time to wait. I already changed my approach a little bit, but I will still award the points even after the bounty has expired. I'm trying to understand everything to do with layout since that's pretty much the only thing that I can't quite figure out with iOS app development.

If the search bar is in the table view header, try reassigning the header view to the table view:
[tableView setTableHeaderView:self.searchHeaderView];
If it is a section header, be sure to update the value for the delegate's
– tableView:heightForHeaderInSection:
– tableView:viewForHeaderInSection:
Otherwise, please post more code on how the searchHeaderView is initialized and added to the table.
Hope this helps!

Firstly, frames are already relative to the enclosing window. You should not be taking into account the height of the status bar (assuming that refers to the 20px area at the top of the screen).
I have found in the past that you may need to implement "layoutSubviews" in your view controller and compute the frames of the views there. It depends on your resizing mask / if you auto-layout enabled.
As the others have stated, more code would be helpful... or at least the relevant portions of the nib/xib.

Related

UITableViewCell content moving around

I have an iPhone app in which I'm using a UITableView to format a set of text responses, one per row. I've set up the cell in the storyboard to have a label inside it, and set up a constraint saying that the label should be 10 points from the edge of the cell. I then set up a custom subclass of UITableViewCell, set the cell in the storyboard to be of that class, and connected the outlet.
However, when I load the table, I see the text in the cell moving slightly to the right under some circumstances: when I select the cell, or when I load additional cells into the table. In fact, in the latter case, sometimes everything gets shifted to the right, even cells which were already there!
What the heck is going on here? The only changes I'm making in tableView:cellForRowAtIndexPath: are to the text in the label, and I'm always setting it. And I've unset "Indent While Editing" on the cell in the storyboard.
Answering some of the questions: I'm setting the view up using the storyboard. Xcode isn't reporting any ambiguity with the constraints. Also, here are the screenshots, before and after:
My guess is that the constraints for the label are ambiguous. Ambiguity can make UI components jump around for inexplicable reasons. You probably need to set more constraints for the label to define its position on both axes.
Or, maybe all you need to do is set the label to the "size that fits content" (intrinsic content size) under the Editor menu in IB.
Did you add a new label to the UITableViewCell, or are you working with the textLabel that already exists in it? If you added a new one, consider removing it and using the cell's existing textLabel property instead. If that's not an option for some reason, double-check that the label you've added is in the contentView of the cell, and that all the constraints are relative to the parent view, not to the cell itself.
Also, for debugging, you could set the cell's contentView background color to red (cell.contentView.backgroundColor = [UIColor redColor];) - this might give you a better sense of what's moving, the label or the whole view.
This is just a guess without seeing your code. I had a similar problem once, when the app reused an existing cell, the dimensions of the label were not correct. So, I had to remove the old label in my cellForRowAtIndexPath method, before adding a new label. Here's how I removed the old one:
UIView *oldLabel = [cell viewWithTag:3];
if (oldLabel != nil)
{
[oldLabel removeFromSuperview];
}
Then I added a new label like this:
[cell.contentView addSubview:newLabelOrWhatever];
It might be worth checking to see that your string content doesn't have a space prefixed on it. Also, you could verify the actual position of the label by setting the background color.
I had a similar issue when the label would move when the cell was selected. It was a custom cell that I was loading from a custom Nib.
In the Nib I had not set the backgroundView of the UITableViewCell (superclass) to any view. Once I set it (I set it to the ContentView) the issue stopped.
My auto-layout constrains seems fine and had no issues, so I'm assuming it was the above that fixed it.
If you have a custom subclass of UITableViewCell, try implementing layoutSubviews. Let me try from the top of my head:
static CGFloat const kLeftMargin = 10.0f;
- (void) layoutSubviews
{
[super layoutSubviews];
/* Prepare for processing */
CGSize cellSize = self.bounds.size;
/* Change the textLabel frame */
{
/* Compute the new label frame */
CGSize labelSize = self.textLabel.bounds.size;
CGFloat xCoor = kLeftMargin;
CGFloat yCoor = roundf((cellSize.height - labelSize.height) / 2.0f);
CGRect labelFrame = CGRectMake(xCoor, yCoor,
labelSize.width, labelSize.height);
/* Set the new label frame */
self.textLabel.frame = labelFrame;
}
}
Now, this isn't what is usually recommended (since a lot of people use Storyboards and NIBs), but from experience, if you want some correct layouting done, implement layoutSubviews.

UIScrollView mysteriously changing frame and content size

I have a scroll view in my app, initialized through storyboard, and I am attempting to change the frame. Everything seems to work, but if the frame and content size are accessed just a short time after they are set, but after my method returns, they are different! Here is the code:
CGFloat inputHeight = inputView.frame.size.height;
originalContentHeight = self.scrollableContentView.frame.size.height;
NSLog(#"%f", self.scrollableContentView.frame.size.height-inputHeight);
[self.scrollableContentView setFrame:CGRectMake(self.scrollableContentView.frame.origin.x, self.scrollableContentView.frame.origin.y, self.scrollableContentView.frame.size.width, self.scrollableContentView.frame.size.height-inputHeight)];
NSLog(#"%f", self.scrollableContentView.frame.size.height);
NSLog(#"%#", self.scrollableContentView);
The output of these logs are all as expected, that is:
<UIScrollView: 0x808de00; frame = (0 0; 320 81); ... >
However, if I set a breakpoint in another method, by the time that is called, logging the scrollView shows this:
<UIScrollView: 0x808de00; frame = (0 0; 320 416); ... >
Additionally, the content size changes as such:
(width=320, height=416)
to
(width=320, height=504)
Both of the values seem to be reverting automatically to the values they have when the view is first laid out. I have set breakpoints in the getter and setter of my scroll view, and cannot find any unexpected accesses, so I have concluded that the change must come internally. Is this a justifiable conclusion? What could be going wrong?
If you're using autolayout you should be changing the constraints, not setting the scrollview's frame.
See my answer to a similar question here. It has some links to examples of how to set constraints programmatically.
Also, in which method are you setting the frame and contentSize? Since you are using a storyboard, if it is in viewDidLoad or viewWillAppear: it would be better to move this code to viewDidLayoutSubviews instead.

UILabel does not wrap (if I change default font size)

I am working on a simple storyboard prototype. My TableViewController uses Dynamic Prototype as Content.
I have a cell with 4 label of which two will be set in code (the label text). The height of the cell will be calculated in code too. The Line Breaks are set to Word Wrap and everything's working fine with the default values (System 17.0):
see here:
..but if I change the Font Size of the "Fantasy Street..." label it will not break any more instead it just will be cut off!
see here: with System Font 16
Lines are set to 0
Word Wrap is still active
.. I also tried to do it manually in code but no change.
Does anyone have an explanation for that?
****edited:** when I add
myLabel.frame = CGRectMake(t.origin.x, t.origin.y, t.size.width, t.size.height *2);
to the cellForRowAtIndexPath I still see the cut off label. But if I then scroll the table view so the label is outside the viewable area shortly it will be displayed with the complete text when it is visible again.
By the way, I am working with viewTags, so I don't have a dedicated Cell Class e.g. UILabel *myLabel = (UILabel *)[cell viewWithTag:2];
You should check UILabel width; the width should be less than that of the value. Then like this:
(void) viewWillLayoutSubviews {
_landPhoneTips.preferredMaxLayoutWidth = _landPhoneTips.bounds.size.width;
}
I spent hours dealing with this identical problem before finally sorting it out last evening. After changing the font size, you must select the UILabel within the storyboard and select Edit > Size to Fit Content, even if you had already previously done so! In doing so you apparently reset some setting that gets messed up when changing the font size. Once done, the UILabel will wrap as it did previously.

Large UICollectionViewCell's disappearing with custom layout

I subclassed UICollectionViewLayout. So far, so good.
However, I have some cells that are wider than the screen, and sometimes these disappear while scrolling. When you scroll some more, they magically reappear where they should be. I can show you my code, however I think there's nothing wrong with it since it works in 90% of the cases.. However, really large cells (more than two times the screen size) disappear sometimes.
NSMutableArray* attributes = [NSMutableArray array];
for (int section=0; section < [[self collectionView] numberOfSections]; section++) {
[attributes addObject:[self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]]];
for (int row=0; row < [[self collectionView] numberOfItemsInSection:section]; row++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:row inSection:section];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
}
return attributes;
I've also these posts: UICollectionView's cell disappearing and Large cells in a UICollectionView getting removed while the cell is still displayed
However, a solution isn't mentioned. Can anybody help me with this? Could it be the problem is on Apple's side? And if it is, is there anything I can do to solve it myself?
Sorry to tell you: I'm pretty sure this a real bug in UICollectionView; I've run into this exact same thing a few weeks ago. I've made a small program to demonstrate the bug and filed a RADAR with Apple, but haven't heard back on whether or if they plan on fixing it. The best workaround I can think of (Warning: I haven't yet implemented this workaround) is to notice that the layout attributes are very far off the edges of the screen, intentionally change the bounds of the cell attributes so it only slightly goes off screen, and possibly store that offset (the amount that you trimmed off of what the real bounds should be) as an additional custom field in the layoutAttributes, so your cell knows to draw it's content correctly. Which feels like a gross hack, but it ought to work.
Are you sure you return the right attribute object for this cell when method -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect is called and when the rect is just a part of your cell ?

How to make a custom drawn UITableViewCell resize properly?

For performance reasons, I draw the strings for my UITableViewCell in a custom view that overrides its drawRect method to draw strings directly in the view rectangle using NSString:drawInRect. This is similar to Apple's TableViewSuite Example 5-CustomTableViewCell.
However, when I invoke setEditing on the cell to bring up the delete button, the view ends up with a squeezed appearance after the animation completes. To demonstrate this, invoke setEditing:YES on the CustomTableViewCell example mentioned above and observe the distortion. Is there any way around this or should I just revert back to using UILabels for my text?
I had a similar problem with a UIView inside a UITableViewCell. I solved it by changing the UIView's contentMode to UIViewContentModeLeft. (I wrote it up here, with screenshots.)
I had this problem too, and in my case I fixed it by handling the 2 states in my drawRect method, one while editting, the other while not. In other words I accounted for the size of the delete button, and got my UI to repaint the cell differently. I'm not sure if it's the most efficient way to go, but here is the code that I used to force a repaint:
-(void)_refreshTableAndCells{
//refresh the table
[myCustomTableView reloadData];
//refresh all the visible cells
for (UITableViewCell *cell in myCustomTableView.visibleCells){
LocationCellView *locationCell = [cell.contentView.subviews objectAtIndex:0];
[locationCell setNeedsDisplay];
}
}
I'm an Objective-C n00b though, so I'd be more than happy for someone to suggest a better way than this.
I usually just modify the x and width values (or whatever else) of whatever I want to be different when editing or not. UITableView automatically calls layoutSubviews when you begin editing, so you don't have to loop through your cells and do it yourself.
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat editingPadding = 5.0;
self.textLabel = CGRectMake((self.editing ? self.textLabel.frame.origin.x + editingPadding : self.textLabel.frame.origin.x), self.textLabel.origin.y, (self.editing ? self.textLabel.frame.size.width - editingPadding : self.textLabel.frame.size.width), self.textLabel.frame.size.height);
}
Try setting the contentMode of your own custom view (which resides inside the cell's contentView) to UIViewContentModeLeft. The "squeezing" is due to the fact that the default contentMode is UIViewContentModeScaleToFill.