Is it possible to have a variable height UIView mask layer NOT stretch, and perhaps just sit at the top? (For example, a "torn paper" style edge?) - ios

I can't for the life of me figure out how to create such an effect on a UIView that has dynamic height. I want to have the top have a "torn paper" style edge, but the view can be of dynamic height, so when I set the torn paper mask at the top, it gets stretched the full length of the view.
Can I say, "stick to the top", or perhaps designate a portion that is supposed to stretch? Preferably with layers but iOS 8's maskView property works too.

You can set the frame of the layer's mask to anything you want. So that's one way to position it.
Or you could (probably, I haven't tried yet) use a stretchable image view as the mask (- resizableImageWithCapInsets:resizingMode:). That should keep the torn paper edge from stretching.

Related

Make view stand out from the surroundings. Border layer with inverse color?

I have a view (a Button in this case) and the content behind/below it can move around (a ScrollView). The button is just plain white with black text and not bordered with anything. When the content behind the View is white it does not really stand out as I would like it to do. (I can fix this with a black border sure... but...)
I have this idea of having a border around the button that is the opposite color of the view (pixel) behind it. So the border would always contrast with the background and constantly change with the content behind it.
I have googled a bit and looked into visual effects layers and some more complicated (over the top of my head) graphics stuff I don't remember the terminology for.
If you have an idea of how to approach this please tell me. I just really want to see what it would look like.
and have a wonderful day!
I don't think you can create a border that uses colors based on the color of the pixel from the layer behind the current layer using CALayer and borders.
What I would suggest doing is to add a second CALayer to your view's CALayer, inset by -1 in both dimensions (made 1 pixel bigger.) Let's call that the surroundLayer. Then make the surroundLayer's borderColor be white and the view's layer.borderColor be black (or visa-versa.) You can make the surroundLayer's borderColor be 50% opaque so it just lightens/darkens the pixels under it without completely obscuring them, and that is enough to increase the contrast and make your view's border show up regardless of the contents under it.
I've used this technique before and it works well.
Edit:
Check out the project https://github.com/DuncanMC/MaskableImageView.git. The project demonstrates using an image as a mask layer to hide/reveal the contents of a view.
The class MaskableView in that project draws a circular "cursor" that shows where it is revealing/masking the contents of its subview (an image and a label, in the example app.) The cursor is yellow in the middle, with a partly transparent black outer circle around it. This gives good contrast regardless of the colors in the part of the image it is being drawn over.
The MaskableView class has properties that let the caller set the colors use for the "cursor" circle.
Below I posted a short animation of what the eraser tool with a yellow inner circle and an outer, 1/2 transparent black circle looks like.
Without the outer dark circle the yellow inner circle tends to get lost in brighter parts of an image. With the combination of a bright colored inner circle and a partly transparent, dark outer circle, it's easy to see on ANY background:

iOS Understanding Layer Masking

I am having some difficulty understanding on how layer masking works. Right now, I have a UIView with UILabels on it. I picture two layers - one with the UIView in the back and one for the labels on top. If I mask the UIView layer, the labels will be affected by the mask too.
The UILabels are children of the parent UIView, so I can understand a parent mask affecting the children as well.
However, when I look at it in terms of layers, it doesn't seem to make sense. Why does masking the deepest layer affect those on top?
Think of layers as sheets of paper. Think of the view's layer as a big sheet of white paper. As you figured out, the labels' layers are children of the view's layers. To relate, think of the labels' layers being strips of paper glued onto the big view's layer-sheet.
Let's say you wish to mask the layer with a circle. To translate that into our little analogy, you wish to cover the big view's layer-sheet with Harry Potter's invisibility cloak, with a circle shaped hole in it.
To do that, you'd cut the invisibility cloak to the same size as that of your view's layer-sheet.
cloakLayer.frame = bigViewLayer.frame;
Then, you'd carefully cut out a circle from it.
cloakLayer.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0) radius:15.0 startAngle:0.0 endAngle:2 * M_PI clockwise:YES];
cloakLayer.fillColor = [UIColor blackColor].CGColor; // the hole
Then, you'd paste this cloak-with-a-hole onto your big view's layer-sheet, carefully aligning the edges.
bigViewLayer.mask = cloakLayer;
What's gonna go invisible? Anything on the sheet (because the cloak was cut to the sheet's dimensions) that doesn't fall into the circle you removed from the cloak. That's the mask property.
Let's talk about the masksToBounds property.
Let's say while pasting the strips of label layer-sheets onto the big view's layer-sheet, you decided to place only half of the strip on the sheet, and made the rest hang off the edge(s).
Let's say you set masksToBounds to YES. What the gods of decoupage would do now is neatly cut off the parts of your labels' strips that are not within the edges of the big view's layer-sheet. That's the masksToBounds property.
Let's talk about borders. This is simple. Just pick a sharpie of borderColor whose nib is borderWidth points wide, and carefully draw on the edges of the view's layer-sheet. That's it.
I hope you get things now and can make your own analogies for other properties of the wonderful CALayer.
As you said, the UIView is the parent, and the UILabels are the children. When it comes time to update the screen, the UIView starts with a blank canvas. It draws itself into the canvas, and then has the children draw themselves into the canvas. When the children are drawing, they are subject to constraints imposed by the parent, e.g. clipping and masking.
iOS CALayer.mask
[CALayer]
[iOS CALayer.masksToBounds]
CALayer has a mask property which is CALayer, which applies mask's alpha channel to mask parent's layer.
layer + mask = masked layer

