Correcting blurry text after a CGAffineTransformMakeScale - ios

I have multiple views with many UILabels on the views. (all constructed in Interface Builder).
I am then trying to create a "smaller" replica of my view when you pinch the screen.
To do this I apply:
view.transform = CGAffineTransformMakeScale(.5, .5);
and then I also adjust the frame of view.
The problem is that after the transformation, the text in all of my UILabels becomes "blurry". It doesn't stay pixel perfect as it is in full-scale view.
Is there a way to increase the pixelation of the labels after the transformation?

Applying a transform to a UIView or CALayer merely scales the rasterized bitmap of that layer or view. This can lead to blurriness of the resulting UI element, because they aren't re-rendered at that new scale.
If you really want your text or images to be crisp at the new scale factor, you're going to need to manually resize them and cause them to redraw instead of applying a transform. I described one way that I did this with a UIView hosted in a UIScrollView in this answer.
You might be able to create a single method that traverses your view hierarchy for your one main view, recursively reads each subview's frame, scales that down, and then forces a redraw of its contents. Transforms are still great to use for interactive manipulation or animation, but you can then trigger a full manual scaling and redraw at the end of the manipulation or animation.

Related

CALayer rotation appears to 'lift' it's child above the surface

Here is the iPad Simulator with four nested UIViews, drawing a custom background, and an inner UILabel. I am rotating the top UIView's CALayer, by getting it's layer and setting transform with a rotateY CATransform3D, animated on a separate thread (but the changes to transform are being sent on the main thread, naturally):
Note- this animation does not loop correctly, hence it appears to bounce.
The layers do animate as a whole, but curiously, the first child and it's descendants appear to be floating above the UIView with the transform applied!
The UIViews themselves are children in another UIView, which has a red background. There are no other transformations being applied anywhere else.
The positions for each UIView were set using setFrame initially at the start.
What is causing this strange behaviour, and how can I ensure the child UIViews transform with their parent, giving a flat appearance to the surface as a whole?
Well. Perhaps unsurprisingly I was doing something silly, but since I'd not used CALayer transforms before, I didn't know if things were acting up. I had overridden layoutSubviews on the UIViews I was creating, and the act of rotating the CALayer was triggering this call and then pushing the child components frame around, due to a bug.
The problem is that CALayers don't actually do 3D perspective by default. In order to do that you need to make a minor change to the layer's transform (which is of type CATransform3D)
You want to change the .m34 field of the transform to a small negative value. Try -1/200 to -1/500 as a starting range. If I remember correctly it should be the negative of 1 over the image height/width.
Change the .m34 property of the layer that you want to appear to "come off the page" and rotate in 3D. When you do that the Z setting of the layer does matter, and will both make closer layers bigger and also make layers that are further away disappear behind other things.
I suggest you do a Google search on "CATransform3D m34" for more information. There is a fair amount of information on the net about it.

Smooth scrolling UIScrollView with transparent CALayers

I'm working on an iPhone app which will be displaying large scrollable and zoomable surface containing a grid of pictures and text labels over them. I need to be able to change the position of pictures individually and control the opacity level of labels. I tried to accomplish these goals by using UIScrollView and Core Animation.
The subview of UIScrollView contains two main sublayers: one for displaying pictures and one for the labels. Pictures are CALayers with their contents property set to CGImage and they are added as sublayers to the pictures layer. Labels are CATextLayers and they are sublayers of the second layer. Transparency of the labels layer changes depending on the zoom scale of the scroll view.
And here is the problem: everything works fine when the labels are fully opaque or fully transparent, but when they are semitransparent scrolling starts to be jerky and FPS drops to about 35. Obviously blending of these layers slows everything down, but I couldn't find a way to fix it. I will appreciate any ideas on how to improve the performance in this situation. Maybe there is a better way to draw text labels than using CATextLayer?
Is it possible for you to merge the two "main layers" of your UIScrollView into one? Also, is it possible for you to add layers directly to UIScrollView's layer instead of adding additional ones?
I find that I get huge performance wins by reducing the number of layers that exist for the sole purpose of containing other layers.
One solution is to add a shadow to the most background layers of both image layer and text layer.
There are number of shadow properties that you can tweak i.e. shadowPath, shadowColor, shadowOffset and shadowRadius - set each of them, don't miss any. Also set yourlayer.masksToBounds = NO.
Do not forget to add yourlayer.shouldRasterize = YES because this will have better performance impact.

