Progress View with UIView indicator - ios

Hi guys i'm stuck with this problem. I need to create a behavior like this one in the image.
I created a UIView xib (because i need to reuse this view) with a UIProgressView for the 'dark orange' fill and then create an UIView for the indicator with a UILabel in it but i'm unable to move it with setFrame so i was thinking that subclassing an UISlider would be much easier.
What do you think?
This is the code that doesn't work, the .xib uses AutoLayout and now i'm using Xcode 6.
ScoresView *score = [[[NSBundle mainBundle] loadNibNamed:#"scoresView" owner:self options:nil] objectAtIndex:0];
[score.markView setFrame:CGRectMake(score.markView.frame.origin.x + offset, score.markView.frame.origin.y, score.markView.frame.size.width, score.markView.frame.size.height)];
[score.progressView setProgress:0.5];
[score setFrame:viewSize];
[self.scoreScrollView addSubview:score];

Since the views are using auto layout, you must animate the layout constraints, not the frame. You do that by creating an outlet to the constraint and changing its constant.
But it might be easier to not use auto layout on the dark orange view. Build and add it in code. Set its frame origin equal to the light orange view, and set its width equal to progress (0-1) * light orange width.

Related

Button width and height is disabled in horizontal stackview

Im learning iOS development right now, XCode doesnt allow me to edit width and height of buttons which are in stack view:
In the Storyboard I create a new button of size 30 x 30 with a custom image and then make more 5 copies of that button. Then I embed them after selecting all of them in a Stack View. Now a disaster happens, the buttons are resized to god knows what size and they appear huge and when I try to go to size inspector to resize those buttons I see that "Width" and "Height" fields are disabled.
I tried few suggestions on stackoverflow and selected the stack view and change the distribution of stack view to "Fill Equally" but still the buttons size is being changed. I dont want this to happen. I want a fixed size buttons in a horizontal stack view and putting them in stack view should not change the size or shape of buttons like this. Can anyone please tell me how do I fix this problem?
Please help.
Sometime Interface Builder is not easy to handle because it is a running layout system at design-time / IB_DESIGNABLE. You make changes, IB gets triggered to 'think', changes parameters, layouts again, you see it does not fit and you change again.
It can be easier to fix UIStackView's constrains to your outer layout before dropping content that will be arranged by taking intrinsicContentSize of the subviews into its calculation. Even worse, if the stackview does not have complete constrains already and you drop something in as being arranged, it will take the default size as intrinsicContentSize of the dropped view and change the stackview spacing as it should. This is no surprise but it can be frustrating as convenience is disturbing your workflow here.
The docs tell you should not change intrinsicContentSize because it is not meant to be animated, it will even disturb animations and layout or even break constrains. Well, you can not set intrinsicContentSize, it is read-only. As thats for good reasons they could have written that while UIView's are instanced they can have supportive variables which have to be set before laying out which allows you to make pre-calculations.
While in code this can be tricky also, you can subclass UIView to make arranged subview instances more supportive to your needs.
There is UIView's invalidateIntrinsicContentSize that triggers the layout to take changed intrinsicContentSize into the next layout cycle. You still cant set intrinsicContentSize, but thats not needed when you would have a class designed like shown below.
// IntrinsicView.h
#import UIKit
IB_DESIGNABLE
#interface IntrinsicView : UIView
-(instancetype)initWithFrame:(CGRect)rect;
#property IBInspectable CGFloat intrinsicHeight;
#property IBInspectable CGFloat intrinsicWidth;
#end
// IntrinsicView.m
#import "IntrinsicView.h"
#implementation IntrinsicView {
CGFloat _intrinsicHeight;
CGFloat _intrinsicWidth;
}
- (instancetype)initWithFrame:(CGRect)frame {
_intrinsicHeight = frame.size.height;
_intrinsicWidth = frame.size.width;
if ( !(self = [super initWithFrame:frame]) ) return nil;
// your stuff here..
return self;
}
-(CGSize)intrinsicContentSize {
return CGSizeMake(_intrinsicWidth, _intrinsicHeight);
}
-(void)prepareForInterfaceBuilder {
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, _intrinsicWidth,_intrinsicHeight);
}
#end
Now this gives you control of the behaviour when UIStackView will layout.
Let's look at instancing of your UIStackView.
#import "IntrinsicView.h"
- (void)viewDidLoad {
[super viewDidLoad];
UIStackView *column = [[UIStackView alloc] initWithFrame:self.view.frame];
column.spacing = 2;
column.alignment = UIStackViewAlignmentFill;
column.axis = UILayoutConstraintAxisVertical; //Up-Down
column.distribution = UIStackViewDistributionFillEqually;
CGFloat quadratur = 30.0;
for (int row=0; row<5; row++) {
IntrinsicView *supportiveView = [[IntrinsicView alloc] initWithFrame:CGRectMake(0, 0, quadratur, quadratur)];
// supportiveView stuff here..
[column addArrangedSubview:supportiveView];
}
[self.view addSubview:column];
}
Don't forget IntrinsicView's intrinsicContentSize is set before instancing is complete, so this example takes frame size at initWithFrame as intended and stores that size to be used when intrinsicContentSize is asked. Having that still needs that UIStackView is large enough to layout nicely but you forced the arranged subviews to that intrinsic size. Btw. the example is arranged up..down.
You can use the IntrinsicView in Interface Builder, just change the views inside UIStackView to the above written class. IB will automatically update the designable API and serve you propertys you can set up. This still needs the StackView to have at least width and height set and also constrains if needed. But it takes away the impression your width and height of arranged views would have any effect other than expected, because IntrinicViews height + width is inactive in IB then.
Just to show you how much this improves your possibilities in IB, see image