Reference enclosing frame in PaintCode expression

I'm trying to use paint code to draw a roundrect with different corner radii. I have nearly everything working by drawing two circles and two roundrects. The problem is I can't make one of the roundrects draw at x offset circle radius have width of "frame.width - circle_radius" - the end effect being it keeps aligned to the right hand edge of the frame.
It feels like I should be able to write frame.width - largeCornerRadius in an expression editor but PaintCode objects to the frame reference.
That said, i's beginning to feels like I could write this code quicker by hand :-)
I don't have an answer to my specific stated question but I have discovered a better way to draw my roundrect as four different rects and turning off the roundrects on the "inner corners:
As you'd expect the drawing code is much better and it resizes well with the enclosing frame.
You can also :
use a set of rect, oval or other shapes
select them and "union" to get one bezier curve for the whole shape
selection each point (or a set of points) of the resulting bezier and fix springs on each of them as fixed or fluid from the edge of the surrounding frame.
I see this question is old, but let me show how to achieve this using Springs & Struts.
Let’s use 2 circles and 2 rounded rectangle, each having only one corner rounded, just like you have. Once you draw a Frame around these shapes, their Springs & Struct inspector becomes enabled.
Here you can click each of 6 segments to toggle fixed or flexible dimension for each shape. For Red Circle, make flexible only top and right margin (just like on the image above) and for Blue Circle the opposite margins (bottom and left). Then for both rectangles make flexible size and fixed margins.
For more information, check out our videos, blog, and documentation on this topic.
– PaintCode Support

Resize UIView so that whatever I draw is visible - ObjectiveC

I have a UIView. I am drawing a line inside the UIView programmativally. But when the line goes outside the UIView, the part of the line which goes out, is invisible. How can I resize the UIView so that whatever I draw inside the drawRect method is visible?
you can change the frame of view. If your line is horizontal then give width to view else increase height of view.
view.frame = CGRectMake(view.frame.origine.x, view.frame.origine.y,view.frame.size.width,lengthOfLine );
If the curve you are drawing is a subview, then you can make use of sizeToFit method. This will make the view's frame enclose the curve(and all subviews, for that matter). Then you can reposition and scale the view's frame to make it fit in the window.
You have mentioned in a comment that you are actually drawing a curve. From what I can tell, you will need to calculate the curve's bounding box yourself.
Based on the bounding box, update the UIView's bounds property (as Durgaprasad suggested). This also resizes the underlying CALayer, which also gives its underlying Core Graphics rendering context a larger bitmap.
Without knowing more about your curve, it's hard to help, apart from linking to some very generic discussion on quadratic Beziers.
You may want to update your question with a minimal implementation of -drawRect: that will allow someone to reproduce your issue.

Correcting blurry text after a CGAffineTransformMakeScale

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.

Resources