I have an UIImageView and an UILabel in a view of my storyboard. I created 2 corresponding IBOutlet and an NSTimer in the controller.
Each 0.01 seconds, the timer call the following method which moves the image:
-(void) update{
CGRect rect = myImageOutlet.frame;
rect.origin.x += 1;
myImageOutlet.frame = rect;
}
It works well. Now I would also like to change the text of the label in this method in order to display the current elapsed time (to do so I initialize an NSDate in the viewDidLoad and I use on it the method timeIntervalSinceNow)
Now the text of the label changes correctly but the image stays at it's original place.
I found a workaround by adding programmatically to my controller a subview and putting the label in this subview.
What is strange is that I tried to do the same by adding an UIView and an UILabel through the object library in the storyboard (and not programmatically), and it does not work.
Do you have any idea why ?
(and if you also know why the image is not moving if I change the label text I am interested)
Related
I have used storyboard to layout a custom cell in a tableview. I have a UI button in this custom cell that has an initial x,y size of 60x7. This UI button (as with all objects in the storyboard) use auto layout with size classes.
When the user clicks on an edit button in the view, I would like to change the size of the UIButton in each cell to be 60x60. Various StackOverflow solutions for changing the UIButton size do something like the following:
CGRect buttonFrame = cell.button1Left.frame;
buttonFrame.size = CGSizeMake(60, 60);
cell.button1Left.frame = buttonFrame;
But the solutions also warn that this will not work unless you turn off auto layout. However, when I try to turn off auto layout for this UIButton in the custom cell, I get the following warning:
This warning scares me. If I disable size classes, will this mess up my layout, disable my segues, and make future changes more difficult? If so, is there any other way to accomplish what I am trying?
Bonus question: is it possible to animate the resizing of the UIButton (i.e. so that it appears to stretch to the larger size)?
Try this:
1) add 2 constraints to your Button in storyboard;
2) create properties for them :
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *btnHeight;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *btnWidth;
3) add action to button click:
- (IBAction)buttonPressed:(id)sender {
UIButton *btn = (UIButton *)sender;
btn.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
self.btnHeight.constant +=50;
self.btnWidth.constant +=50;
[UIView animateWithDuration: 0.7 animations:^{
[self.view layoutIfNeeded];
}];
}
P.S. If your button is in the center of cell, you need also create top and left constraints and if you make height and width for 50 bigger you need to make top and left for 25 smaller.
I decided that the best solution for me was to create another UIButton that was already the desired size. When the user presses an edit button for the view, I hide the collapsed UIButton that was 60x7. Then I unhide the full size UIButton that is 60x60. To animate the transition so that it looks more natural, I did the following:
[UIView transitionWithView:cell.pencilButtonLeft
duration:0.6
options:UIViewAnimationOptionTransitionFlipFromBottom
animations:NULL
completion:NULL];
cell.pencilButtonLeft.hidden = NO;
As for the warning message when I tried to turn off autosizing, I decided to not turn off autoresizing and not to disable size classes. In reading it closely, I might have been ok as long as I did not have an intention of running the app on a device other than an iPhone. Thanks to #Ptah for the suggestion on the animation.
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.
I am working on a small application on Mac that I need to create customed cursor and move it. I used NSImageView to implement it. However when I call setFrameOrigin (the same to setFrame) it will leaves images on the previous place.
Here is my code:
#property (nonatomic, strong) NSImageView *eraserView;
this is the define
_eraserView = [[NSImageView alloc] initWithFrame:CGRectMake(100, 100, 32, 32)];
_eraserView.image = [NSImage imageNamed:#"EraserCursor"];
[self.view addSubview:_eraserView];
[_eraserView setHidden:YES];
here is the initialization. Everything goes well until now but:
- (void)setImageatPoint:(NSPoint)point
{
[_eraserView setFrameOrigin:point];
}
- (void)hidePenImage
{
[_eraserView setHidden:YES];
}
- (void)unhidePenImage: (BOOL)isEraser
{
[_eraserView setHidden:NO];
}
These are methods I use to change the state of the NSImageView. They will be called by another class using delegate when corresponding events of trackpad occurs.
However every time I change the state of the NSImageView, it seems like it is drawn on the superview.
I debugged it and found there was no extra subviews. And when I use setHidden it has no effect on those tracks. I think it somehow did something to the CALayer, but I have no idea how to fix it.
Screenshots would help but in general if you move a view or change the area of the view that is drawn, you need to redraw.
To do this it kind of depends on how your drawing happens. Calling setNeedsDisplay may not be enough if your implementation of drawRect only draws a sub rect of the view bounds. Cocoa only draws what it is told to draw.
You can erase sections of the view that should be empty by drawing (filling) where it should be empty. That means drawing a color ( NSColor clearColor if nothing else) in the area that was previously drawn.
I'm working on an iPad app that lets you control different things in a prototype of an intelligent house. For example it lets you turn lights on and off. For this, I have made a UIImageView that shows the floor plan of the house and added UIButtons as subviews for each lamp that can be toggled.
As you can see the buttons are placed perfectly on the floor plan using the setFrame method of each UIButton. However, when I rotate the iPad to portrait orientation, the following happens:
The buttons obviously still have the same origin, however it is not relative to the repositioning of the image.
The floor plan image has the following settings for struts and springs:
and has its content mode set to Aspect Fit.
My question is
how do I dynamically reposition each UIButton, such that it has the same relative position. I figure I have to handle this in the {did/should}AutorotateToInterfaceOrientation delegate method.
It should be noted that the UIImageView is zoomable and to handle this I have implemented the scrollViewDidZoom delegate method as follows:
for (UIView *button in _floorPlanImage.subviews) {
CGRect oldFrame = button.frame;
[button.layer setAnchorPoint:CGPointMake(0.5, 1)];
button.frame = oldFrame;
button.transform = CGAffineTransformMakeScale(1.0/scrollView.zoomScale, 1.0/scrollView.zoomScale);
}
Thank you in advance!
I find the best way to layout subviews is in the - (void) layoutSubviews method. You will have to subclass your UIImageView and override the method.
This method will automatically get called whenever your frame changes and also gets called the first time your view gets presented.
If you put all your layout code in this method, it prevents layout fragmentation and repetition, keeps your view code in your views, and most things just work by default.
I'm experimenting with some code which probes a UI to see it's structure. As part of this I am doing a hitTest on a UISegmentedControl which is embedded in a UIToolbar at the bottom of the screen. I have a structure like this:
UIToolbar
UISegmentedControl
UISegment
...
I get the centre of the UISegmentedControl and hit test it like this:
UIView *view = // code which gets a reference to the UISegmentedControl.
frameInWindow = [view.window convertRect:view.frame fromView:view.superview];
CGPoint locationInWindow = CGPointMake(
frameInWindow.origin.x + 0.5 * frameInWindow.size.width,
frameInWindow.origin.y + 0.5 * frameInWindow.size.height);
UIView *target = [view.window hitTest:locationInWindow withEvent:nil];
I've been over this numerous times and I cannot see why it sets target to the UIToolbar instead of the UISegmentedControl. I would have expected target to be the same control. Or some UIView inside the segmented control.
The docs say:
"This method ignores view objects that are hidden, that have disabled
user interaction, or have an alpha level less than 0.01. This method
does not take the view’s content into account when determining a hit.
Thus, a view can still be returned even if the specified point is in a
transparent portion of that view’s content."
Is user interaction with your segmented control enabled?