Best practical way to draw line over UIImageView? - ios

I've been reading a lot of posts here and I see conflicting information.
I'm trying to draw a line over a UIImageView which already contains a picture.
I'll need to draw the line either horizontally, vertically, or not at all based on user selection, without disturbing the existing picture.
Some responses say to draw into the UIImageView directly, some say to subclass a UIImageView or UIView, and still others say to create a view layer.
What is the Best Practice for this, and can you also point me to a tutorial?

Since you need to pan/zoom the image underneath, I suggest you implement a stack like this:
[UIScrollView] on the bottom
[UIImageView] inside the scroll view for pan/zoom
[UIView] on top of the scrollview - for drawing the line
(see this tutorial for line drawing).
Personally I've used this project for implementing pan/zoom -- it's well implemented and takes a lot of the guess work out of it.

The easiest way to do this, since you only want to draw a horizontal or vertical line, is to add a subview to the UIImageView. If you want a horizontal line, set the subview's height to 1-2 points and set the width to the image view's width. If you want the line to be vertical, set the subview's height to the image view's height and set the width to 1-2 points. Set the subview's background color to whatever color you want the line to be.
A subview always appears on top of its superview.

Related

Image is not working as expected with constraints

I have a root UIView (for rendering shadow) and it's content is another UIVIew that contains a UIImage and some labels at the bottom. When I look at a sample poster with my constraints set up in interface builder, it looks more or less how I want it.
In this screenshot, the DropshadowUI View holds the content and renders a shadow. The CardView holds both the UIImageView and the UILabels at the bottom. The DropshadowUI View is transparent, the CardView has a blue background and is the full height/width of the dropshadow (w/ a little bit of margin) and the UIImageView has a green background to help distinguish the views while testing. You can see that the UIImageView takes up roughly 80% of the CardView layout, which is desired. The rest of the CardView is made up of the UILabels.
When I run the app however, the constraints don't seem to be working the same way as shown in interface builder. The UIImageView stretches to take the entire height of the CardView. The UILabels are hidden from sight because of this. Judging from the green blur behind my UINavigationBar and UITabBar, it appears that the UIImageView is stretching vertically beyond the extents of the visible area, despite the image not even being that large.
The UIImageView image is set in the interface builder for now (will be set programmatically when this is working). The Content Mode is Aspect Fit. Why does the UIImageView stretch vertically? The Status label has a Bottom Space to bottom of Superview set at 8 points. The Year label's Bottom Space is constrained to the top of Status. The Movie Titles bottom is constrained to the top of Year. Movie Title has it's top constrained to the bottom of the UIImageView. The assumption was that the labels would prevent the image view from growing on the bottom, and instead getting taller by stretching the top (which is constrained to the superview views top.
Is there something wrong with my constraints? I'm still learning the auto-layout system, so if there's something in the screenshots that don't help explain my constraints, let me know what I could do to help clarify them.
Edit
I reset the UIImageView to the suggested constraints and ended up with this at runtime, despite the design-time view looking correct.
Is there a way for me to constrain the UIImageView so that the image can only grow taller, until it runs out of space to fit the rest of the content? I'm missing my bottom label here because now the image is fitting into the UIImageView but pushing everything else to far down. I'd rather it try to fill as much horizontal space as it can, until the siblings beneath it can no longer be pushed further down.
What I get, vs what i want
Select your image and go to Layout Issues tool > Reset to Suggested Constraints

How do I make two equally sized imageviews cover the whole screen

I implemented a viewcontroller similar to the one in this question:
iOS two views cover exactly half of parent view
I get the desired result. The problem is that when I add a UIImageView into those two containers, the result get resized and ruins the symmetry. How do I prevent Imageviews from changing the size of their containers? I need to use AspectFill for these images.
I don't think the containers' sizes are changed. You just need to set their clipsToBounds property to true to avoid overflow.
If you use Reveal you should see the containers' sizes are not changed even if pictures inside them are bigger than themselves.
I'm unsure I understand what you mean about adding UIImageView into those controllers causing the views to resize, so forgive me if I'm getting this all wrong...
It sounds as though you've created two views of equal height that, together, consume the entire vertical space of the screen. After having done that, you want to add one or more UIImageView's to each of the original two views. Unfortunately, when you add the UIImageView, the enclosing view is resized.
Assuming I have that correct...
Are you doing this with Interface Builder either in an XIB or Storyboard file? If so, you ought to be able to achieve this with the proper set of constraints.
In the following image, I've laid out what I describe above.
As you can see, I have a red view on the top half of the window and a green view on the bottom half. The red view contains a UIImageView that is 75% of the width and height of red view, with its origin at (20, 20) within the red view.
The scene is configured as shown below:
The constraints on "Upper View" are:
You can see from this that Upper View is flush with the left, right, and top of its superview, and that its space to Bottom View is 0. You'll have to trust me that Bottom View is set up the same way.
The height of the Upper and Lower views is "Proportional" as shown in this constraint:
To achieve this "Proportional" setting, you first make the height of Upper View equal to the height of the superview, and then edit the constraint, changing "Multiplier" from "1" to "0.5."
The height (and width) of the Image View is proportional to that of the Upper view, as shown here:
If you set it up this way, you ought to be able to accomplish what (I think) you are looking to accomplish.
If my original assumption of what you are trying to achieve is incorrect, please post images of what you've got and how it's not working.

Pixel Perfect UILabel

Here are two labels stacked directly on top of each other, with their backgrounds colored:
I always design my apps in Photoshop first. That dead space on the top and bottom of the labels makes it extremely difficult to position text precisely as in the design. How can I compensate for that top and bottom space when I want to place the label by top or bottom of the text?
Try calling -sizeToFit on the label in order to resize it.
Call this method when you want to resize the current view so that it
uses the most appropriate amount of space. Specific UIKit views resize
themselves according to their own internal needs. In some cases, if a
view does not have a superview, it may size itself to the screen
bounds. Thus, if you want a given view to size itself to its parent
view, you should add it to the parent view before calling this method.
Either use AutoLayout to size your labels exactly at the content size, or use sizeToFit in code and position your labels accordingly.
Can you not create a background UIView with the background colour, and then add the label as a subview of the background view?

clipsToBounds only verticaly

I would like to be able to set clipsToBounds at NO for an UIView but only with the horizontal component.
My content will be displayed on left / right even if it's too large but top / bottom will not be displayed beyond the container's height.
Should I use maskToBounds layer property and add a specific mask ?
You should start by asking yourself why you think you need this. If you want to display the horizontal content when clipsToBounds is YES, why not make the view big enough horizontally? It can go right off the screen on both sides, no problem. A view that is visible when it is not inside its superview is usually a very bad idea in any case (for example, the user can see it but can't touch it, which is usually undesirable and confusing).
Otherwise, this is going to be a very tricky problem. You will probably need to put another view above your view and another view below it, to cover the content that sticks out above and below your view. Crude but effective.
Use UIView's mask property. See documentation
The mask view's width can be maximal, and the height can be the same as the view itself.
maskToBounds needs to be false in this case.

Set UIView height based on inner view height using constraints

I have one UIView and inside that, N UILabels which are laid out relative to each other.
The containing UIView has a background color, I want to extend the UIView to be high enough to cover all labels inside it, so the background color is behind them all.
(I'm embedding them in a UIView so I can have the labels inset from the view edges.)
Is there away to make the UIView's height expand to fill its content? I can't figure it from the constraint options, it seems like its all relative to superviews.
Normally I'd just work out the frame sizes programatically in viewDidAppear but those are getting reset by the constraints system, AFAIK.
I think I actually worked it out though.
I had the labels height set manually from when I drag-dropped and resized it. Deleting the height constraint on the UILabel made it size to fit content, which causes its superview to resize too. At least I think that's the case, I'm new to constraints.
Will leave the question up since it will probably bite someone else too.

Resources