UIView won't move programmatically - ios

so there must be something simple I am missing because I just can't figure out how to move my UIView
This is what I have so far
my .m file
- (void)viewDidLoad
{
[super viewDidLoad];
[self buttonLayout];
}
-(void)buttonLayout
{
UIView *theView = [self buttonGroup];
theView.center=CGPointMake(50, 50);
}
My .h file
#property (nonatomic, retain) IBOutlet UIView *buttonGroup;
So this is what I have so far and i just cant seem to get it to move at all
P.S i don't want it animated as i'm getting my layout to move to compensate for different iPhone screen sizes :)

I have not tested this, but it seems like you need to:
A) Remove the view from its parent.
B) Adjust the center of its 'frame', not the view.
C) Re-add the subview.
Like so:
UIView *theView = [self buttonGroup];
CGRect theFrame = theView.frame;
[theView removeFromSuperview];
theFrame.origin.x = 50.0;
theFrame.origin.y = 50.0;
theView.frame = theFrame;
[self.view addSubview:theView];
This should work with autolayout.

As the other poster says, you can't move views around by changing their center or frame when you have auto-layout in effect.
Instead, you have to add a vertical and horizontal constraint that positions the view from the top/left edge, connect an outlet to the constraint, and then change the constant value on the constraint from code.

I had similar problem , but when i tried to change the origin as suggested in first solution , i got "Expression not assignable" error.
so i solved it with below solution in viewDidLoad().
First save its center in some temp variable , then change the centre and add again to its parent view.
CGPoint buttonCenter = self.yourButton.center;
[self.yourButton removeFromSuperview];
buttonCenter.y = buttonCenter.y + 50.0;
self.yourButton.center = buttonCenter;
[self.view addSubview:self.yourButton];

Related

UIDynamics and Autolayout

Recently I used UIDynamics to animate an image view into place. However, because its autolayout y-pos constraint was set to off-screen, when navigating away from the screen and then returning to it, my image view was being placed off-screen again. The animation took about 3 seconds, so after three seconds I just reset the constraint. That feels a little hacky.
So my question is this: what is the proper way to handle autolayout and UIDynamics at the same time?
This is not really a dynamics problem. Autolayout is incompatible with any view animation, or any manual setting of the frame: when layout comes along, it is the constraints that will be obeyed. It is up to you, if you move a view manually in any way, to update the constraints to match its new position/size/whatever.
Having said that: with UIKit Dynamics, when the animation ends, the animator will pause, and the animator's delegate is notified:
https://developer.apple.com/library/ios/documentation/uikit/reference/UIDynamicAnimatorDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIDynamicAnimatorDelegate/dynamicAnimatorDidPause:
So that is the moment to update the constraints.
You have a nice solution provided by Geppy Parziale in this tutorial.
Basically you can create an object that conforms to UIDynamicItem:
#interface DynamicHub : NSObject <UIDynamicItem>
#property(nonatomic, readonly) CGRect bounds;
#property(nonatomic, readwrite) CGPoint center;
#property(nonatomic, readwrite) CGAffineTransform transform;
#end
That needs to init the bounds or it will crash:
- (id)init {
self = [super init];
if (self) {
_bounds = CGRectMake(0, 0, 100, 100);
}
return self;
}
And then you use UIDynamics on that object and use the intermediate values to update your constraints:
DynamicHub *dynamicHub = [[DynamicHub alloc] init];
UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:dynamicHub
snapToPoint:CGPointMake(50.0, 150.0)];
[snapBehavior setDamping:.1];
snapBehavior.action = ^{
self.firstConstraint.constant = [dynamicHub center].y;
self.secondConstraint.constant = [dynamicHub center].x;
};
[self.animator addBehavior:snapBehavior];

Horizontally center multiple UIViews

