I'm initializing a loader subview to match the height, width and position of the UITabBar I'm using to wrap my app:
// In UITabBarController implementation
LoaderView *loaderView = [[LoaderView alloc] initWithFrame:[self tabBar].viewForBaselineLayout.frame];
[[self view] addSubview:loaderView];
//
// LoaderView.h
#import <UIKit/UIKit.h>
#interface LoaderView : UIView
#property (nonatomic, strong) UILabel *messageLabel;
#property (nonatomic, strong) NSString *message;
#property (nonatomic) CGRect frame;
- (void)createLabel;
- (void)drawLoader;
- (void)setText:(NSString *)newMessage;
- (void)show:(NSNotification *)notification;
#end
//
// LoaderView.m
#import "LoaderView.h"
#implementation LoaderView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self drawLoader];
}
return self;
}
- (void)drawLoader
{
UIColor *semiOpaqueGray = [[UIColor alloc] initWithRed:0.0f green:0.0f blue:0.0f alpha:0.8f];
[self setBackgroundColor:semiOpaqueGray];
[self createLabel];
}
- (void)createLabel
{
_messageLabel = [[UILabel alloc] initWithFrame: CGRectMake(15,9,([self frame].size.width - 10), 30)];
_messageLabel.textColor = [[UIColor alloc] initWithWhite:1.0 alpha:1];
_messageLabel.backgroundColor = [[UIColor alloc] initWithWhite:1.0 alpha:0.0];
[self addSubview:_messageLabel];
}
#end
The frame struct represents this incoming frame data:
2013-09-16 07:48:35.552 ---[97825:a0b] {{0, 519}, {320, 49}}
// Ostensibly 0,519 origin point and 320,49 w/h
The result is this. The mostly opaque dark box can be spotted in the top left corner. It looks like it's being positioned by its center point of the loader to the top left most point of the screen:
I can make the size of the box change, but I can't seem to move it from that top left position. Further, I set an animation on it, and that animation adjusts the frame (sliding it up an down from the tab bar area). That seems to have no effect either.
Thanks in advance for your help.
You can gently add your loadingView your application window. After set the frame of loaderView.
[loadView setFrame:CGRectMake(0,0,self.frame.size.width.,self.frame.size.height)];
[self.window addSubview:loaderView];
Then after loading finished.
[self.window removeSubview:loaderView];
Your superview is the problem. If you're adding it to your UINavigationController then the y-axis likely won't respond nicely. Try using the primary view of your controller
loaderView.frame = CGRectMake(x, 514, 40, 320); // made up numbers
[self.mapView addSubview:loaderView];
Also you're accessing your tabBar. Try using UIDevice window for getting your width and inherit the height from your labels on the bottom (or nest the labels within your LoaderView)
Also look into actually using UITabBar for handling this.
Related
In Storyboard I applied Multiplier for height and width to UIImageView then I just want to rounded border so I used below code its not work for all iPhones.
_profileImgView.clipsToBounds = YES;
_profileImgView.layer.backgroundColor = color.CGColor;
_profileImgView.layer.cornerRadius =_profileImgView.frame.size.width/2;
_profileImgView.layer.borderColor = [UIColor colorWithRed:253.0/255.0 green:182.0/255.0 blue:43.0/255.0 alpha:100].CGColor;
_profileImgView.layer.borderWidth = 5.0f;
Since your corner radius depends on your frame size, you need to update it whenever the frame size changes. If you are using storyboards for your design, you will get the frame size that is in the design when viewDidLoad is called. If the frame size differs for different devices, you will get the final size at a later point in time in the views layoutSubviews or possibly the view controller's viewDidLayoutSubviews.
My suggested solution is to sub-class UIImageView and put the specifics for the image view in awakeFromNib and layoutSubviews, then use this class instead of UIImageView where appropriate.
// CircularImageView.h
#import <UIKit/UIKit.h>
#interface CircularImageView : UIImageView
#end
// CircularImageView.m
#implementation CircularImageView
- (void)awakeFromNib {
[super awakeFromNib];
self.clipsToBounds = YES;
self.layer.borderColor = [UIColor colorWithRed:253.0/255.0 green:182.0/255.0 blue:43.0/255.0 alpha:100].CGColor;
self.layer.borderWidth = 5.0f;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.layer.cornerRadius = self.frame.size.width / 2;
}
#end
implement this code in same Viewcontroller class it is work for me
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
_profileImgView.clipsToBounds = YES;
_profileImgView.layer.backgroundColor = color.CGColor;
_profileImgView.layer.cornerRadius =_profileImgView.frame.size.width/2;
_profileImgView.layer.borderColor = [UIColor colorWithRed:253.0/255.0 green:182.0/255.0 blue:43.0/255.0 alpha:100].CGColor;
_profileImgView.layer.borderWidth = 5.0f;
}
I have 2 monitors, and I'd like to get my videoWindow to be placed and scaled to the size of the second monitor. I'd like to do this programmatically, as the second monitor resolution may change. I'm able to get the window placed in the bottom-left of the second monitor, but I'm not able to scale it to fit.
The warning on this line:
[self.videoWindow setFrame: screenRect];
Is: 'NSWindow' may not respond to 'setFrame'
// inside my .h file
#property (assign) IBOutlet NSWindow *videoWindow;
// inside my .m file
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
NSRect videoPreviewScreenRect;
NSArray *screenArray = [NSScreen screens];
//Using index of 1, to get secondary monitor
NSScreen *videoPreviewScreen = [screenArray objectAtIndex: 1];
NSRect screenRect = [videoPreviewScreen frame];
videoPreviewScreenRect = [videoPreviewScreen visibleFrame];
// Get and set the screen origin based on the second monitors origin
NSPoint videoScreenOrigin ;
videoScreenOrigin.x = videoPreviewScreenRect.origin.x;
videoScreenOrigin.y = videoPreviewScreenRect.origin.y;
[self.videoWindow setFrameOrigin: videoScreenOrigin];
// **** THIS LINE DOESN'T WORK ****
[self.videoWindow setFrame: screenRect];
[self.videoWindow setBackgroundColor: NSColor.blackColor];
[self.videoWindow display];
[self.videoWindow makeKeyAndOrderFront:nil];
}
I was able to figure out what the issue was.
[self.videoWindow setFrame: screenRect];
needed to be changed to this:
[[self videoWindow] setFrame:screenRect display:YES animate:NO];
I draged out a generic view and hooked it up to my circleView.m. I then dragged out a round rect button on top of that view and hooked up an IBAction to it. As of right now, when the view loads the circle is automatically drawn onto the screen. What I would like to do is draw the circle on the screen only when the button is pressed using drawRect or some other draw method. Here is my code:
drawCircleViewController.h
#import <UIKit/UIKit.h>
#interface drawCircleViewController : UIViewController
#end
drawCircleViewController.m
#import "drawCircleViewController.h"
#import "circleView.h"
#interface drawCircleViewController()
#property (nonatomic, weak) IBOutlet circleView *circleV;
#end
#implementation drawCircleViewController
#synthesize circleV = _circleV;
- (IBAction)buttonPressedToDrawCircle:(id)sender {
// This is action I want to use to draw the circle in my circleView.m
}
#end
circleView.h
#import <UIKit/UIKit.h>
#interface circleView : UIView
#end
circleView.m
#import "circleView.h"
#implementation circleView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawCircleAtPoint:(CGPoint)p
withRadius:(CGFloat)radius
inContext:(CGContextRef)context
{
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);
CGContextStrokePath(context);
UIGraphicsPopContext();
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGPoint midpoint;
midpoint.x = self.bounds.origin.x + self.bounds.size.width / 2;
midpoint.y = self.bounds.origin.y + self.bounds.size.height / 2;
#define DEFAULT_SCALE 0.90
CGFloat size = self.bounds.size.width / 2;
if (self.bounds.size.height < self.bounds.size.width) size = self.bounds.size.height / 2;
size *= DEFAULT_SCALE;
CGContextSetLineWidth(context, 5.0);
[[UIColor blueColor] setStroke];
[self drawCircleAtPoint:midpoint withRadius:size inContext:context];
}
#end
With what you have there, the simplest approach would probably be to make your circle view hidden and show it when the button is pressed.
Otherwise, you can keep a BOOL in your view to denote whether the button has been tapped and check that during drawRect: (and use setNeedsDisplay to trigger changes).
I am trying to add a (fake)3d like effect for an image (UIImageView moving from point A to B, during this movement I want at point C=(A+B)/2 for it to have the biggest shadow size (or larger shadow offset), so it looks like it is going up and down again.
when I try to even change the shadow size, it is not animating. could you help me how to edit this code:
NSValue *pointB = [NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(imageView.frame)+50, CGRectGetMinY(imageView.frame)+50)];
[self.view bringSubviewToFront:ImageView];
[UIView beginAnimations:#"UIImage Move" context:NULL];
CGPoint point = [pointB CGPointValue];
CGSize size =imageView.frame.size;
[UIView setAnimationDuration:1.0];
imageView.frame = CGRectMake(point.x, point.y, size.width, size.height);
imageView.layer.shadowOffset = CGSizeMake(0, 4); //actually I want this to happen in mid point and revert to offset 1
[UIView commitAnimations];
//sorry for possible problems with syntax, the code works fine, I had to rewrite and simplify it for understanding
You need to animate the shadowOffset of the layer by using CAAnimation. Here is an example on how to enlarge the shadowOffset while moving the object. This example uses a UIButton.
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface ViewController : UIViewController
#property (nonatomic, retain) IBOutlet UIButton *button;
#end
In the M file I am calling the animations on the button from the buttons IBAction.
-(IBAction)shadowGrow:(id)sender {
CABasicAnimation *shadowGrow = [CABasicAnimation animationWithKeyPath:#"shadowRadius" ];
shadowGrow.delegate = self;
[shadowGrow setFromValue:[NSNumber numberWithFloat:3.0]];
[shadowGrow setToValue:[NSNumber numberWithFloat:20.0]];
[shadowGrow setDuration:1.0f];
shadowGrow.autoreverses = YES;
CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:#"transform.translation.x" ];
move.delegate = self;
[move setFromValue:[NSNumber numberWithFloat:0]];
[move setToValue:[NSNumber numberWithFloat:50]];
[move setDuration:1.0f];
move.autoreverses = YES;
//Add animation to a specific element's layer. Must be called after the element is displayed.
[[button layer] addAnimation:shadowGrow forKey:#"shadowRadius"];
[[button layer] addAnimation:move forKey:#"transform.translation.x"];
}
One thing to remember with CoreAnimation is when animating the properties like this they are going to revert to their value from the start unless you set those values after the animation ends in the CAAnimation's Delegate Method.
- (void) animationDidStop:(NSString *)theAnimation finished:(NSNumber *)finished context:(void *)context
Here is some additional information on CALayer's animatable properties.
CALayer and CIFilter animatable properties
I'm currently initializing my UITableViewCell's backgroundView's frame with self.frame. This seems to work fine for device orientation changes (cell background fills entire cell, looks fine etc). What's a better frame to use (if any)?
Edit #1: I've also initialized the backgroundView with CGRectZero as the frame. This seems to make no difference (UITableViewCells and backgroundViews function just fine in all interface orientations).
I've also tested setting the autoresizingMask property of the backgroundView. This made no difference either. I'd just like to understand what (if anything) is affected by the backgroundViews initial frame.
Assuming that you are trying to add a UIImageView as backgroundView and that you are trying to resize that imageView, here's my experience:
It seems to be impossible to change the frame of UITableViewCell.backgroundView (or at least not a thing Apple recommends, hence it's not mentioned in the documentation). To use a custom sized UIImageView, eg with a resizable UIImage, as background in a UITableViewCell, I do the following:
1) Create a UIImageView and set its image property to an image of your wish.
2) Add the UIImageView as a subview of the UITableViewCell using the addSubview: message.
3) Send the UIImageView to the back using sendSubviewToBack: message.
This puts your UIImageView behind any other added subviews and you are now able to manipulate the frame of your 'backgroundView' (aka the imageview).
To make sure the imageview will fit the tableViewCell's frame, use cell.frame's height and width properties when calculating the height of your imageview.
If you develop custom table view cell the solution is to adjust the frame in layoutSubviews method. Here is custom UITableViewCell from one of my projects, I needed 10 points margin from left:
#import "TETopicCell.h"
#import "UIColor+Utils.h"
#implementation TETopicCell
#synthesize topicTitleLabel = _topicTitleLabel;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
UIImageView *bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"theme_btn_yellow"]];
bgImageView.contentMode = UIViewContentModeTopLeft;
bgImageView.frame = CGRectMake(0.0f, 0.0f, 239.0f, 42.0f);
self.backgroundView = bgImageView;
_topicTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(46.0f, 0.0f, 206.0f, 42.0f)];
_topicTitleLabel.backgroundColor = [UIColor clearColor];
_topicTitleLabel.textColor = [UIColor colorWithR:116 G:74 B:1];
[self.contentView addSubview:_topicTitleLabel];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// update frame here
self.backgroundView.frame = CGRectOffset(self.backgroundView.frame, 10.0f, 0.0f);
// and here
if (self.selectedBackgroundView){
self.selectedBackgroundView.frame = CGRectOffset(self.selectedBackgroundView.frame, 10.0f, 0.0f);
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if (selected) {
UIImageView *selectedImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"theme_btn_red"]];
selectedImageView.contentMode = UIViewContentModeTopLeft;
selectedImageView.frame = CGRectMake(0.0f, 0.0f, 239.0f, 42.0f);
self.selectedBackgroundView = selectedImageView;
[_topicTitleLabel setTextColor:[UIColor colorWithR:255 G:211 B:211]];
}
else {
self.selectedBackgroundView = nil;
[_topicTitleLabel setTextColor:[UIColor colorWithR:116 G:74 B:1]];
}
}
#end