I am trying to think through this fun "problem".
I have a UIView (288x36) that will hold up to 8 UIImages (36x36).
Any number (up to 8) can be placed in the UIView.
I want the "collection" of these images to be centered in the UIView.
If there is only 1 image, then it's center will be in the center of the UIView. If 2, then the max width of the image will be in the center of the UIView and the 2nd images starting point will also be in the center, etc etc.
Has anyone dealt with this before? Any code examples.
I am not very advanced but trying to learn.
Suppose your UIView is called view and your array of images is imageArray:
float remainingSpace = view.bounds.size.width - imageArray.count*36; //This is the space to remaining
float spaceOnLeft = remainingSpace/2.0; //Just the space to the left of the images
for (UIImage *image in images) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(spaceOnLeft, 0, 36, 36)];
imageView.image = image;
[view addSubview:imageView];
spaceOnLeft += 36.0; // so the next image is spaced 36 points to the right
}
Related
I am making a words match app in iOS in which i have two parts of words strings and I want to make a complete word from two labels of random words so for all is fine.
Now I want to make a rectangle at run time as a target of draggable label, when I click on label to drag it the rectangle should become hi-lighted with the same size as the size of label of words.
How can i achieve this in objective-C?
For more clearness you can see in image where I want to make this green rectangle at run time to drop the right side labels in it
The left side labels are not moveable and should always in the rectangle as you see in given image.The code so far i try to make the rectangle as a UIView in viewDidLoad as
for(int i = 0; i <5;i++){
customView = [[UIView alloc]initWithFrame:CGRectMake(10,y,50, 30)];
customView.backgroundColor = [UIColor greenColor];
[gameLayer addSubview:customView];
y = y+40;
}
But this is not what i actually want. Any help appreciated...
Finally i got the rectangle size same as the size of tapped label as here, i make an array in .h file which contain the reference of my target rectangle NSMutableArray *rectangleLabels
after that i make the size of rectangle same as the size of my draggable labels using a loop in tapped gestures method and it works fine...
-(void)gotTapped:(Id)sender {
for (UIView *v in rectangleLabels) {
v.hidden = !v.hidden;
UILabel *tapLbl = (UILabel *)[sender view];
CGRect rect = tapLbl.frame;
for(int i=0;i<rectangleLabels.count;i++) {
UILabel *lblChange = (UILabel *)[rectangleLabels objectAtIndex:i];
lblChange.frame = CGRectMake(lblChange.frame.origin.x, lblChange.frame.origin.y, rect.size.width, rect.size.height);
}
}
}
All the similar questions on SO and on the net are regarding placing a UILabel on a UIImageView, which is something i am familiar with, however i have to place multiple UILabel's on multiple UIImageView's. One on each UIImageView. I have a for loop like this:
for(int i=0;i < [arrURL count] ;i++)
{
UIImageView *view_Image = [[UIImageView alloc]initWithFrame:CGRectMake(x, y, 400, 180)];
y = y + 182;
view_Image.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:arrURL[i]]]];
UILabel *lblName = [[UILabel alloc] initWithFrame:CGRectMake(view_Image.frame.origin.x, view_Image.frame.origin.y, view_Image.frame.size.width, view_Image.frame.size.height)];
[lblName setText:arrNames[i]];
[view_Image addSubview:lblName];
[mainScroll addSubview:view_Image];
}
When i run the code, the UILabel appears on only the first UIImageView, for the rest the UIImageView appears on the top of the UILabel. (I found this by adding background color to the UILabel). How can i make the UILabel's appear on the UIImageView. Thanks in advance.
A view's frame is in it's superview's coordinate system. So each image view's frame is in mainScroll's coordinate system.
Since each of your labels is a subview of a separate image view, each label's frame is in the coordinate system of its parent image view. But you are acting as though the label's frame is in the coordinates of mainScroll.
UILabel *lblName = [[UILabel alloc] initWithFrame:view_Image.bounds];
I start out with an imageView.image (a photo).
I submit (POST) the imageView.image to remote service (Microsoft face detection) for processing.
Remote service returns JSON of CGRect's for each detected face on the image.
I feed JSON into my UIView to draw the rectangles. I initiate my UIView with a frame of {0, 0, imageView.image.size.width, imageView.image.size.height}. <-- my thinking, a frame equivalent to the size of the imageView.image
Add my UIView as a subview of self.imageView OR self.view (tried both)
End Result:
Rectangles are drawn but they do not appear correctly on the imageView.image. That is, the CGRects generated for each of the faces are supposed to be relative to the image's coordinate space, as returned by the remote service but they appear off once I add my custom view.
I believe I may have a scaling issue of some sort as, if I divide each value in the CGRects / 2 (as a test) I can get an approximation but still off. The microsoft documentation states the detected faces are returned with rectangles indicating the location of faces in the image in Pixels. Yet, aren't they being treated as points when drawing my path?
Also, shouldn't I be initiating my view with a frame equivalent to the imageView.image's frame so that the view matches an identical coordinate space as the submitted image?
Here is a screenshot example of what it looks like if i try to scale down each CGRect by dividing them by 2.
I am new to iOS and broke away from the books to work on this as a self exercise. I can provide more code as needed. Thanks in advance for your insight!
EDIT 1
I add a subview for each rectangle as I iterate over an array of face attributes which include the rectangle for each face via the following method, which gets called during (void)viewDidAppear:(BOOL)animated
- (void)buildFaceRects {
// build an array of CGRect dicts off of JSON returned from analized image
NSMutableArray *array = [self analizeImage:self.imageView.image];
// enumerate over array using block - each obj in array represents one face
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// build dictionary of rects and attributes for the face
NSDictionary *json = [NSDictionary dictionaryWithObjectsAndKeys:obj[#"attributes"], #"attributes", obj[#"faceId"], #"faceId", obj[#"faceRectangle"], #"faceRectangle", nil];
// initiate face model object with dictionary
ZGCFace *face = [[ZGCFace alloc] initWithJSON:json];
NSLog(#"%#", face.faceId);
NSLog(#"%d", face.age);
NSLog(#"%#", face.gender);
NSLog(#"%f", face.faceRect.origin.x);
NSLog(#"%f", face.faceRect.origin.y);
NSLog(#"%f", face.faceRect.size.height);
NSLog(#"%f", face.faceRect.size.width);
// define frame for subview containing face rectangle
CGRect imageRect = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
// initiate rectange subview with face info
ZGCFaceRectView *faceRect = [[ZGCFaceRectView alloc] initWithFace:face frame:imageRect];
// add view as subview of imageview (?)
[self.imageView addSubview:faceRect];
}];
}
EDIT 2:
/* Image info */
UIImageView *iv = self.imageView;
UIImage *img = iv.image;
CGImageRef CGimg = img.CGImage;
// Bitmap dimensions [pixels]
NSUInteger imgWidth = CGImageGetWidth(CGimg);
NSUInteger imgHeight = CGImageGetHeight(CGimg);
NSLog(#"Image dimensions: %lux%lu", imgWidth, imgHeight);
// Image size pixels (size * scale)
CGSize imgSizeInPixels = CGSizeMake(img.size.width * img.scale, img.size.height * img.scale);
NSLog(#"image size in Pixels: %fx%f", imgSizeInPixels.width, imgSizeInPixels.height);
// Image size points
CGSize imgSizeInPoints = img.size;
NSLog(#"image size in Points: %fx%f", imgSizeInPoints.width, imgSizeInPoints.height);
// Calculate Image frame (within imgview) with a contentMode of UIViewContentModeScaleAspectFit
CGFloat imgScale = fminf(CGRectGetWidth(iv.bounds)/imgSizeInPoints.width, CGRectGetHeight(iv.bounds)/imgSizeInPoints.height);
CGSize scaledImgSize = CGSizeMake(imgSizeInPoints.width * imgScale, imgSizeInPoints.height * imgScale);
CGRect imgFrame = CGRectMake(roundf(0.5f*(CGRectGetWidth(iv.bounds)-scaledImgSize.width)), roundf(0.5f*(CGRectGetHeight(iv.bounds)-scaledImgSize.height)), roundf(scaledImgSize.width), roundf(scaledImgSize.height));
// initiate rectange subview with face info
ZGCFaceRectView *faceRect = [[ZGCFaceRectView alloc] initWithFace:face frame:imgFrame];
// add view as subview of image view
[iv addSubview:faceRect];
}];
We've got several problems :
Microsoft returns pixel and iOS uses points. The difference between them is just about screen dimension. For instance on an iPhone 5 : 1 pt = 2 px and on an 3GS 1px = 1 pt. Look at the iOS documentation for more informations.
The frame of your UIImageView is not the image frame. When Microsofts returns the frame of a face, it returns it in the frame of the image and not in the frame of the UIImageView. So we've got a problem of coordinates system.
Be careful about time if you use Autolayout. The frame of a view set by constraints is not the same when ViewDidLoad: is called than when you see it on the screen.
Solution :
I'm just a read-only Objective C developer so I can't give you code. I could in Swift but it's not necessary.
Convert pixels into points. That's easy : use ratio.
Define the frame of a face using what you did. Then you have to move the coordinates you determined from the image frame coordinates system to the UIImageView coordinates system. That's less easy. It depends on the contentMode of your UIImageView. But I quickly find informations about it on the Internet.
If you use AutoLayout, add the frame of the face when AutoLayout finishes to calculate the layouts. So when ViewDidLayoutSubview: is called.
Or, that's better, use constraints to set your frame in the UIImageView.
I hope to be clear enough.
Some links :
iOS Drawing Concepts
Displayed Image Frame In UIImageView
I have an UIView that contains a UIImageView. The UIImageViews works like the branding logo of the app. When I rotate the device, the containing UIView resizes itself to correspond to the landscape or portrait proportions of the screen.
What I'm trying to achieve is to have the UIImageView scaled accordingly, keeping proportions also on the left margin.
This is the actual code for the top white "banner":
UIView *topBanner = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, height_topBanner)];
[topBanner setAutoresizingMask:(UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin)];
[topBanner setBackgroundColor:[UIColor whiteColor]];
topBanner.autoresizesSubviews = YES;
// the logo
UIImage *topBanner_logo = [UIImage imageNamed:#"logo.png"];
float logoAspectRatio = topBanner_logo.size.width/topBanner_logo.size.height;
topBanner_logoView = [[UIImageView alloc] initWithFrame:CGRectMake(topBanner.frame.size.width/100*3, topBanner.frame.size.height/100*7, (topBanner.frame.size.height/100*86)*logoAspectRatio, topBanner.frame.size.height/100*86)];
[topBanner_logoView setImage:topBanner_logo];
topBanner_logoView.backgroundColor = [UIColor blueColor];
topBanner_logoView.contentMode = UIViewContentModeScaleAspectFit;
[topBanner_logoView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleBottomMargin|UIViewAutoresizingFlexibleRightMargin)];
[topBanner addSubview:topBanner_logoView];
[self.view addSubview:topBanner];
This is my starting point: portrait iPad on startup:
This is what happens when I rotate it in landscape:
As you can see, the proportions of the UIImage are ok, but I'm getting extra borders (I set the background color of the UIImageView to highlight it) because the UIImageView stretches itself to follow the change of the size of its container, and the UIImage is fit into the UIImageView and put on its center.
The same - reversed - happens when I start the app directly in landscape mode:
Then I rotate it:
... and I get the logo with extra borders on top and bottom.
I do see that I can write a function to recalculate every size on each rotation change, but I'm asking to myself if is there a way to set the UIImageView and the UIImage to make it works without hacking the autorotate/resize procedures of iOS. It sounds so simple!
You can solve this by not using UIViewContentModeScaleAspectFit, and instead calculating the aspect ratio of the image and using that to explicitly the width or height based on the other (width or height).
e.g. I rotate to landscape, and so I want the height to be 80% of the view.
CGFloat w = logo.image.size.width;
CGFloat h = logo.image.size.height;
CGFloat a = w / h;
CGFloat h_use = self.view.height *0.8;
CGFloat w_use = h_use*a;
Furthermore, set the content mode to UIViewContentModeScaleAspectFill instead now that you've explicitly set the aspect ratio.
You have set the auto resizing mask to flexible height and width:
[topBanner_logoView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleBottomMargin|UIViewAutoresizingFlexibleRightMargin)];
If you do not do that, the default is that the view will not chance size, and therefore, the image will not either.
I think it is because of topBanner_logoView.contentMode = UIViewContentModeScaleAspectFit;
Try topBanner_logoView.contentMode = UIViewContentModeCenter or topBanner_logoView.contentMode = UIViewContentModeLeft to prevent the UIImageView's image from resizing (and getting padding).
If the UIImageView is resizing, remove the autoresizing mask.
I have a UIView that I am placing UIImageView's into, with each UIImageView being 16 pixels wide.
The query is if I add say 5 of the UIImageViews using addSubView, and the UIView is spec'd at 16 tall by 300 wide, is there any way to have the images in the view 'stack up' so to speak, so that the images are not on top of each other? Like adding image tags to a web page.
The easiest way I see of doing this is to keep a running tally of where you last placed an image, then increment by width, something like this:
-(void) addImage:(UIImage*)img toView:(UIView*)view
{
static CGRect curFrame = CGRectMake (0,0,16,16);
UIImageView* imgView = [[UIImageView alloc] initWithFrame:curFrame];
imgView.image = img;
[view addSubview:imgView];
curFrame.origin.x += 16;
}
This will have the images appear within your view from left to right
I think I understand your question correctly. You want all the images to line up in a row correct? You would need to set the frame of the UIImageView's view. The orgin will be where the top left of your image is(x,y coordinates inside the UIView that contains it) - so you would move that over 16 each time you add another image.