I want to horizontally center a number of UIViews (they happen to be circles) in the master UIView. It will end up basically looking like the dots on the standard Page Control.
I have all the code written to create the circle UIViews I just have no idea how to arrange them horizontally and dynamically at run time.
Essentially I need some kind of horizontal container where I can do this
-(void)addCircle{
[self addSubView:[CircleView init]];
}
And it will auto arrange however many children it has in the center.
I get confused with auto-layout as well from time to time but here is a way how you can do it programmatically: (I assume that you add your circle views to a containerView property of your view controller and you do not add any other views to it.)
Add these two properties to your view controller:
#property (nonatomic) CGRect circleViewFrame;
#property (nonatomic) CGFloat delta;
Initiate those properties with the desired values in your view controller's viewDidLoad method:
// the size (frame) of your circle views
self.circleViewFrame = CGRectMake(0, 0, 10, 10);
// the horizontal distance between your circle views
self.delta = 10.0;
Now we add your "automatic addCircle method":
- (void)addCircleView {
UIView *newCircleView = [self createCircleView];
[self.containerView addSubview:newCircleView];
[self alignCircleViews];
}
Of course we need to implement the createCircleView method...
- (UIView*)createCircleView {
// Create your circle view here - I use a simple square view as an example
UIView *circleView = [[UIView alloc] initWithFrame:self.circleViewFrame];
// Set the backgroundColor to some solid color so you can see the view :)
circleView.backgroundColor = [UIColor redColor];
return circleView;
}
... and the alignCircleViews method:
- (void)alignCircleViews {
int numberOfSubviews = [self.containerView.subviews count];
CGFloat totalWidth = (numberOfSubviews * self.circleViewFrame.size.width) + (numberOfSubviews - 1) * self.delta;
CGFloat x = (self.containerView.frame.size.width / 2) - (totalWidth / 2);
for (int i = 0; i < numberOfSubviews; i++) {
UIView *circleView = self.containerView.subviews[i];
circleView.frame = CGRectMake(x,
self.circleViewFrame.origin.y,
self.circleViewFrame.size.width,
self.circleViewFrame.size.height);
x += self.circleViewFrame.size.width + self.delta;
}
}
This is the most important method which will automatically realign all your subviews each time a new circleView is added. The result will look like this:
Simple steps: append circle to container view, resize container view, center align container view
-(void)addToContanerView:(CircleView*)circle{
circle.rect.frame = CGrectMake(containers_end,container_y,no_change,no_change);
[containerView addSubview:circle];
[containerView sizeToFit];
containerView.center = self.view.center;
}
Assumptions:
containers_end & containers_y you can get from CGRectMax function,
for UIView SizeToFit method check here
To take care of rotation use make sure your Autoresizing subviews are set for left, right bottom and top margin.
You can try using this library. I have used it on several of my projects and so far, it worked really well.
https://github.com/davamale/DMHorizontalView

Positioning a button using CALayer not working

I added an image button into the interface builder and I want to position it using CGPointMake so I added the button IBOutlet into the .h file and then added a CALayer in the .m file, here is my code...
in .h file
// This is the .h file
#interface ViewController : UIViewController
{
IBOutlet UIButton *thebtn;
}
in .m file
// This is the .m file
- (void)viewDidLoad
{
CALayer *btn = thebtn.layer;
btn.position = CGPointMake(480, 150);
btn.opacity = 0.4f;
[self.view.layer addSublayer:btn];
}
So that is great but my issue that the button position is not changing but the button opacity was changed so how can I fix that issue?
Thanks in Advance
Try to do the following:
First, move your code to viewDidAppear. Get rid of the layer code. Also, add setNeedsLayout call. Here is an example:
-(void)viewDidAppear
{
thebtn.center = CGPointMake(480, 150);
thebtn.opacity = 0.4f;
[self setNeedsLayout];
}
UPDATE
I figured out what the problem was. You have to turn off "Auto-Layout". After that your view will be repositioned to where you want.
Please see this link to see how to disable Auto Layout
Hope this helps!
I think for such purposes as changing position and opacity of a view, you'd better operate with a UIView object (UIButton in your case), instead of its CALAyer property. This should work:
- (void)viewDidLoad
{
thebtn.center = CGPointMake(x, y);
thebtn.alpha = 0.4f;
}