Frame Resizing using AutoLayout

I have an UIView inside which i have a UIButton. I am using auto layout. Now I want to reduce the height of the UIView. How should I do it ? On reducing the height of the UIView , the UIButton inside the view should also move up at the same time. How can i do this using Auto Layout ?
You can create IBOutlet for height constraint of you view and you can change value for it.Just check how to create.
Now use the code below to set height of you UIVIew
heightConstraintOfView.constant = DYNAMIC_HEIGHT;

iOS position UILabel in circle view

I defined a view which contains an UImageView and a UILabel. I setted constraints for each elements.
In wanted to do a circle with the first view, so I did that in the code :
self.mainView.layer.cornerRadius = self.mainView.frame.size.width / 2;
self.mainView.clipsToBounds = YES;
So it works, I have a circle, BUT the UImageView and the UILabel seems don't follow the constraints setted in the storyboard.
For example, on my UILabel, I setted a margin left and right 5px to the mainView, but I can see my UILabel "out" the mainView....
I tried to do a "setNeedsUpdateConstraints", but it's not the solution.
So, what I need to do to have my UILabel correctly positioned ?
Thanks,
I think this is what you are looking for:
self.mainView.layer.masksToBounds = YES;
Your problem is that when changing the mainView's layer you are not actually changing the bounds of the view. The bounds of the view are still represented in a rectangle manner. what you need to do is change the width constraint of the UILable.
To do so just create a autolayout constrain to your UILable (is you don't have it already). Control-Drag it to your viewController and change it dynamically using the constant value in the constraint.
If you don't need to set it dynamically just set the left & right margins to a bigger margin

Xcode6 Interface Builder constraints not stretching subviews

Xcode Interface Builder is driving me nuts and I've spent most of my day googling for a solution.
I have a storyboard with a CollectionViewCell that contains a UIImageView. The CollectionViewCell size is 125 x 125 and Autoresize subviews is checked.
The UIImageView has 4 constraints to its superview (leading, trailing, top, bottom), all set to 0. This should ensure that the UIImageView is sized to fill the superview. The UIImageView is sized correctly when the CollectionViewCell is shrunk to a smaller size, but IT DOES NOT WORK when the CollectionViewCell is stretched to a larger size.
EDIT: I've tried the same using a UILabel subview and the same thing happens.
Is this a known problem or is there any way to debug constraints?
Thanks
I've finally found a complete solution to the problem from http://www.nomtek.com/adjusting-your-app-to-ios-8/
Firstly, I had to ensure my CollectionViewCell had Autoresize Subviews checked in Interface Builder, then I had to add the following awakeFromNib method on the ConnectionViewCell subclass.
- (void)awakeFromNib {
[super awakeFromNib];
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
With these two things, the contents of my cells (UIImageView and UILabel) are stretched properly even with dynamic cell sizing using sizeForItemAtIndexPath.
I've made partial progress.
I was setting the cell size dynamically using sizeForItemAtIndexPath.
If I drop that method and set a larger Cell Size of the CollectionView's FlowLayout in Interface Builder, it works as expected. This means the constraints and subview size are updated at compile time.
I would still love to know how to dynamically update the constraints and subview sizes when using sizeForItemAtIndexPath. Any suggestions?

Unable to change height of UIView loaded from nib

I have a view that is loaded from a nib like so:
SLSCaseCard* caseCard = [[[NSBundle mainBundle] loadNibNamed:#"SLSCaseCard" owner:self options:nil] objectAtIndex:0];
I'm setting it's frame like this:
cardFrame = CGRectMake(25,25, caseCard.frame.size.width, 44);
[caseCard setFrame:cardFrame];
[self.view addSubview:caseCard];
The x and y are changing but the height always remains the same. The view has a size of 224 in the nib, and it stays at that height at runtime.
Storyboard (or XIB's) generates code for you. And this code is executed in laying out subviews. So if you want to change frame of a view defined in XIB, you should do that after viewDidLayoutSubviews or layoutSubviews.
Hence even after you setting the height of the view, your changes are overridden by the code generated by XIB, which overrides the height to the height defined in XIB, in your case 224. Same goes with width.

Resources