I have a messages collection view that is rotated 180 degrees (so that the cells are appended from the bottom).
collectionView?.transform = CGAffineTransform.init(rotationAngle: (-(CGFloat)(Double.pi)))
cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
I want to use the insertItem option when appending new cells, but it causes the cells to perform an awkward animation where the ones visible on the screen are flipped upside down and over to the opposite side. However, when they are scrolled out of view and back into view, they reset into the right positions.
This is a video of the bug: https://www.youtube.com/watch?v=2X8FjOf5AqA
This is happening because when performBatchUpdates is called when you add the new cell, all visible cells are re-rendered and the transform is applied again, essentially removing the transform.
You only want this to happen once, so the cells will maintain their transform. To do this, ensure the transform of the cells matches that of the collectionView, which we know won't change (because the collection view itself is not re-rendered on performBatchUpdates).
Also, you don't need to invert one of the transforms - a rotation by -π is equal to a rotation by π.
collectionView?.transform = CGAffineTransform.init(rotationAngle: CGFloat(Double.pi))
cell.transform = collectionView!.transform
I believe I fixed the issue by creating a UIView inside the custom collection view cell, and fitting all of the content (like the text bubble) inside that view then rotating the view by pi (instead of rotating the cell by pi). I still rotated the collection view using Bradley's answer above.
collectionView?.transform = CGAffineTransform.init(rotationAngle: CGFloat(Double.pi))
Related
I'm writing an iPhone app. For most of the scenes on our storyboard the default behaviour when the phone changes from portrait orientation to landscape orientation is fine. I.e. this is the layout change we want:
But for one of the scenes in the storyboard I do not want this layout change. Instead I want this:
I am confused about how to achieve the latter layout change. I can use size classes to ensure that the 100 pixels gap for the toolbar swaps from the bottom (portrait) to the right (landscape), but I cannot work out how to constrain the toolbar correctly, especially because the rotation needs to happen in code, e.g.
switch (UIDevice.currentDevice().orientation) {
case UIDeviceOrientation.LandscapeLeft, UIDeviceOrientation.LandscapeRight:
self.toolbarView.transform = CGAffineTransformMakeRotation(CGFloat(3 * M_PI_2))
// Reposition toolbarView into space to the right of the content's view
break
default:
self.toolbarView.transform = CGAffineTransformIdentity
break
}
What should I do to reposition the toolbar correctly?
Layout constraints constrain the frame of the given view. Let's see what the documentation says about the interplay between the frame and transform properties:
WARNING
If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
...
if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, you can reposition the view using the center property and adjust the size using the bounds property instead.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/frame
So you cannot do this via AutoLayout. You have to use center and bounds, and do positioning from code:
-(void)layoutSubviews {
[super layoutSubviews];
self.toolbarView.center = ...
self.toolbarView.bounds = ...
}
When a user selects a collectionView cell, I animate that cell's frame to grow and reposition so that it is sitting has this size/location:
CGRectMake(114, 148, 540, 620)
This works well if I haven't scrolled down to other cells in the collectionView. When I try this on a lower cell, it still animates, but the cell goes shooting up so that it's y coordinate can be at 148 for the collectionView.
I have tried all sorts of variants of convertRect and convertPoint, but I am unable to conceptualize the correct solution.
What do I need to do to convert the selected cell's y value to move to the equivalent of 148 in the superview's coordinate system?
EDIT: To reduce confusion
I tap on a cell at the bottom (meaning I scroll down several rows) of my collectionView and this is the origin:
(x=394.5, y=4114)
The x here is fine, but I have a problem with the y. I want to animate this cell that I just selected so that it appears as though it's y coordinate is at 148 of the outer view. Just like a form sheet modal view controller. But setting that origin to 148 causes the cell to fly up to the top of the collectionView because it is all the way down at 4114. How can I get the correct y value that looks like 148 to the user, but in reality will be something closer to the cell's original origin?
EDIT 2: PIC
If I understood correctly what you want to do then the solution is simple: the "y" position of your cell should be self.collectionView.contentOffset.y + 148.
CGRectMake(114, self.collectionView.contentOffset.y + 148, 540, 620);
This will work with any given scroll value.
Hope this helps!
This may sound a newbie question, however I'm new to iOS dev.
I've got a UITableView on my iPad app. TableView has obly three rows, is there a way to tell UITableView to view rows vertically centered, i.e. to not from the top to down.
Figure out the sum of the heights of all 3 rows, call it MyTotalHeight.
float MyTotalHeight = heightOfRow0 + heightOfRow1 + heightOfRow2;
Set your
tableView.frame = CGRectMake(start_X, start_Y, tableWidth, MyTotalHeight);
If you want the contents of each row/cell to be centered vertically within the cell, this will depend greatly on what is in the cell. You will need to calculate the height of the content and then center that content vertically within the cell by adjusting it's frame.
You may want to try the UiTableView.sectionHeaderHeight property. Play with the number until the cells are centered vertically. If your using a plain table view, I don't know how well this will work for you.
--John
I'm looking to write a method for an iPhone app that will auto adjust a UIViews's subviews Y values depending on the available space within that view. I'll try my best to explain without getting too confusing.
I have a Container view that is housing up to 3 Subviews. With in each subview is a button that removes the sub view from the container view, when the subview is removed i would like to adjust the remaining subviews to take up whatever space that has been opened by the removed subview.
Thanks in advance for any help!
One way is to make your wrapper view a custom UIView subclass. In that subclass, maintain a separate NSMutableArray of your subviews wherein each subview's array index corresponds to its position on the screen.
With this in place, you have a couple of options. One is to overide didAddSubview:. Based on the frame of the subview being added, you can determine the subview's position and insert reference to the subview at the appropriate index in your array.
A cleaner option is to implement your own custom method like this:
- (void)insertSubview:(UIView *)subview atPosition:(NSInteger)position;
where position is an index identifying which "slot" the subview should fill. You can set the frame for the subview explicitly within this method, along with any other subviews that are impacted by the insertion. Then insert the subview into your array at the corresponding index.
Finally, override willRemoveSubview:. In it you can use indexOfObject: on your array to find the position of the subview being removed. Then simply adjust the frames of all the subviews that follow it, and remove the subview from your array.
(One other alternative is to skip the array and just use the tag property to indicate the position of each subview. I don't like this option though. Using the tag property for anything always feels like a terrible hack to me.)
Well the first thing you need to do is signal your container that a subview has been removed.
Then you can take the height value of the view that was removed, divide it by the number of remaining subviews, and then expand the height of those remaining subviews.
Then you set your first remaining subview to Y coordinate 0, and the second (if there is one), to a Y coordinate of the first subviews height value
I got a subclass of UIView in which I draw an NSString object using the drawInRect:withFont:lineBreakMode:alignment: method.
Unfortunately, when I change the orientation of the device, say from portrait into landscape mode, the text doesn't get redrawn correctly but gets scaled and distorted against my intentions.
How can I solve this problem?
This is part of how Core Animation animates transitions. A snapshot of your view is taken, and then stretched/moved into the new location.
There are a number of ways you can tackle this. First of all you can try this:
self.contentMode = UIViewContentModeRedraw;
This might be all you need and will tell Core Animation to redraw your contents instead of using a snapshot. If you still have issues, you can try defining a "stretchable" region that is stretched instead of your text.
For example, if you know you have a vertical slice of your view where there is never any text, you can define the content stretch to be in that little section and any stretching only occurs there, hopefully keeping your text intact.
CGFloat stretchStartX = 25.0f;
CGFloat stretchEndX = 30.0f;
/* Content stretch values are from 0.0-1.0, as a percentage of the view bounds */
self.contentStretch = CGRectMake(stretchStartX / self.bounds.size.width,
0.0f,
stretchEndX / self.bounds.size.width,
1.0f);
This causes the your view to be stretched only between x values 25 and 30.