How do you change the coordinates of a UIImageView? - objective-c

I have made a UIImageView show an image of my choosing in Interface Builder.
In code, I want to find a way to change the x and y coordinates of this image view, during the program.
Is it possible to do that?
I've already made a variable
IBOutlet UIImageView *Alan;
but am not sure what to do with it.

Change view's frame property:
Alan.frame = (CGRect){{newX, newY}, Alan.frame.size};
// same as
// Alan.frame = CGRectMake(newX, newY, Alan.frame.size.width, Alan.frame.size.height);
or if you want to set position of view center:
Alan.center = CGPointMake(newX, newY);
P.S. Note also that per objective-c naming guidelines instance variable names should start with lowercase.

Related

UIVIew from XIB with Autolayout to UItableView Header

I am writing because I have a problem with the Auto Layout.
I'm trying to create a simple view in InterfaceBuilder with Auto Layout I want to load code and enter as a header of a table (not as header section). I explain briefly what are the characteristics.
The imageView must be square and must be as wide as the screen.
The space under the picture to the bottom of view that contains the button and label must be high 50 points.
Between image and button has to be a fixed distance of 12 points.
Between image and label must be a fixed distance of 13 points.
All these features are able to get them with Auto Layout. I added a constraint to the aspect ratio of the image (1: 1) and the various constraints for distances. all right.
The real problem is that by launching the app on iphone 6+ simulator (414 points of width), the image (with the label and button) goes above the cells.
Enabling various transparencies I noticed that the superView of Image View, only increase the width. It does not increase its height! How do I fix?
This is the code:
- (void)viewDidLoad{
//...
PhotoDetailsHeaderView *hView = (PhotoDetailsHeaderView *)[[[NSBundle mainBundle] loadNibNamed:#"PhotoDetailsHeaderView" owner:self options:nil] objectAtIndex:0];
hView.delegate = self;
self.tableView.tableHeaderView = hView;
//...
}
This is how I create the xib:
and this is how it is on the simulator, the green box is Uiimageview and the yellow box (under green box) is the mainview (or superview):
How can fix it?
Many thanks to all!
You'll need to add a property to store your PhotoDetailsHeaderView:
#property (nonatomic, strong) PhotoDetailsHeaderView *headerView;
Then calculate its expected frame in viewDidLayoutSubviews. If it needs updating, update its frame and re-set the tableHeaderView property. This last step will force the tableView to adapt to the header's updated frame.
- (void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
CGRect expectedFrame = CGRectMake(0.0,0.0,self.tableview.size.width,self.tableView.size.width + 50.0);
if (!CGRectEqualToRect(self.headerView.frame, expectedFrame)) {
self.headerView.frame = expectedFrame;
self.tableView.tableHeaderView = self.headerView;
}
}
The problem is probably that in iOS you have to reset the header of the table view manually (if it has changed its size). Try something along these lines:
CGRect newFrame = imageView.frame;
imageView.size.height = imageView.size.width;
imageView.frame = newFrame;
[self.tableView setTableHeaderView:imageView];
This code should be in -(void)viewDidLayoutSubviews method of your view controller.

iPhone MKMapView: set span/region value to show all pins on map

I'm working on a project (platform iOS 7) in which i required current location with stores around 5km, so how to calculate the span/region value to display all stores with current location on map.
MKMapRect zoomRect = MKMapRectNull;
double inset;
for (id <MKAnnotation> annotation in mapVW.annotations)
{
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
zoomRect = MKMapRectUnion(zoomRect, pointRect);
inset = -zoomRect.size.width * 20;
}
[mapVW setVisibleMapRect:MKMapRectInset(zoomRect, inset, inset) animated:YES];
this is what I'm trying
Thanks
It's not clear what your exact issue is but the following may help:
The calculation of the inset looks wrong. It's setting the inset (padding on the sides) to 20 times the width of the whole zoom area. What you probably want is to set the inset to a small fraction of the entire width. Maybe you meant 0.20 instead of 20.0:
inset = -zoomRect.size.width * 0.20;
You also don't need to repeatedly set the inset inside the for loop since it only depends on the final width. You can move the above line after the for loop before calling setVisibleMapRect.
You mention some issue with the current location. It's not clear what the issue is but maybe you mean that this zooming code doesn't include the current location? If so, maybe the current location hasn't been determined yet when this code is called. Try moving this code to (or also call it from) the didUpdateUserLocation delegate method. Make sure showsUserLocation is YES and that the map view's delegate is set.
By the way: iOS 7 includes the new method showAnnotations:animated: which automatically determines the bounding rectangle for some given annotations and sets the map's visible region for you. It doesn't let you specify a custom inset like you are doing (though the default isn't bad). So instead of the above loop, you would do:
[mapVW showAnnotations:mapVW.annotations animated:YES];
NSArray *anno_Arrr = mapview.annotations;
[mapview showAnnotations:anno_Arrr animated:YES];

How to have a tiled image for a portion of a window cocoa

I'm new to this and it's hard for me to even ask my question right because I don't know the right terminology. I've done some objective c coding so I'm a little bit beyond beginner except when it comes to working with UIs.
I would like to know the best practices to accomplish this - i.e. the right way.
I have a window with some buttons at the top of it. Below that is a region that will have an image or webview. This will be of variable size so to make it look nice I'd like to have the area behind it have a nice tiled pattern.
I've experimented with a few things that work but everything feels a bit hackish. Is there a control that automatically provides a tiled background and lets me put other controls inside of it? For that matter, is there any kind of control that allows putting other controls inside of it? (I'm used to this in GTK but it doesn't appear to be common in Cocoa)
Also, considering that the image can change sizes based on the buttons above, should I be using core animation and it's layers (I've read about them but not used them)?
One fairly simple way to do this is to use a custom NSView subclass for the background view. In its -drawRect: method, write code to take the image and draw it repeatedly to fill the bounds of the view. The algorithm to do this is pretty simple. Start at the top left (or any corner really), draw the image, then increment the x position by the width of the image, and draw again. When the x position exceeds the maximum x coordinate of the view, increment y by the height of the image and draw the next row, and so on until you've filled the whole thing. This should do the trick:
#interface TiledBackgroundView : NSView
#end
#implementation TiledBackgroundView
- (void)drawRect:(NSRect)dirtyRect
{
NSRect bounds = [self bounds];
NSImage *image = ...
NSSize imageSize = [image size];
// start at max Y (top) so that resizing the window looks to be anchored at the top left
for ( float y = NSHeight(bounds) - imageSize.height; y >= -imageSize.height; y -= imageSize.height ) {
for ( float x = NSMinX(bounds); x < NSWidth(bounds); x += imageSize.width ) {
NSRect tileRect = NSMakeRect(x, y, imageSize.width, imageSize.height);
if ( NSIntersectsRect(tileRect, dirtyRect) ) {
NSRect destRect = NSIntersectionRect(tileRect, dirtyRect);
[image drawInRect:destRect
fromRect:NSOffsetRect(destRect, -x, -y)
operation:NSCompositeSourceOver
fraction:1.0];
}
}
}
}
#end
No control automatically tiles a background for you.
Remember that NSViews (usually subclasses) do all the drawing - so, for instance, that gray area would be a subclass of NSView and you could put the images inside of it.
To actually draw the tiled image (by the NSView subclass), Madsen's method is usable, but not the most convenient. The easiest way is something along the lines of:
NSColor *patternColor = [NSColor colorWithPatternImage:[NSImage imageNamed:#"imageName"]];
[patternColor setFill];
NSRectFill(rectToDraw);
which you should put in the -drawRect: method of your custom view class. It creates an NSColor which represents a tiled image. Note that it can also be a subclass of a scroll/clip view, etc.
I am not too familiar with Core Animation but it is useful for manipulating views, and might be a direction you want to look at concerning the view drawing the image (and that view only).

UIScrollView - Custom Map - Prevent marker subview on map from scaling with map

I have a custom map of a limited area, and have it set up to correctly show the users' location. The map is a 1600px square image within a UIScrollView.
I have a crosshair image to show the current location of the user, which at zoomScale 1.0 is the desired size. When I pinch and zoom the scrollView, the crosshair scales with it. I would like to have the subview remain the same size on screen.
I haven't been able to find any information on this, what would be the best way to go about this?
If there is anything I can provide you with to help the answer, please let me know.
Many thanks!
EDIT -
Having looked in to this further, there is a UIScrollViewDelegate method - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale which I tried using to take the marker's current center and size, then adjust, but this only scales at the end of the zoom. I would prefer to have the marker remain the same size while the user is zooming.
EDIT 2-
Cake has provided a great answer below, but I haven't been able to implement this in the way I imagined it would be.
I have the UIImageView as a placeholder, with alpha set to 0. This placeholder moves around relative to the map to show the user location. This operates as I expect it to. Unfortunately, this resizes with the map, as it is a subview of the map (so it stays in place).
Taking Cake's below answer, I have created the non-scaling crosshair image, and added it as a sibling subview to the scrollview. The maths, once Cake had pointed them out, were quite simple to get the new frame for the crosshair:
CGPoint ULPC = userLocationPlaceholder.center;
float zs = scrollView.zoomScale;
CGRect newFrame = CGRectMake(((ULPC.x * zs) - scrollView.contentOffset.x) - 20, ((ULPC.y * zs) - scrollView.contentOffset.y) - 20, 40, 40);
Where the image is 40points wide. This matches the centers perfectly.
The problem I now have is that I cannot get the crosshair image to stay locked to the placeholder.
I have tried using a self calling animation as such:
-(void)animeUserLocationAttachment
{
[UIView animateWithDuration:0.05
delay:0
options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear )
animations:^{
userLocationDotContainer.frame = newFrame;
} completion:^(BOOL finished){
// Call self
[self animateUserLocationAttachment];
}];
}
As soon as I start scrolling/zooming, this locks the animation so that the crosshair just sits in place until I release the scrolling/zooming, then it correctly updates it's location.
Is there any way I can get around this, or an alternative method I can apply?
Many thanks
EDIT 3 -
I've re-accepted Cake's answer as it covers 90% of the issue. Further to his answer I have implemented the ScrollViewDelegate methods scrollViewWillBeginDragging: andscrollViewWillBeginDecelerating: to scale the placeholder to match the current size of the crosshair relative to the map, show the placeholder (that is a subview of the map image) and hide the crosshair image. The delegate method scrollviewWillBeginZooming:withView: does not show the placeholder because it scales with the map. As Cake recommends, I'll make a new question for this issue.
The counterpart methods (scrollViewDidEndZooming:withView:atScale:, scrollViewDidEndDragging:willDecelerate: and -scrollViewDidEndDecelerating:`) all hide the placeholder, and re-show the crosshair.
The question is old but for the future similar questions I've recently resolved a similar problem applying the hint of Andrew Madsen of another post.
I'had a UIScrollView, with an UIImageView in it. Attached to the UIImageView I had many MKAnnotationView (those are my subviews that I didn't want scaling with the superview).
I did subclass UIImageView and implement setTransform: method like here:
#import "SLImageView.h"
#implementation SLImageView
- (void)setTransform:(CGAffineTransform)transform
{
[super setTransform:transform];
CGAffineTransform invertedTransform = CGAffineTransformInvert(transform);
for (id obj in self.subviews)
{
if ([obj isKindOfClass:[MKAnnotationView class]])
{
[((UIView *)obj) setTransform:invertedTransform];
}
}
}
#end
This works perfectly!
Mick.
Create another crosshair image that's associated with the view or view controller that contains the scrollview. Then have this one always snap to the center of the crosshair image you already have. Then, hide your original crosshair image. Then you can avoid having the scrollview scale the disassociated crosshair, and it should stay the same size.
Relative coordinate systems
Each view in cocoa touch has a frame property that has an origin. In order to position an object owned by one view properly relative to another view, all you have to do is figure out the differences in their origins. If one view is a subview of another, then this isn't too difficult.
Get the origin of the container view
Get the location of the subview inside of the container view
Get the origin of the subview
Calculate the difference in the positions of the origins
Get the location of the object you want to overlap (relative to the subview)
Calculate the location of the object you want to overlap relative to the container view
Move your crosshair to this position
Swift equivalent for Mick's answer:
class MapContainerView:UIView {
#IBOutlet var nonScalingViews: [UIView]!
override var transform: CGAffineTransform {
didSet {
guard let nonScalingViews = nonScalingViews else {
return
}
let invertedTransform = CGAffineTransformInvert(transform)
for view in nonScalingViews {
view.transform = invertedTransform
}
}
}
}

location of a button/textfield in a view in cocoa

I'm sorry to ask such a question, but I can't seem to find the answer for it from the wild web.
I want to find out the location of a NSTextField in my custom view, so I can add other textfields under it programmatically.
The reason I don't just add other textfields in IB, is because I need to be able to dynamically create them.
The NSTextField is linked to an IBOutlet.
So the main question is: How do I find out the location of a NSTextField (or NSButton, it doesn't really matter atm) in a custom view (I need to get the coordinates of the item)?
Make an instance Variable with the NSTextField and then call these methods on it to get the four values you want.
NSRect textFieldFrame = [textField frame];
NSPoint textFieldLocation = textFieldFrame.origin;
NSSize textFieldSize = textFieldFrame.size;
NSInteger x = textFieldLocation.x;
NSInteger y = textFieldLocation.y;
NSInteger width = textFieldSize.width;
NSInteger height = textFieldSize.height;
Every kind of view or control (like NSButton, NSTextField, etc.) that inherits from NSView has a -frame method that contains the positioning information.
If your custom view has an IBOutlet connected up to the NSTextField, you could do the following:
NSRect textFieldFrame = [textField frame];
That NSRect contains all of the information for where the text field is positioned.
See the following 2 guides for more information:
View Programming Guide: Understanding a View's Frame and Bounds
Cocoa Drawing Guide: Coordinate Systems and Transforms
Any view has both a bounds and a frame property. bounds is the rectangle that encloses the view in that view's own coordinate space; frame is the enclosing rectangle in the superview's coordinate space. In this case, you want the text view's frame, i.e. its location and size in the view that contains it, so that you can locate other text views in the same superview.