Subviews gets trimmed when out of UITableViewCell bounds - ios

I've been looking around and can't find a solution to my problem. I have a UIImageView as subview of UITableViewCell, I add it in cellForRowAtIndexPath, the frame of subview starts on cell-1 and goes out of cell-1, getting into cell-2.
Basically, I want my image to be on the middle of two cells. Now, when tableViewfirst loads, it appears correctly, but when I scroll the cells down and go back, the image is trimmed, showing only the part that is in cell-1 bounds.
I know iOS 7 has a scrollView between contentView and cell. When I log on my cellForRowAtIndexPath:
if (cell.contentView.superview.clipsToBounds == YES || cell.contentView.clipsToBounds == YES || cell.clipsToBounds == YES) {
NSLog(#"CLIP = YES");
} else {
NSLog(#"CLIP = NO");
}
it shows me that cell, contentView and scrollView have the property clipToBounds set to NO, which is what I want.
I just don't know why subviews still get trimmed.

I ran across the same problem as you.
I realised that the problem was my cell had non-transparent backgrounds. The subviews weren't being clipped, they were simply getting covered by the background colours of previously added cells.
You can't control the order in which cells get added to the table view, so you'd have to use [UIColor clearColor] as the background colour of your cells to get the desired effect.
If that's an issue, set the zPosition of your subview to a high enough number and you'd hopefully be good to go.

Related

Why is UIScrollView adding UIImageView subviews to its subviews when scrolling

If title isn't telling you anything, here's what I found out recently and am curious about:
In my app I have a UIScrollView with buttons in it. These buttons all have one subview each - an instance of UILabel. Sometimes there is a particular event triggered that changes the text in labels and I also needed to change the frame of both labels and buttons, so that whole text can be displayed (it won't be truncated). So I just grabbed first subview of a button and checked how much space its text needs.
This caused crashes if that event occurred during scrolling. Turns out that besides the label, each button had another subview which was instance of UIImageView. At first I thought that during scrolling, UIScrollView takes "screenshots" of its subviews and kind of puts the images on top so that animating the scrolling is somewhat less expensive in terms of performance. This logic is flawed however, because the UIImageView was a subview at index 0, so it was put below my labels.
Anyone knows why this happens? What did Apple engineers try to achieve with this weird mechanic?
Note that it might actually happen just for buttons though. Also, I checked the labels and they didn't have any subviews.
UIButtons have a UIImageView for the background image (which is nil until you call - (void)setImage:(UIImage *)image forState:(UIControlState)state or set it using Interface Builder). So I would assume that the subview at index 0 would be the background image since that would be drawn first to be below everything else.
What you could do to be sure that you are getting the UILabel that you're looking for is something like this:
- (UILabel *)getLabelForButton:(UIButton *)button
{
for (id subView in button.subviews)
{
if ([subView isKindOfClass:[UILabel class]])
{
return subView;
}
}
return nil;
}

UICollectionView and UINavigationController not cooperating — cells occluded by nav controller on setting prompt

In my UIViewContoller's subclass, ViewWillAppear asks whether or not there's any data to present, and if there is, changes the UINavigationController's prompt accordingly. This triggers an animation as the prompt pops into view, causing the UINavigationBar to grow in size. When this happens it partially occludes the cells in the top row of the UICollectionView.
I have a vertical Auto Layout constraint of 0, seemingly pinning the UICollectionView to its nearest neighbor, which should be its superview, but the navbar still blocks the top halves of the cells. I've tried everything — telling the CollectionView to layout its subviews, reloading data, etc., but nothing seems to work. Any idea what's going wrong?
- (void)viewWillAppear:(BOOL)animated{
if(self.orderedURLSet.count == 0){
self.navigationItem.prompt = nil;
[self.collectionView setNeedsDisplay];
} else {
self.navigationItem.prompt = #"Tap photos to edit";
}
[self.collectionView reloadData];
[self.collectionView layoutSubviews];
}
Edit: What makes this even stranger is that when I rotate orientation the collectionViewCells aren't occluded, and the full cells remain visible when I rotate back to portrait orientation. Is there some way I can "trick" my app into thinking its layout has changed and it needs to reposition the cells? LayoutSubviews isn't doing the trick.
Edit: After digging a little more into the UIView documentation, it looks like setNeedsLayout and layoutIfNeeded are really the methods I should be using, and not layoutSubviews. I've tried calling both of them, on navigationController:didShowViewController:animated:, viewWillAppear, viewDidAppear, and viewDidLayoutSubviews to no avail.
Have you tried??
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}

How to draw connecting lines between two uitableviewcells ios

I want to show links between two cells of uiTableView.
For Ex:
To show links between cells 1 and 5, it could be shown like:
Does any one has any idea how this can be achieved. Also when table scrolls, these links should be scrolled with it.
This looks like you want to build hierarchical view. Your implementation might be rejected by Apple due to not taking HIG into account.
Also what will be in case when lower part is not seen to user? Arrow with no end and need to scroll down for the user?
You might want to do a tree like structure (anything hierarchical) instead of ugly (sorry for that) arrows.
If you want arrow between two cell then make a separate UIView class for the Tablecell, in that UIView add one UILabel for text and one UIImageView for arrow, adjust there position as per your requirement.
Now pass this UIView to cell.
Hope this will help you.
UITableViewCell is just a subclass of UIView and UITableView is a subclass of UIScrollView. The only fanciness that UITableView provides is creating/reusing the cells and laying them out in the scroll view. (That's a gross over-simplification but for this It'll do the trick.)
So if I have a UIView subclass that draws an arrow, then it's just a matter of getting the frame for the cells I want to point to. CGRect frame1 = [[self.tableView cellForRowAtIndexPath:indexPath] frame];
Some pseudocode...
topCellFrame = get top cell frame;
bottomCellFrame = get bottom cell frame;
arrow = new arrow view;
arrow set frame = frame with origin of top cell frame origin, and height of distance from topCellFrame to bottomCellFrame;
tableView add subview = arrow;
There are edge cases to think about, If the top cell or bottom cell are offscreen the cellForRowAtIndexPath: will return nil and frame will be CGRectZero.
But I'll leave that as an exercise for you.
Edit: (I haven't done this exact thing, but I have done some similar things with the frames of cells)

How to keep the background color of UICollectionViewCells from changing when scrolling?

My UICollectionView's cells have a contentview with a background color of white upon loading. Users can change the background color of the cell's contentview to cyan by selecting the cell assuming a boolean value (isSplitting) is set to YES.
My problem arises when I have more cells then fit on the screen and the user has selected cells and thus changed their contentview's background color to cyan.
I have instances where cells that are cyan get scrolled out of view and when scrolled back in are white. I also have instances where cells that are not cyan are scrolled into view and are cyan.
I understand that the cells are being dequeued for reuse and retaining their background colors when getting loaded into a different indexpath.
I have resolved the issues of cells that are not selected becoming cyan upon scrolling into view. I have not however been able to resolve the issue of certain selected cells losing their cyan color when scrolled in and out of view.
Here is the current logic I have in cellForItemAtIndexPath.
if (!isSplitting) {
cell.contentView.backgroundColor = [UIColor whiteColor];
}
else{
for (NSIndexPath *collectionIndexPath in [self.myCollectionView indexPathsForSelectedItems]) {
if (indexPath == collectionIndexPath) {
cell.contentView.backgroundColor = [UIColor cyanColor];
break;
}
else{
cell.contentView.backgroundColor = [UIColor whiteColor];
}
}
}
I know the that correct cells are indeed selected because another operation using the same for loop above produces the desired results. The logic seems to breakdown if I select the first couple items (turn them to cyan), scroll to the right and select the 10th item. When I scroll back to the left the first couple are still cyan but upon scrolling to the right again the 10th is back to white.
Use isEqual: to compare the indexPaths rather than ==
if ([indexPath isEqual:collectionIndexPath]) {

Avoid auto resize of uitableview cell content view on entering edit mode

I have a uitableviewcell with content view containing some custom view.'
When the table view enters edit mode the content view resizes (becomes narrower) there by the image in the content view is shrunk horizontally
Does anyone know how to prevent this ?
I have set the cell indentation to none.
Thanks
Have you tried setting shouldIndentWhileEditing to NO
Take a look at properties :
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewCell_Class/Reference/Reference.html
Have you tried setting the auto-resize masks on the view?
theView.autoresizingMask = UIViewAutoresizingNone;
You may need to set it on the content view and/or the image view - it's not clear exactly how your view hierarchy is structured. However, the frame might be set explicitly (rather than auto-resized) by the framework, in which case this won't work.
If you are trying to have a background image for the entire table cell, you may also want to try an alternative method which is to set the backgroundColor of the cell like this:
UIImage* someImage = [UIImage imageNamed:#"someImage"];
cell.backgroundColor = [UIColor colorWithPatternImage:someImage];
Remember to make sure the backgroundColor of all other views you place inside are [UIColor clearColor] so that you can see through to the background image.
You can always get a tableviewcell with an indexpath. Using that tableviewcell reuseidentifier, You can avoid the tableview cell content size to be resized or not. I had a requirement to implement the similar kind of functionality to avoid resizing of seperate cells. PFB the code.
-(BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath{
BOOL shouldIndentWhileEditingRow = NO;
UITableViewCell *lTableViewCell = [tableView cellForRowAtIndexPath:indexPath];
/*Change the position of the target rect based on Sending messages or Receiving messages*/
if ([lTableViewCell.reuseIdentifier isEqualToString:#"SendingChatCellIdentifier"]) {
shouldIndentWhileEditingRow = NO;
}else if ([lTableViewCell.reuseIdentifier isEqualToString:#"ReceivingChatCellIdentifier"]){
shouldIndentWhileEditingRow = YES;
}
return shouldIndentWhileEditingRow;
}
I did something similar to avoid the cell content to be resized when using cell automatic dimension.
My problem was that the textView inside the cell, after the selection, was wrapping its content in more lines, and I just wanted to avoid this.
To solve this "issue":
I added a trailing constraint of 40px (the size of the accessory view) to the cell content
On cell select, i change the constraint to 0, so the text is 40 px larger, but as the accessory shows up, you don't see any changes.
The pro of this solution is that the content dimension is not changing anymore when user select a row.
the con is that you have always 40px of free space on the right of the cell, also when not selected.

Resources