Fixed UIView for collision - ios

Is it possible to place an UIView fixed but as collision-object? In my example is a box-view falling down and collide with the floor-view. I want the floor-view to stay at it's place but it's moving after it's been hit by the box.
How can I glue it in one place (I don't want to enlarge the object or use other objects than UIView (UIBezierPath etc)).
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *start = [[UIButton alloc]initWithFrame:CGRectMake(200, 20, 40, 40)];
start.backgroundColor = [UIColor redColor];
[start addTarget:self action:#selector(start) forControlEvents:UIControlEventTouchUpInside];
[main addSubview:start];
self.box1 = [[UIView alloc]initWithFrame:CGRectMake(50, 0, 20, 20)];
self.box1.backgroundColor = [UIColor redColor];
[main addSubview:self.box1];
self.floor = [[UIView alloc]initWithFrame:CGRectMake(0, main.frame.size.height-20, main.frame.size.width, 200)];
self.floor.backgroundColor = [UIColor lightGrayColor];
[main addSubview:self.floor];
}
- (void) start {
self.animation = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];
UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:#[self.box1]];
[self.animation addBehavior:gravity];
UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:#[self.box1, self.floor]];
[self.animation addBehavior:collision];
}

One solution to your problem (which is a quite simple setup) could be to create an UIView that will serve as a reference view. Set it's frame so the bottom of the view will be your floor. Then add your box as a subview for that reference view, add collision behaviour with translatesReferenceBoundsIntoBoundary set to YES and you have a box falling on the floor.
// Reference view
CGRect referenceFrame = CGRectMake(0, 0, 320, 500); // the floor will be at y = 500
UIView *referenceView = [[UIView alloc] initWithFrame:referenceFrame];
[self.view addSubview:referenceView];
// Box
CGRect boxFrame = CGRectMake(50, 50, 10, 10);
UIView *boxView = [[UIView alloc] initWithFrame:boxFrame];
boxView.backgroundColor = [UIColor redColor];
[referenceView addSubview:boxView];
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:referenceView];
// Gravity
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:#[boxView]];
[self.animator addBehavior:gravity];
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:#[boxView]];
collision.translatesReferenceBoundsIntoBoundary = YES;
[self.animator addBehavior:collision];
You can provide a pretty visual for the floor outside of referenceView

I used UIDynamicItemBehavior for my view and set the following property to be true.
#property(nonatomic, getter=isAnchored) BOOL anchored;
This locked the UIView in place. Do what you were doing above to add the item to the behavior and add the behavior to the animator.

Related

Programmatically added subview frames don't show up right in scrollview

