iOS: UIView's origin with respect to UIWindow - iphone

A UIView has an origin contained in its frame or bounds properties with respect to its superview. Say I want to do something which grabs the origin of a UIView with respect to the UIWindow instead. Do I have to go each step up the hierarchy in order to make this calculation or is there a simpler, more direct way?

I guess you looking for this method
convertPoint:toView

to find out where a view aView is in the application window, try
[aView convertRect:aView.frame toView:[UIWindow screen]]
This method is in the UIView Class Reference

The best and easiest way to do this is by using convertPoint:toView or convertRect:toView on UIWindow. In order to do this correctly, you need to supply a view whose window matches the window of the view whose coordinates you are trying to convert.
For your question, you need to know a view's origin with respect to its location in the window. Thankfully, you don't need to know the window in order to get this. According to the documentation of UIView's convert:to methods.
The view into whose coordinate system point is to be converted. If view is nil, this method instead converts to window base coordinates. Otherwise, both view and the receiver must belong to the same UIWindow object.
This means that you can just supply nil to achieve what you need!
In Swift:
let pointInWindow = yourView.convert(.zero, to: nil)
In Objective-C:
CGPoint pointInWindow = [yourView convertPoint:CGPointZero toView:nil];

Related

Beginner confused about allocation notation

I was reading the Apple Documentation and came across this line:
SKView *spriteView = (SKView *) self.view;
I'm not confused about SKView, but rather the notation that is used. I have never seen it before and do not know what its called or how it works. Normally, if I wanted to create a view, I would do something like:
UIView *view = [UIView alloc]init];
Can someone explain the differences between the two notations or breakdown the first notation? I've seen this used in UIColor a lot as well. I don't know what this is called so I'm not exactly sure what I would have to search.
Normally, if I wanted to create a view...
The notation you're asking about, self.view, doesn't create a view directly. Dot notation is a simple way to access an object's properties. It's exactly the same as [self view]. The object that is self in your example is probably a view controller, and therefore has a view property which is accessed via a -(NSView*)view method and set via -(void)setView:.
Now, view controllers are lazy about loading their views -- they don't load (or create) the view they manage until it's needed. So, the -(UIView)view accessor looks something like:
-(UIView)view
{
if (_view == nil) {
[self loadView];
}
return _view;
}
So it's not the dot notation that creates the view, it's the fact that you're calling the -view method. Of course, since the view property is declared as a UIView* but your view controller manages an instance of SKView, you need to cast the value to SKView*.

iPhone scrollView add elements dynamically with id

I want to populate a scrollView with quite a few different UI elements.
Therefore I thought I would write a method that remembers the current Position in the scrollView and just adds the element to the scrollView at the current Position.
Something like:
- (void)addUIElement:(id)element withWidth:(CGFloat)width andHeight:(CGFloat)height andYGap:(CGFloat)YGap {
element.frame = CGRectMake(currentScrollPos.x, (currentScrollPos.y + YGap), width, height);
[scrolly addSubview:element];
//And then set the current scroll position here
}
Unfortunately when I try to do access element.frame = ..., I get request for member in something not a structure or union. When I try to do [element frame] = ... Lvalue required as left operand of assignment.
Now, first of all I am not sure what's the best way to dynamically add objects to a scrollview. Maybe anyone has a better or easier approach.
Then on the other hand, I don't get why the above does not work?! Would I have to cast my element to the actual class? I thought I would not have to do so... Also then my method would not make that much sense anymore. Or at least would require some more steps...
This should work I think:
[element setFrame:...];
However if you work with different UI elements in your method may be you can make your elements parameter UIView* instead of id? This way your code will work for all UIView subclasses (which is what you actually need I suppose)
The difference is that "id" doesn't have any kind of reference to a frame. It could be anything. You want to instead do (UIView *)element in the method declaration, or alternatively in the call to element.frame, you would do ((UIView *)element).frame.
(And yeah, all things that you put on the screen are inheriting from UIView -- UIButton, UIImageView, etc.)

How to know when a subview becomes its coordinates in its parent view?

I would like to find a way for the following problem: If I add views (annotation views) to a parent view (map view) I can't have their positions immediately but at some point in the furute (when the view becomes visible, makes it layout, whatever ...). I would like to be triggered if the position of my subviews becomes available (I mean sview1.center.x, sview1.center.y). Is there a smart way?
There is one possibile way:
Use the UIView's subviews function (it returns an NSArray containig all the subviews) and enumerate through it and check all the views

Re-ordering a collection of UIView's based on their CGPoint

I have a NSMutableArray that holds a collection of UIViewControllers
Amongst other properties and methods an instance of each of the viewControllers are placed in a parent view
The user will place these objects individually when desired to.
So essentially I use - (void)addSubview:(UIView *)view when a new view is added to the parent view controller.
Because the UI is isometric it's made things a tad more complicated
What I am trying to do is re-order the views based on their co-ordinate position, so items higher up the parent UIView frame is indexed lower then views lower in the parent UIview frame. And items that are on the left side of the view are positioned at a higher index to those on the right
I think the solution may have to do with re-ordering the NSMutableArray but how can I compare the CGpoints? Do I need to compare the x and y separately?
So users can drag views around inside a parent view? And when a view changes position, you want to change its place index among the subviews so that the draw order will be correct?
You can use -(void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2 do do this. It won't be enough to just reorder them in you array, since the parent UIView has its own array to keep track of the views. You should create a reorder method where you switch the views around both in your own array and in the parent view.
There are functions for checking equality of points, inclusion of points in rects, intersection of rects, etc, but here it just sounds like you want to get the origin.y point and use that to compare which views are further "back" or to the front...
As an aside, you might want to look at using CALayers, which have support for setting a z position as well.
This might be a simplistic answer, but maybe it's what you're looking for.
Assuming you have access to their CGpoints, you could write a...
-(NSComparisonResult) compare: (NSObject *) incoming;
method in every delegate that looked at the CGpoints of the incoming and "self" and returned a NSComparisonResult. Cool thing about this would be that you could just run...
[myMutableArray sortUsingSelector:#selector(compare:)];
anytime anything changed. You just have to setup the compare: method to return the right NSComparisonResult.
I've managed to resolve this, I did some reading on Key-Value Coding
I created a property called itemY to store the view.frame.origin.y value.
I created a method to re-assign the itemY with the current view.frame.origin.y value.
Now the ViewController that stores the array of ViewControllers uses a instance NSSortDescriptor with the property itemY.
A new NSArray is created using the NSSortDescriptor
Now I loop through the new NSArray and carry out my logic

What UIView is returned when using -viewWithTag: when several views have same .tag?

Say I have 4 UIViews, made in IB, all with the tag property = 2
When I get a view with:
UIView *thisView = (UIView*)[self.view viewWithTag:2];
What is the criterion for retrieving that UIView since several have the same .tag value?
Is it:
random
the first one created
the view with the lowest index in it's superview
something else
Its weird but the view that is added first will be returned if you try to get the views among the views with same tag. You can check it in this way too.
NSLog(#"%#",[[self.view viewWithTag:custTag] class]);
Hope this helps.
If you use Interface Builder, it depends which order you use. In my case, UIActivityIndicator will be my result, and not UIWebView or UIButton with the same tag.
if I had to guess, I would assume that it would be almost-random. as in, you'll probably get some amount of consistency, but every so often it'll be something completely different (heh).
I'd say use different tags for them?