UIScrollView - content goes out bound when scrolling

I design the scrollview in interface builder like this
It looks good here. But unfortunately when I run it on emulator or device
it becomes
The content in scrollview is expand outside scrollview itself and even though outside UIView that contains this scrollView.
In my viewDidLoad (panel is the container of scrollView )
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
CGFloat adjustPanelHeight = [PTTScreenScaleUtil getAdjustHeight:self.panel.frame.size.height];
CGRect panelRect = self.panel.frame;
panelRect.size.height = adjustPanelHeight;
self.panel.frame = panelRect;
UIImage *image = [UIImage imageNamed:#"panel-background"];
UIGraphicsBeginImageContext(self.panel.frame.size);
[image drawInRect:CGRectMake(0, 0, self.panel.frame.size.width, adjustPanelHeight)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.panel setBackgroundColor:[UIColor colorWithPatternImage:newImage]];
NSLog(#"scrollView Height : %f", self.scrollView.frame.size.height);
NSLog(#"scrollView contentSize Height : %f", self.scrollView.contentSize.height);
// CGRect scrollViewRect = self.scrollView.frame;
// CGRect scrollViewContentRect = self.scrollView.frame;
// NSLog(#"ScrollView Height Before : %f , After : %f", self.scrollView.frame.size.height, [PTTScreenScaleUtil getAdjustHeight:self.scrollView.frame.size.height]);
// scrollViewRect.size.width = 280;
// scrollViewRect.size.height = [PTTScreenScaleUtil getAdjustHeight:270];
// self.scrollView.frame = scrollViewRect;
// [self.detailsLabel sizeToFit];
UIView *view = [[self.scrollView subviews] objectAtIndex:0];
// [view sizeToFit];
// [self.scrollView setContentMode:UIViewContentModeScaleAspectFit];
// NSLog(#"ContentSize Height : %f", view.frame.size.height);
// scrollViewContentRect.size.height = view.frame.size.height;
NSLog(#"Bounds : %f", view.bounds.size.height);
self.scrollView.frame = CGRectMake(10, 10, 280, 270);
self.scrollView.contentSize = CGSizeMake(280, 500);
NSLog(#"Frame Height %f", self.scrollView.frame.size.height);
//[self.scrollView setContentSize: CGSizeMake(280, 1000)];
CGRect termBtnRect = self.termBtn.frame;
CGRect mailBtnRect = self.mailBtn.frame;
CGRect twitterBtnRect = self.twitterBtn.frame;
CGRect fbBtnRect = self.fbBtn.frame;
termBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
mailBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
twitterBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
fbBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
self.termBtn.frame = termBtnRect;
self.mailBtn.frame = mailBtnRect;
self.twitterBtn.frame = twitterBtnRect;
self.fbBtn.frame = fbBtnRect;
}
All the log return 270.0
PS. the scroll bar is correct even though the content goes outside but the scroll bar is working correctly (stay in the scrollview's frame as arrange in interface builder)
I have no idea how can I solve this.
Anyone help me please.
Thanks you.
Solve it by creating new view controller in interface builder and redo the same process with careful and bingo. It works.
When I compare both two view controller I realise that the wrong one UIScrollView Clip Subviews is unchecked. When check it the problem solve.
I just struggled with this for an hour and had a head smack moment.
In my case, I had a UIView on the scene in the Storyboard. At some point I decided I needed it to be a UIScrollView instead (as opposed to the original plan which was to embed the UIScrollView in a UIView)
I went ahead and changed the class on the UIView to UIScrollView. IB changed it to Scroll View in the Document Outline, I figure I'm good, right?
And then I see the behavior you describe.
At some point it hits me that this isn't sufficient. Apparently adding a UIScrollView via IB does some things differently than adding a UIView and just changing class isn't enough. And this is probably the reason re-doing it from scratch fixed it for you.
So for anyone who runs into this in the future, make sure you added the UIScrollView via IB instead of a UIView
I was having the same problem as described in this post. I tried multiple combinations of solutions that did not work, including:
putting the scroll view inside a view with Clip To Bounds = YES
putting a view inside the scroll view with Clip To Bounds = YES, that then contained my child view
putting a Container View inside the scroll view, and then embedding my subview
rebuilding the Interface Builder files completely
every combination of autosizing mask options systematcially for both the scroll view and container view
clip to bounds enabled or disabled for every single element systematically
The child view in question had previously worked inside a scroll view, but wouldn't in this one case where the content blew outside the bounds of the scroll view.
In the end, I implemented the solution in code as I could find no way to get Interface Builder to co-operate:
// There are two scroll areas on the screen, the left view and the right view.
// We want the right view to contain a scrollable area with another child view controller
// we designed in Interface Builder.
// create a scroll view to fill the right view with a scrollable area
CGSize rightFrameSize = self.rightView.bounds.size;
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake (0, 0, rightFrameSize.width, rightFrameSize.height)];
scrollView.contentSize = CGSizeMake(640, 1352);
[self.rightView addSubview:scrollView];
// now create our child view controller from Interface Builder and add it to the scroll view
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"CustomerAddress" bundle:[NSBundle mainBundle]];
detailsView = [sb instantiateViewControllerWithIdentifier:#"CustomerDetailsView"];
detailsView.delegate = self;
detailsView.customer = _customer;
[scrollView addSubview:detailsView.view];
You could of course get the scrollView.contentSize from the child view controller you constructed in Interface Builder using scrollView.contentSize = detailsView.view.frame.size.
I have a love/hate relationship with Interface Builder... most days I love it, but some days we argue and I wish we'd never met... :)
only make cliptobound=YES in storyboard if you changed UIView to UIScrollView

'UIView' may not respond to 'addSubview:withAnimation:'

I got this warning:
'UIView' may not respond to 'addSubview:withAnimation:'
The line of code which produce that warning is this:
[self.masterView addSubview:self.detailImage withAnimation:def];
And my relevant code is like this:
ExUIViewAnimationDefinition *def = [[ExUIViewAnimationDefinition alloc] init];
def.type = ExUIAnimationTypeTransition;
def.direction = ExUIAnimationDirectionMoveUp;
[self.masterView addSubview:self.detailImage withAnimation:def];
[def release];
I looked on the UIView documentation, i thought addSubview may be deprecated, but it still like this.
Does any one know how to solve this warning? Thanx in advance.
addSubview is a method UIView will respond to. addSubview:withAnimation: is not a method UIView will respond to.
If you want to add a subview with a fade or something like that, try this:
self.detailImage.alpha = 0.0;
[self.masterView addSubview:self.detailImage];
[UIView animateWithDuration:0.3 animations:^{
self.detailImage.alpha = 1.0;
}];
To add a subview to a parent, call the addSubview: method of the parent view. This method adds the subview to the end of the parent’s list of subviews.
To insert a subview in the middle of the parent’s list of subviews, call any of the insertSubview:... methods of the parent view. Inserting a subview in the middle of the list visually places that view behind any views that come later in the list.
[self.masterView addSubView:self.def];
[def release];
This helped me to animate subview by sliding out from down of border of parent view
-(void) addAnimatadView:(UIView *) animatedView toView:(UIView *)aView {
CGRect frame = animatedView.frame;
float origin = frame.origin.y;
frame.origin.y = aView.frame.size.height;
[animatedView setFrame:frame];
[aView addSubview:animatedView];
frame.origin.y = origin;
[UIView animateWithDuration:0.4 animations:^{[animatedView setFrame:frame];}];
}
Just change frame origins as you want to reach free sliding

Resources