I'm creating a scrollView programmatically, and all the views in it. However, when I add more then 1 view, the other views layers don't show up right in their respective frames.
For example:
-(void)viewDidLoad {
[super viewDidLoad];
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, 150*5);
self.scrollView.backgroundColor = [UIColor lightGrayColor];
self.scrollView.scrollEnabled = YES;
self.scrollView.showsVerticalScrollIndicator = NO;
[self.view addSubview:self.scrollView];
[self setUpLogInButtons];
}
Then I set the subViews to scrollView up here:
-(void)setUpLogInButtons {
CGFloat subviewWidth = self.scrollView.frame.size.width/2;
CGFloat subviewHeight = 150;
UIView *facebookView = [[UIView alloc] init];
facebookView.frame = CGRectMake(0, 0, subviewWidth, subviewHeight);
[facebookView.layer insertSublayer:[self gradientLayerForViewFrame:facebookView.frame withColors:[self colorArrayWithValues:0x4A5C81 v2:0x495B82 v3:0x495B82 v4:0x475B85 v5:0x465B87 v6:0x455A88 v7:0x445A8A v8:0x435A8B v9:0x425A8D v10:0x41598F v11:0x405990 v12:0x3F5992 v13:0x3E5993 v14:0x3D5895 v15:0x3C5896 v16:0x3B5898 v17:0x3A589A]] atIndex:0];
[facebookView addSubview:[self label:self.facebookLabel forView:facebookView withName:#"Facebook" loggedIn:NO]];
[self.scrollView addSubview:facebookView];
}
When it's one subView it works fantastic, when I add the other one it's not right:
-(void)setUpLogInButtons {
...
UIView *facebookView = [[UIView alloc] init];
...
[self.scrollView addSubview:facebookView];
UIView *twitterView = [[UIView alloc] init];
twitterView.frame = CGRectMake(subviewWidth, 0, subviewWidth, subviewHeight);
[twitterView.layer insertSublayer:[self gradientLayerForViewFrame:twitterView.frame withColors:[self colorArrayWithValues:0x2BA8D5 v2:0x28A8D6 v3:0x25A8D8 v4:0x22A8D9 v5:0x20A9DB v6:0x1DA9DC v7:0x1AA9DE v8:0x18AADF v9:0x15AAE1 v10:0x12AAE3 v11:0x10ABE4 v12:0x0DABE6 v13:0x0AABE7 v14:0x08ACE9 v15:0x05ACEA v16:0x02ACEC v17:0x00ADEE]] atIndex:0];
[twitterView addSubview:[self label:self.twitterLabel forView:twitterView withName:#"Twitter" loggedIn:NO]];
[self.scrollView addSubview:twitterView];
}
This one does not show up, the layers specifically are off. However, here is the kicker, the label shows in the right spot because the labels frame is based on it's parent view frame.
-(UILabel *)label:(UILabel *)viewLabel forView:(UIView *)accountView withName:(NSString *)name loggedIn:(BOOL)loggedinStatus {
UILabel *label = viewLabel;
label.frame = CGRectMake(0, accountView.frame.size.height - 50, accountView.frame.size.width, 50);
label.text = [self setAccountLabelForName:name loggedIn:loggedinStatus];
label.textColor = [UIColor whiteColor];
label.textAlignment = NSTextAlignmentLeft;
return label;
}
here is a picture that shows you that the label is based off the parents view frame, and it shows up correctly, but the gradient does not, and it's based off the same frame.
and my gradient method:
-(CAGradientLayer *)gradientLayerForViewFrame:(CGRect)viewFrame withColors:(NSArray *)colors {
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = viewFrame;
gradient.colors = colors;
return gradient;
}
For some reason when inserting my gradient layer to the views layer I had to change it:
//INSTEAD OF THIS:
[... insertSublayer:[self gradientLayerForViewFrame:facebookView.frame...];
//THIS WORKED FLAWLESSLY:
[... insertSublayer:[self gradientLayerForViewFrame:facebookView.bounds...];

How do I crop a MKMapView (or any UIView) into a custom shape?

I'm trying to size an MKMapView in the following way:
Elements should be able to appear behind the arc at the top, so it appears that the view is not square. I know this should be possible with CALayer, but perhaps someone has done it before?
This should be quite possible if you put your MKMapView within a UIView, then apply a mask to that.
Here's a very (!) basic example:
All I've done is put my map in a UIView called "mapContainer" and added a mask to it using this:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGRect rect = CGRectInset(self.view.frame, 70, 70);
UIView* newView = [[UIView alloc] initWithFrame:rect];
newView.layer.cornerRadius = 55.0;
newView.backgroundColor = [UIColor redColor];
self.mapContainer.layer.mask = newView.layer;
}
And you could add a border to it...
..with a few more lines...
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGRect rect = CGRectInset(self.view.frame, 70, 70);
UIView* newView = [[UIView alloc] initWithFrame:rect];
newView.layer.cornerRadius = 55.0;
newView.backgroundColor = [UIColor redColor];
UIView* borderView = [[UIView alloc] initWithFrame:rect];
borderView.backgroundColor = [UIColor clearColor];
borderView.layer.cornerRadius = 55.0;
borderView.layer.borderWidth = 3.0;
borderView.layer.borderColor = [[UIColor redColor] CGColor];
[self.mapContainer addSubview:borderView];
[self.mapContainer bringSubviewToFront:borderView];
self.mapContainer.layer.mask = newView.layer;
}
I hope this points you in the right direction.
Unlike Apple Maps.
;-)

Remove previous UIView before creating another on

I have a method were I'm creating UIView and it works fine when I call it from IBAction. But when I call the same method again it draws another view on top and I believe it's a memory leak. How do I remove previous UIView before creating another one? Thanks!
- (int)showQuestionMethod:(int)number;
{
UIView *questionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
[self.view addSubview:questionView];
questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
questionLabel.text = question1;
[questionView addSubview:questionLabel];
CGRect frame = questionView.frame;
frame.size.height = questionHeight;
questionView.frame = frame;
questionView.tag = questionNumber;
return currentQuestion;
}
- (IBAction)nextQuestion:(id)sender {
[self showQuestionMethod:questionNumber];
}
Create a property which will let you reference a view:
#property(nonatomic, strong) UIView *questionView;
Then change your method to remove the old view and create a new one:
- (int)showQuestionMethod:(int)number;
{
// Remove the previous view.
[_questionView removeFromSuperview];
// Create a new view.
_questionView= [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
_questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
// Add the view.
[self.view addSubview:_questionView];
_questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
questionLabel.text = question1;
[_questionView addSubview:questionLabel];
CGRect frame = _questionView.frame;
frame.size.height = questionHeight;
_questionView.frame = frame;
_questionView.tag = questionNumber;
return currentQuestion;
}
The simplest way would be to keep a reference to the view you will want to remove (a private property would work nicely). You could add the code at bottom to the top of your controllers .m file:
#interface MyUIViewController ()
#property (nonatomic, strong) UIView* questionView;
#end
Then modify your method as follows:
- (int)showQuestionMethod:(int)number;
{
[self.questionView removeFromSuperview]
self.questionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
self.questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
[self.view addSubview:self.questionView];
self.questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
self.questionLabel.text = question1;
[self.questionView addSubview:questionLabel];
CGRect frame = questionView.frame;
frame.size.height = questionHeight;
self.questionView.frame = frame;
self.questionView.tag = questionNumber;
return currentQuestion;
}
use this before creating new view
[myview removeFromSuperview];
You can either keep a reference to the view by adding #property (strong, nonatomic) UIView *questionView; in your #interface declaration then call [_questionView removeFromSuperview]; to remove it.
Or, better yet, keep that reference to it then have a method to reload the info on it and animate it out/back into view (perhaps by fading out, reloading the data on it, then fading it back in). That way you aren't throwing away / recreating views all the time, and instead you're just reusing the same, already created view.
[self.questionView removeFromSuperview];
before adding the other view, remove this from the superview!
Why not reuse the view?
If you'd rather delete it every time and you don't want to keep a reference to it, you can always set (dirty but simple):
questionView.tag = SOME_CONST;
And then add in the beginning of your method:
[[self.view viewWithTag:SOME_CONST] removeFromSuperview];
I know this question has been answered, but i want to add a precaution that you before removing a UIView or anything else you should FIRST CHECK IF IT IS ALLOCATED. So the removal should be like:
// Make property first
#property (nonatomic, strong) UIView *questionView;
- (int)showQuestionMethod:(int)number;
{
// Check it it is allocated
if(questionView)
{
[questionView removeFromSuperView];
//[questionView release]; // Un-Comment it if NOT using ARC
questionView = nil;
}
// At this point you safe to create a new UIView.
questionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
[self.view addSubview:questionView];
questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
questionLabel.text = question1;
[questionView addSubview:questionLabel];
CGRect frame = questionView.frame;
frame.size.height = questionHeight;
questionView.frame = frame;
questionView.tag = questionNumber;
return currentQuestion;
}
Hope the snippet and comment inside makes sense.
Happy Coding!!!

How can I add UIView object to self.view.window in ios7?

I'd like to add a dark view layer that covers the whole screen.
In order to do that, I added UIView object to window property of UIViewController as shown below.I remember I was able to add a view to window like this in ios6. But, it doesn't work in ios7.
How am I able to make it work?
Thanks in advance!!
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
overlayView.backgroundColor = [UIColor blackColor];
overlayView.alpha = 0.8;
[self.view.window addSubview:overlayView];
}
Here's one way of doing what you want:
[[UIApplication sharedApplication].keyWindow addSubview:overlayView];
According to the documentation of UIView, the window property is nil if the view has not yet been added to a window which is the case when viewDidLoad is called.
You can do the same thing in viewDidAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated; {
UIView *overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
overlayView.backgroundColor = [UIColor blackColor];
overlayView.alpha = 0.8;
[self.view.window addSubview:overlayView];
}
Swift 3
UIApplication.shared.keyWindow?.addSubview(overlayView);
you can try like this
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *overlayView = [[UIView alloc] initWithFrame:self.view.frame];
overlayView.backgroundColor = [UIColor blackColor];
overlayView.alpha = 0.8;
overlayView.center = self.view.center
[self.view addSubview:overlayView];
}
i hope will helpful for you...

UIScrollView programmatically Scrolling

I have a UITextView inside a UIScrollView that needs to automatically scroll once the user starts editing it. This is because the keyboard will cover the textview.
Here is the code -
In viewDidLoad:
feedBackformView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, segmentedControl.frame.origin.x + self.segmentedControl.frame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
feedBackformView.backgroundColor = [UIColor whiteColor];
feedBackformView.scrollEnabled = YES;
feedBackformView.delegate = self;
feedBackformView.userInteractionEnabled = YES;
feedBackformView.showsVerticalScrollIndicator = YES;
feedBackformView.contentSize = CGSizeMake(320, 700);
commentsView = [[UITextView alloc] initWithFrame:CGRectMake(5, emailField.frame.origin.y + 40, 250, 150)];
commentsView.delegate = self;
commentsView.layer.borderWidth = 2.0f;
commentsView.layer.cornerRadius = 5;
and here's the delegate method implementation -
-(void)textViewDidBeginEditing:(UITextView *)textView{
CGPoint point = textView.frame.origin;
[scrollView setContentOffset:point animated:YES];
}
However, nothing happens.
your are doing fine but use feedBackformView instead of scrollView,while setting content offset in textViewDidBeginEditing:method, just have a look on below code
feedBackformView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 50, 320, 200)];
feedBackformView.backgroundColor = [UIColor whiteColor];
feedBackformView.scrollEnabled = YES;
feedBackformView.delegate = self;
feedBackformView.userInteractionEnabled = YES;
feedBackformView.showsVerticalScrollIndicator = YES;
feedBackformView.contentSize = CGSizeMake(320, 700);
commentsView = [[UITextView alloc] initWithFrame:CGRectMake(5, 40, 250, 150)];
commentsView.delegate = self;
commentsView.layer.borderWidth = 2.0f;
commentsView.layer.cornerRadius = 5;
[feedBackformView addSubview:commentsView];
[self.view addSubview:feedBackformView];
in textview DelegateMethod,
-(void)textViewDidBeginEditing:(UITextView *)textView{
CGPoint point = textView.frame.origin;
[feedBackformView setContentOffset:point animated:YES];
}
hope it will hepls you...
You can use scrollView scrollRectToVisible:animated or the setContentOffset:animated methods described here:
UIScrollView Class Reference
Keep in mind that UITextView comes with its own scroll view. so you may not need to nest it inside another scrollview. But you may need to if your app is that interesting.
Is your point of scrolling already at a visible point?
-(void)textViewDidBeginEditing:(UITextView *)textView{
// try this instead
CGPoint point = CGPointMake(textView.frame.origin.x,
textView.frame.origin.y + textView.frame.size.height);
[scrollView setContentOffset:point animated:YES];
// What does this produce?
NSLog(#"%# %#", NSStringFromCGPoint(scrollView.contentOffset),
NSStringFromCGRect(textView.frame));
}

Resources