IOS: Animate UICollectionViewCells to slide when changing orientation - animation

I'm looking to override my UICollectionViewFlowLayout to cause the cells to slide when changing positions due to an orientation change. What I have currently is 3 cells per row in portrait and 4 cells per row in landscape but the only animation I can get is the default fading in when I change orientations.
I've been looking at using performBatchUpdates but I'm pretty sure that's not where I'll find the answer.
I've also been looking into the layoutAttributesForElementInRect and layoutAttributesForItemAtIndexPath which I think is where I'll find the answer. I'm not sure if I'll need to create a new attribute for the cells (previousCenter maybe) and use that as the starting point for new animations or maybe use performBatchUpdates using what should be the new frame as the value to change.
For the record all animation questions I've found have been about how to change animations for insertion and deletion of items which is not what I'm wanting to do.

Try
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:( NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self.collectionView reloadData];
}
and then add whatever you need to "slide" it at that point.
If you are using flowLayout or a subclass of it, it should automatically reposition the cells for you.If you subclass layout you might need to adjust the layoutattributes you return to correspond to the rotation. The animation should be done for you though.

Related

How do I optimise Cocoa drawing to ensure smooth scrolling

I am drawing graphs on NSView using standard Cocoa drawing APIs. See image below. There are multiple graphs on the NSView which is in a scrollView. Each graph has around 1440 data points and scrolling performance struggles a bit because of redrawing that is being done.
Is there any way to ensure the graphics are only drawn once such that the image can be scrolled up and down smoothly ?
This same view is used to generate a PDF output file.
Given the drawing does not actually need to change unless the view is resized, and this does not happen, is there any way to prevent the view from redrawing itself during scrolling. Hopefully there is a simple switch to ensure the view draw itself once and keeps that in memory!?
The basic code is in the NSView subclass draw() function.
override func draw(_ dirtyRect: NSRect) {
drawAxis()
// Only draw the graph axis during live resize
if self.inLiveResize {
return
}
plot1()
plot2()
plot3()
...
}
func plot1(){
for value in plot1Data {
path = NSBezierPath()
if isFirst {
path?.move(to: value)
} else {
path?.line(to: value)
}
}
}
Apple has pretty comprehensive advice in their View Programming Guide: Optimizing View Drawing article.
It doesn't appear that you're taking even the minimal steps to avoid drawing what you don't have to. For example, what code you've shown doesn't check the dirtyRect to see if a given plot falls entirely outside of it and therefore doesn't need to be drawn.
As described in that article, though, you can often do even better using the getRectsBeingDrawn(_:count:) and/or needsToDraw(_:) methods.
The scroll view can, under some circumstances, save what's already been drawn so your view doesn't need to redraw it. See the release notes for Responsive Scrolling. One requirement of this, though, is that your view needs to be opaque. It needs to override isOpaque to return true. It's not enough to just claim to be opaque, though. Your view actually has to be opaque by drawing the entirety of the dirty rect on every call to draw(). You can fill the dirty rect with a background color before doing other drawing to satisfy this requirement.
Be sure the clip view's copiesOnScroll property is set to true, too. This can be done in IB (although it's presented as an attribute of the scroll view, there) or in code. It should be true by default.
Note that the overdraw that's part of Responsive Scrolling will happen incrementally during idle time. That will involve repeated calls to your view's draw() method. If you haven't optimized that to only draw the things that intersect with the dirty rect(s), then those calls are going to be slow/expensive. So, be sure to do that optimization.

Trouble with Auto-Layout

Xcode 5
I'm trying to learn the auto-layout system. Thought I would start with something simple, but I'm already getting stumped :-)
Scene: Main View -> ImageView -> View
I want to support rotation such that the Image rotates and centers on the screen, using Aspect-Fit content.
I want the smaller view to maintain it's relative position to the top edge of the UIimage view. It does't seem to understand the aspect-fit, and it aligns the sub view along the top of the main view, not the fitted image.
I think it has something to do with the fact that the small view is a sibling of the Image, and not a sub-view. I can only seem to create constraints to the superview.
.
You haven't started with something simple!
An aspect fitted image view doesn't actually change its size under auto layout depending on the image, it fits the image into the bounds that the constraints have determined, leaving the rest of its frame blank. If you set a border or background colour on the image view you will see this.
To achieve the effect you're after you would need to do the aspect fitting calculation yourself and modify the sizing constraints on the image view appropriately.