iOS, UIView animation, animate own content

i have a subclass of UIView that displays own content. I'd like to animate the content.
The content is self-drawn in an own drawRect:, i wonder what possibilities are there to animate it. The content itself consists of graphical shapes that change their form.
I don't see a way to construct the content with subviews that can then be animated themselves.
Is there a way to use an UIView animation block?
Are there other possibilities? I would not want to animate this using OpenGL ES, this would be my last choice.
Thanks for any hints
Torsten
are you sure you can't use CALayer? They are made for this! You can create complex frames/textures (you wrote you have geometric shapes) and apply animated transforms to them.
Consider that if your shapes don't fit in the (really wide array of possibility) of shapes, you can basically draw any line using a CALayer: you create a layer of the proper length and width then simply translate and rotate it as needed (and of course translation an rotation are "animatable").

How to apply 3d perspective transform only in one part of compound UIView?

I have UIView with UIImageViews, UILabels, UITextView.
My goal is to transform the middle part so it would look like folding a piece of paper:
- top and bottom parts remain the same only they slide towards eachother
- middle part folds towards the screen
(as in Clear app: http://blog.massivehealth.com/post/18563684407/clear?cbe4fc38)
My idea was to first load whole view, then split into 4 parts, make middle two parts into CGImage and somehow animate them with perspective while simultaneously transforming top and bottom parts, so they slide towards eachother (in the end, middle two parts should become invisible).
I also should be able to unfold this view and scroll UITextView.
I'm not looking for a ready-to-go answer, just pointers towards correct solution.
I have came across CALayer, CABasicAnimation and CGImage, but yet don't know how to solve this one.
I think your approach is sound. Since you cannot apply a transform to part of a view, you have to split your container view into separate parts. You can use the CALayer method renderInContext: to render a view into a static image. You can then split this image into the parts you need, place the image parts over the original view (or replace the view with the image) and animate the images. When the animation has finished, reinstate the view in its new form.
A few pointers:
convert your UIView into an image: see this post; either you take 4 "snapshots" of your view, or:
1.2 you take one, then crop the resulting image (see here for cropping);
create a new view and add 4 CALayers as sublayers of self.layer; each layer has its contents property set to the corresponding UIImage;
animate the view layers as you need; have a look at this file from the Leaves framework to see how this could be done; basically, this code uses a CATransaction and transformations to animate a property of the layers (which in this case represents the position of one layer respect another), so that when that property value changes, the layers are redrawn accordingly.
Hope it helps.

How to resize a custom UIView and maintain its custom draw in proportion?

I have a custom view with some drawing on it.
I want to resize it to a new proportion and I want the pattern I drew in it's drawRect to also be resized by the same proportion.
Is there anyway I can accomplish this without refreshing and redrawing everything.
This should be happening for you automatically with the default contentMode, which is UIViewContentModeScaleToFill. contentMode determines how to adjust the cached bitmap without forcing a new call to drawRect:. Also see contentStretch which allows you to control which part of the view is scaled.
you will have to redraw it for the new proportion.
For that you have to store the points that made the CGPath and scale the points according to the new proportion and render it again.
Redrawing CGPath needs attention.
If you have used simple moveTopoint / AddlinePoint you can do it just by storing points in an array. You can scale and redraw it later.
If you can used functions like addcurveTopoint etc., storing points in array won't work.A general purpose way is needed.For that you have to use the CGpathApply function. You can see an example it here. http://www.mlsite.net/blog/?p=1312
If you need to zoom and no interation neeeded you can take a scrrenshot and and zoom the image.

Resources