I have a nib with a 2 UIViews and 2 UILabels with IBOutlet's in my controller.
I am increasing and decreasing the height of these UIViews to look like a bar to indicate when something is 100% or less - like a bar chart almost.
I am using the following method for both bars (reuse) however the first UIView (bar) positions correctly but the second is too low down - the Y axis is wrong. However the height of both is correct.
Anyone have any ideas? I have positioned them in interface builder already all I am actually doing in this method is changing the height (basically)
//Position the point, size and label of a rating bar
- (void)configureRatingBar:(UIView *)vRatingBar
andRatingLabel:(UILabel *)lRatingLabel
usingRating:(NSDecimalNumber *)rating
{
//NSDecimalNumber *foodRating = [self calculateRating:self.currentHotel.foodAndBeverageRating];
NSString *formattedRating = [self formatRating:rating];
lRatingLabel.text = formattedRating;
float newHeight = [rating floatValue]; //The height will be based on the rating 100 max
CGRect currentFrame = vRatingBar.frame; //Current frame of the rating view
//CGPoint currentPoint =
// [vRatingBar convertPoint:vRatingBar.frame.origin toView:vReviews];
CGPoint currentPoint = vRatingBar.frame.origin; //Current point of the rating view
float newYaxis = currentPoint.x + (100 - newHeight); //Y axis must move down with the decreasing rating from 0 (100 %) down
[vRatingBar setFrame:CGRectMake(currentPoint.x, newYaxis, currentFrame.size.width, newHeight)];
[lRatingLabel setFrame:CGRectMake(currentFrame.size.width / 34, newHeight - 20, 34, 21)];
}
I see you have this line:
float newYaxis = currentPoint.x + (100 - newHeight); //Y axis must move down with the decreasing rating from 0 (100 %) down
Where you are using currentPoint.x for the calculation. Should this be currentPoint.y?
Related
I have a UIScrollView which scrolls horizontally from left to right.
I want to be able to vertically position my UIScrollView on the Y axis according to the screen size of the iPhone. E.g iPhone 4 and iPhone 5.
CGFloat startX = (70.0f * ((float)[_attachments count] - 1.0f) + padding);
CGFloat startY = 295;
CGFloat width = 64;
CGFloat height = 64;
Right now I start my Y position at 295 which works okay with the iPhone 4 but not on iPhone 5.
How would I change the startY to accommodate the same position for different screen size?
CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (screenBounds.size.height == 568)
{
//iphone5
}
else
{
//iphone4
}
You can set your y value accordingly
Do use layoutSubviews in your view ...
- (void)layoutSubviews {
CGRect frame = self.bounds;
frame.origin.y += frame.size.height - _scrollView.frame.size.height;
if ( ! CGRectEqualToRect( _scrollView.frame, frame ) {
_scrollView.frame = frame;
}
}
... I assume that your horizontal scroll view is in _scrollView ivar and also that the _scrollView.frame.size.height contains correct height of your _scrollView. If not, replace _scrollView.frame.size.height with some constant which does contain your UIScrollView height.
Why the condition with CGRectEqualToRect? Because layoutSubviews can be called very often and when you set new frame (even if it equals) to it, UIScrollView can stop scrolling.
you can do it like this-
first get the width and the height of the screen
CGRect screenBounds = [UIScreen mainScreen].bounds ;
CGFloat width = CGRectGetWidth(screenBounds);
CGFloat height = CGRectGetHeight(screenBounds) ;
now create a method which will do some calculations and return an int
-(NSInteger) getwidth:-(NSInteger *) value
{
int temp = (value * 100) / 480;
return int((height * temp) / 100);
}
-(NSInteger) getheight:-(NSInteger *) value
{
var temp = (value * 100) / 320;
return int((width * temp) / 100);
}
now set the bounds of view according to these function
actind.frame=CGRectMake(getWidth(20),getheight(20),16,16);
this will work on all the devices and the views will arrange themselves according to the width and height of the screen.
hope this will help for you. :)
I have an image for user's icon and a label for user's name
And I want the image and the label align center horizontally in the screen.
Because the length of the label changes as the length of user's name, (the size of image is fixed)
I can't set the positon as a fixed value.
Now I change the positon of the image and lalel at runtime,
It's not convenient.
Is there any good way to do this?
Thank you:)
Here is the snapshot:
All right.
I know there is no a very convenient way to do this just with IB.
And I learn the function of [label sizetoFit].
It's very helpful.
In android, it's very convenient to do this just with the xml layout.
But in ios I have to write code to control the positon of image and label.
Yes...Not too bad.
Thanks everybody :)
[label sizetoFit];
label.center =imageView.center;
this will make the label center on the image center..and it will appear on top...
now you can just use CGRect manipulation to move the label origin downwards based on your image height.
Edit .. now you can do this ..
CGRect frame = label.frame;
frame.origin.x -= imageview.frame.size.width/2 - 15; // you can change 15 to a more appropriate number based on your preference..
label.frame = frame;
Do the above after you do the 2 lines of code given on top in my answer.
Do some calculation
Width of UIImageView + Offset width (Space b/n UIImageView and UILabel "Keep this as constant value") + UILabel Width = You Will get some 'X' width.
iPhone screen width is 460.
320-X = Remaining width.
Remaining width/2 pass this value to UIImageView's X value. This might help you.
#define MARGIN 10.0f
In your -layoutSubviews method, do this:
[ label sizeToFit ] ;
CGRect r = label.frame ;
r.origin = (CGPoint){ CGRectGetMaxX( imageView.frame ) + MARGIN, CGRectGetMidY( imageView.frame ) - 0.5 * r.size.height } ;
label.frame = CGRectIntegral( r ) ;
update here's how to center the the image view and label unit
bounds should be set to bounds of enclosing view
//
// center an image view + label in parent view, with label to right of image view
//
[ label sizeToFit ] ;
CGSize size = (CGSize){ imageView.image.size.width + MARGIN + label.bounds.size.width,
MAX( imageView.image.size.height, label.bounds.size.height } ;
CGRect r = (CGRect){
{ CGRectGetMidX( bounds ) - 0.5 * size.width,
CGRectGetMidY( bounds ) - 0.5 * size.height },
size }
} ;
CGRect imageFrame, labelFrame ;
CGRectDivide( r, &imageFrame, &labelFrame, imageView.image.size.width, CGRectMinXEdge ) ;
imageView.frame = imageFrame ;
labelView.frame = labelFrame ;
following WWDC2010 Session 104 I just created a CATiledLayer within a UIScrollView for a 10000 x 8078 px image.
I am troubled with the frame & zoomScale when the view is first shows at its top level
like in session 104 I defined levelsOfDetail as 4
in my drawRect I call CGFloat lScale = CGContextGetCTM(lContext).a;
Strangely at runtime lScale is assigned 0.124907158, not 0.125 as expected.
As well the rect passed to drawRect has floatpoint values, such as
rect.origin.x = 4099.04443
rect.origin.y = 6144
rect.size.width = 2049.52222
rect.size.height = 2048
Most irritating for me is that the frame of the CATiledLayer shows an origin 0 x 26.93 even though I created the tiledImageView using initWithFrame using a 0x0 origin.
Any ideas where I can find the calculation that is responsible for this?
EDIT:
I found the source for the wierd frame position, which is the ScrollView bounds being incorrectly set at 450 px. that should be 420 px. The layoutSubview routine in the UIScrollView has a center view routine that inadvertently adjusted the y coordinate.
I found a cure to this.
The WWDC 2010 session 104 sample has two UIScrollView methods that control the view behaviour.
The first is configureForImageSize that I mentioned in my previously posted answer where the zoomscales are set.
Due to the explained float-point difference the imageView-bounds get generated with the decimals as highlighted before (see wx/hx or wy/hy).
To get clean this up I used the override of layoutSubviews where I calculate the view frame:
- (void) layoutSubviews {
[super layoutSubviews];
CGSize lBoundsSize = self.bounds.size;
CGRect lFrameToCenter = imageView.frame;
// cure to the decimals problem
lFrameToCenter.size.width = roundf(lFrameToCenter.size.width);
lFrameToCenter.size.height = roundf(lFrameToCenter.size.height);
if (lFrameToCenter.size.width < lBoundsSize.width)
lFrameToCenter.origin.x = (lBoundsSize.width - lFrameToCenter.size.width) / 2;
else
lFrameToCenter.origin.x = 0;
if (lFrameToCenter.size.height < lBoundsSize.height)
lFrameToCenter.origin.y = (lBoundsSize.height - lFrameToCenter.size.height) / 2;
else
lFrameToCenter.origin.y = 0;
imageView.frame = lFrameToCenter;
if ([imageView isKindOfClass:[tileView class]]) {
imageView.contentScaleFactor = 1.0;
}
}
Note that I round the frame size before doing anything else with it!
I got a little further in my bug analysis.
Having an mImageSize of 10000x8078 and 320x450 Bounds in the UIScrollView I used the configureForImageSize calculations from the session 104 example as follows:
- (void) configureForImageSize:(CGSize)mImageSize {
CGSize lBoundsSize = [self bounds].size;
// set up our content size and min/max zoomscale
CGFloat lXScale = lBoundsSize.width / mImageSize.width; // the scale needed to perfectly fit the image width-wise
CGFloat lYScale = lBoundsSize.height / mImageSize.height; // the scale needed to perfectly fit the image height-wise
// debug values
float wx = mImageSize.width * lXScale;
float wy = mImageSize.width * lYScale;
float hx = mImageSize.height * lXScale;
float hy = mImageSize.height * lYScale;
...
}
The debugger shows the following values:
* mImageSize = width 10000 height 8078
* bounds size: width 320 height 450
* lXScale = 0.0396137647
* lYScale = 0.0450000018
* wx = 320
* wy = 363.51001
* hx = 396.137634
* hy = 450.000031
so I gather the image size in relation to the bounds leads to a floatpoint calculation difference. When the CATiledLayer is generated the bounds are alway floatpoint values.
If that is the cause, how can I get a mathematical way out of this without having to resize the image (ugly thought)???
I have an image that I want to load into an image view and set the minimumZoomScale, as well as the zoomScale to an aspectFill like scale that I calculate as follows:
// configure the map image scroll view
iImageSize = CGSizeMake(iImageView.bounds.size.width, iImageView.bounds.size.height);
iScrollView.minimumZoomScale = iScrollView.bounds.size.height / iImageSize.height;
iScrollView.maximumZoomScale = 2;
iScrollView.zoomScale = iScrollView.minimumZoomScale;
iScrollView.contentOffset = CGPointMake(0, 0);
iScrollView.clipsToBounds = YES;
The iScrollView size is 450 x 320px and the iImageSize is 1600 x 1960px.
Doing the minimumZoomScale math by hand: 450 / 1960 = 0.22959184.
The system determines 0.234693885 instead (???).
But to get the window fit into the 450px space, both figures don't work (!!!).
I manually tried and found 0.207 is the right number (that would translate to a image height of 2174 xp or alternatively a UIScrollView height of 406px).
For information: the UIScrollview screen is 450px, namely 480px minus status bar height (10), minus UITabBar height (20)
Any clues on this misbehaviour?
Not sure if you still have this problem, but for me, the scale is exactly the opposite. minimumZoomScale = 1 for me and I have to calculate the maximumZoomScale.
Here's the code:
[self.imageView setImage:image];
// Makes the content size the same size as the imageView size.
// Since the image size and the scroll view size should be the same, the scroll view shouldn't scroll, only bounce.
self.scrollView.contentSize = self.imageView.frame.size;
// despite what tutorials say, the scale actually goes from one (image sized to fit screen) to max (image at actual resolution)
CGRect scrollViewFrame = self.scrollView.frame;
CGFloat minScale = 1;
// max is calculated by finding the max ratio factor of the image size to the scroll view size (which will change based on the device)
CGFloat scaleWidth = image.size.width / scrollViewFrame.size.width;
CGFloat scaleHeight = image.size.height / scrollViewFrame.size.height;
self.scrollView.maximumZoomScale = MAX(scaleWidth, scaleHeight);
self.scrollView.minimumZoomScale = minScale;
// ensure we are zoomed out fully
self.scrollView.zoomScale = minScale;
For simple zoom in/out i generally use below code. minimumZoomScale= 1 sets initial zoom to current image size. I have given maximumZoomScale = 10 which can be calculated from actual ratio of image size and container frame size.
[scrollView addSubview: iImageView];
scrollView.contentSize = iImageView.frame.size;
scrollView.minimumZoomScale = 1.0;
scrollView.maximumZoomScale = 10;
[iImageView setFrame:CGRectMake(0, 0, 450, 320)];
[scrollView scrollRectToVisible:iImageView.frame animated:YES];
I am loading in images with varying sizes and putting them in UIScrollViews, all the images are larger than the UIScrollView.
The user can scroll and zoom as they please, but initially I would like for the image
to be centered and scaled so the largest side of the image aligns with the edge of the scrollView, i.e. if the picture is in landscape I would like to size and scale it so that the left and right side goes all the way to the edge of the UIScrollVIew and vice versa
I found a formula in a utility function in the Programming guide but it does not quite fit my needs.
My approach is to use:
CGrect initialPos = ?
[self.scrollView zoomToRect:initialPos animated:YES];
I know the size of my scrollView and the size of my image, what I need to figure out is the scale and CGRect to apply to the scrollView to center and size my image.
Hope someone can help out:) Thanks
Edit: previous version was sizing the image to the view rather than the other way around. I think this should correct that:
double imgRatio = imageSize.width / imageSize.height;
double viewRatio = viewSize.width / viewSize.height;
if ( imgRatio >= viewRatio )
{
initialPos.size.width = imageSize.width;
initialPos.size.height = imageSize.width / viewRatio;
initialPos.origin.x = 0;
initialPos.origin.y = (imageSize.height - initialPos.size.height) / 2;
}
else
{
initialPos.size.height = imageSize.height;
initialPos.size.width = imageSize.height * viewRatio;
initialPos.origin.y = 0;
initialPos.origin.x = (imageSize.width - initialPos.size.width) / 2;
}