Is it possible to increase the clickable area of a UIView subclass?
I would rather do it without subclassing it's superview. Is that possible?
I've seen how to do it by overriding hitTest:withevent: and pointInside:withEvent: on the superview, but as I said, I would rather avoid that.
Why not create a container view that has a larger area, with a transparent background, that contains a subview that has your visible part? This is a quick and easy way to increase the tap area of a button, for instance.
Related
I have a UIButton, for which I have a touchUpInside IBAoutlet function call, and it is embedded inside a view, which is then embedded inside a stackview. I have User Interaction enabled for all three of of the stackview, the view and the button.
However, the touchUpInside function is not called when I click the button. Does anyone know if this has a solution?
With the limited context, I can only give a guess. Perhaps something is blocking the button such as another view on top of it? Sometimes the order of things in your storyboard file can make certain things not register touches.
The container view for the button is likely shrined to a small size and thus it and its subviews do not receive touches. Subviews are displayed because "Clip to bounds" is false by default for all views. So subviews are drawn even outside the bounds. The easiest way to check is to give a container view a background color.
If this is the case, then there are several ways to resolve the issue:
Set a reasonable constraints to the container. Stick to nearest neighbour boundaries, for example. Or set a minimum size.
Set a size for the container view.
If the container view is inside UIStackView you can set Alignment = Fill, (not Center) which will make the container view take the space suggested by UIStackView.
I am exploring the idea of drawing some custom primitives (using CGContext) on a view that is scrollable and larger than the phone screen width.
The idea would be to use the "power" of a UIScrollView by programmatically scrolling the content of the view as the content is added and decouple in this way the scrolling handling (and general UI interaction with the view) from the content drawing.
Is this a feasible approach in iOS?
Yes it is. The easiest approach AFAIK would be to add a UIView onto the UIScrollView. You would then draw on that UIView instance - after drawing another part of your graph/image you would need to inform the containing scroll view, via a delegate for example, that it needs to update its contentSize. This would of course be the size of the UIView upon which you drew. The update is needed, beacuse it seems that you may need to increase your drawing area size as you do it.
I have a custom view with custom popup on it (added as subview).
When I'm opening this popup it's frame goes out of parent view frame.
And I can't handle user interaction on the outside popup view.
How can I fix it?
I thought about this plan:
1. Add custom view on superview;
2. Add custom popup on superview (right the position where it should be on custom view)
But i think it isn't right way.
Any suggestions?
To be honest I haven't tried it yet, but you might have luck with adding a custom view on the superview and overriding pointInside:withEvent:.
I'm thinking the superview is recognizing that the tap doesn't occur inside its own frame, so it won't even check its subviews. But if you override pointInside:withEvent: you can check that the tap location is inside the subviews frame regardless of whether it's inside the superview's frame.
If that doesn't work, you might have to override hitTest:withEvent: also (or instead of). I can try to work out an example if you need more direction than that.
This Technical Q&A might help you out https://developer.apple.com/library/ios/qa/qa2013/qa1812.html
What you mention is actually the right approach: you should have a superview (it can be transparent (clear color)) that contains both the custom view and the popup inside of its frame.
On iOS, touch events are sent to a receiver at a low level in your visual hierarchy (I believe this is your Window to be specific). This receiver calls HitTest on its subviews to figure out which one to forward the event to. This happens recursively until the HitTest fails on all of a view's subviews. Then the parent of those subviews handles (or doesn't handle) the touch event.
But before the HitTest implementation even starts calling HitTest on the subviews, it calls PointInside on the superview. If PointInside returns false for the touch point, then HitTest returns null.
So overriding PointInside on the class that you call SuperView may solve the problem you're facing, but not necessarily. You may need to override PointInside on the superview of SuperView, and then on that view's superview, and so on. This is not a good solution, it is brittle and hacky. Overriding PointInside does have its uses, but this isn't one.
So try to keep all of your views within the bounds of their superview, even if you have to make a transparent superview that has no other reason to exist other than to contain other views. That's fine.
In my iOS app I want my users to be able to zoom in on the screen. My main uiview contains several subviews which contain images. I want my uipinchgesturerecognizer to either change the scale, or ideally use some "zoom" rather than scaling each subview.
Please and thank you.
This can be accomplished with UIScrollView. First create a scroll view as the base of your view hierarchy, putting your previous container view as a subview of the scroll view. Set the delegate of the scroll view to self and implement the delegate method viewForZoomingInScrollView, in which you should return the view that will be zoomed in (your original container view). This will allow the user to pinch and zoom your original UIView.
It's hard to provide advice on this without having a clearer view of what exactly you want to achieve.
Can you include a link to a sketch? For example, do you want the individual subviews to remain the same size but the layout to change ? Do you want the individual subviews to resize but their contents to be upscaled?
If you simple want to treat the subview as (basically) a single image which just happens to have other images in it, then maybe it would be better to render it as one and then scale that?
I created a container view that holds a bunch of child views - a collection view, a custom toolbar and some bits and pieces.
The design has a border on the top, left and right sides, but not the bottom, so I overrode drawRect to include border.
When I added the toolbar I noticed that it appears over the top of the border. (For some reason I initially thought it wouldn't but of course it does!).
Is there anyway I can tell drawRect to draw over the top of my subviews?
Of course there's loads of other ways to solve my problem (adjust the toolbar's frame for example) however I'm asking this question in order to get a deep understanding of how drawing works in relation to compositing and the view hierarchy.
Drawing happens beneath all subviews of a UIView. Think of it as being on the very base - an actual part of your view - and then each subview is added on top of your view. To make the drawing above the subviews is the same as wanting for the subviews to appear under the view, while still being subviews. Perhaps that analogy makes it clearer why it must always be on the bottom. And it also leads you logically to the solution:
To get the drawing to appear above subviews, simply create a new UIView subclass to place the drawing code inside, and place this above all other subviews.
It might also be a good idea to override your UIView's addSubview: implementation, to ensure your subview always remains on top.
I believe you can't, since the drawRect is called first for the view and when it has finished drawing drawRect is called for subviews to draw over it. Maybe just make another subview on top of that view that has the borders you need and is transparent everywhere else?
Subviews are drawn on top of their super views. So the answer to your question is no.
At the time when you draw the border on your container view, Cocoa hasn't even started drawing the toolbar yet.
I guess you could make the top of the border a subview or move the toolbar down a bit.