How to animate horizontal bar with right cap, by UIView animation in iPhone

I got wiered but unsurprising animation from call UIView animation, I don't know if it works the same by using CALayer animation. I guess it is.
please see this picture: what I want is to animate a horizontal bar growing horizontally, what I do is:
Subclass a UIView, called UIViewBar, and in its drawRect:rect method, I draw the shape of rectangle and a right cap, it's done by
CGContextMoveToPoint A
CGcontextAddLineToPoint B
CGContextAddArcToPoint D
CGContextAddLineToPoint C
//then close the path and fill the context
Then I call this UIViewBar (initWithFrame:rect) in my UIViewController, and the shape is what I want, looks fine. BUT when I perform [UIView animation] say from original rect to rectGrew it does not perform nicely. Instead, it perform as the picture says.
Well, after thinking, it's not totally unreasonable because when the UIView horizontally stretches itself, it does not know the cap will not be changed. So is there another way to do this?
Actually, I'm very new to drawing, graphic, and animation. What I know is that (if wrong please kindly correct me):
If I want to "draw something", I should override the UIView's drawRect method, and this is done by initing the UIView, should not or better not to be called outside. Say I drew a rectangle in a UIView by CGContextFillRect.....
But what if I want to animate this rectangle? I cannot make animation based on Quartz2D, but from UIView animation or CALayer(deeper tech), so What I have to do is to make the rectangle itself as a seperate UIViewRect seperately, so I can call the [UIViewRect animation] method, AM I RIGHT ON THIS
If so, I have to make every rectangle that I want to animate to be UIView respectively. Doesn't it affect performance? Or it is just the way apple prefers to do ?
Any suggestion will be much helpful, GREAT thanks.
Wow, it's the first time that no answer posted at all! TO answer my question: it requires to consider animate custom property of CALayer. The custom property is the AB width (the width without cap width, that should work). If someone wants detailed code. Please google custom property animate in CALayer.

How to set NSOutlineView to consider minimal content's widths with autolayout?

I have NSSplitView with NScrollView inside it and view-based NSOutlineView inside NSScrollView, it has e.g. one column. My outline view must be scrollable vertically only and it must consider minimal width of column content to fit it. I think they must return -(NSSize)fittingSize with values {minColumnWidth, 0}, but it returns {0,0}. How can I do that?
Try to return the desired view size in (NSSize)intrinsicContentSize. I am not sure if I totally understand your scenario. You could add a screenshot or wireframe to make it easier to understand the setup. Whatsoever, take a look at my question dealing with a similar problem.
Maybe also check out the WWDC Session 232 - Auto Layout by Example. It covers a new split view API together with Autolayout (starting around 41:00 minutes).

How can I add a UILabel so its text is 2 pixels below the "text" of another UILabel?

I've really searched for an answer to this one but not come up with anything solid so here goes.
I'm dynamically adding UILabels to a view, they could be any size.
I would like the second added one to be placed about 2 pixels below the last regardless whether there is letters that go bellow the line.
I've tried using various method the get the labels frame after it has been sized to font but with no look. The frame always seems to be bigger than the actual text vertically.
Have you guys got any ideas?
First, I'd try setting the label's adjustsFontSizeToFitWidth to NO and see if that it will allow you to mess up the normal proportions, as seems to be your goal.
If that doesn't work, you probably need to draw the string to a CALayer. Create a CALayer and add it to your view's root layer, i.e.:
[yourView.layer addSublayer.yourNewLayerForString].
Set the sublayer's delegate to the class which will do the drawing:
[yourNewLayerForString setDelegate:self];
And implement drawLayer in that class (the one you assigned as delegate). The drawLayer code can be kind of ugly, but you can find examples out there for how to draw a string in a layer. This one looks good: addTextToLayer.
You will then have exact control over the font and string size, and can adjust the layer frame and the view frame to suit your aims.

Resources