I would like to implement a temporary alert into to a uitableviewcontroller to inform a user that their data has been saved.
I could do this with a uiAlertView - but for aesthetic reasons it would be preferable to implement something similar to the round cornered fade in/out alert view used in IOS7 for tasks such as showing volume control - as in this pic -
Is this a IOS7 class? I cant find any info on it (probably because I don't know what its called!), or would I need to extend the uiAlertView to replicate this functionality?
No, this is not a native iOS 7 subclass but there are plenty implementations of it in the wild. One example would be DTAlertView or CXAlertView or SDCAlertView. Check them out.
If you just want the volume-thingy type behavior, don't search too far. It's easily home-rolled with a full screen sized image view that's mostly transparent, and has in it's center a rounded-corner message rectangle, translucent if you like. Then build a convenience method to show/hide it with animation...
- (void)setAlertHidden:(BOOL)hidden animated:(BOOL)animated {
UIImageView *alertImageView = [self alertImageView];
BOOL currentlyHidden = alertImageView.alpha == 0.0;
if (currentlyHidden == hidden) return;
NSTimeInterval alpha = (hidden)? 0.0 : 1.0;
NSTimeInterval duration = (animated)? 0.3 : 0.0;
[UIView animateWithDuration:duration animations:^{
alertImageView.alpha = alpha;
} completion:^(BOOL finished) {
// if we showed the alert, hide it after 3 seconds
// you can make this duration a parameter
if (!hidden) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self setAlertHidden:YES animated:YES];
});
}
}];
}
All you need other than this is to build the image view lazily...
- (UIImageView *)alertImageView {
UIImageView *alertImageView = (UIImageView *)[self.view viewWithTag:999];
if (!alertImageView) {
alertImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
alertImageView.image = [UIImage imageNamed:#"fullscreen-volume-looking-thing.png"];
alertImageView.tag = 999;
[self.view addSubview:alertImageView];
}
return alertImageView;
}
Realize it's not exactly what you need, but this was pretty easy to paste together. It's the volume thing on a screen sized transparent background...
This is a quick implementation of a subview that will do what you want
#import "BellAlert.h"
#implementation BellAlert
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
UIImageView *bell = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Bell.png"]];
bell.frame = CGRectMake(0, 0, 50, 50);
bell.center = self.center;
[self addSubview:bell];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1].CGColor);
CGContextMoveToPoint(context, 5, 0);
CGContextAddLineToPoint(context, 95, 0);
CGContextAddArcToPoint(context, 100, 0, 100, 5, 10);
CGContextAddLineToPoint(context, 100, 95);
CGContextAddArcToPoint(context, 100, 100, 95, 100, 10);
CGContextAddLineToPoint(context, 5, 100);
CGContextAddArcToPoint(context, 0, 100, 0, 95, 10);
CGContextAddLineToPoint(context, 0, 5);
CGContextAddArcToPoint(context, 0, 0, 5, 0, 10);
CGContextFillPath(context);
}
#end
If you want more complex functionality, you can implement public properties and a protocols
If you want to check it working look at it at GitHub... https://github.com/eharo2/BellAlert
for aesthetic reasons it would be preferable to implement something
similar to the round cornered fade in/out alert view used in IOS7
Rounding the corners of any view is incredibly easy:
someView.layer.cornerRadius = 5.0;
Making a view fade in and out is also trivial using Core Animation. For example, if you want to fade in someView, set its alpha property to 0 and then animate setting it to 1:
someView.alpha = 0.0;
[UIView animateWithDuration:1.0 animations:^{
someView.alpha = 1.0;
}];
With those tools at your disposal, you'll find it very easy to roll your own version of Apple's display.
Related
I wrote an example about Wave Animation.The animation is ok,but I don't understand why the custom UIView needs to add "self.layer.masksToBounds = YES" to have the round Corner.
This is a custom UIView. I have rewritten its drawRect. If i don't set "masksToBounds" to YES, the round corner disappear.
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.frame = CGRectMake(10, 40, 300, 300);
self.layer.cornerRadius = 150;
self.backgroundColor = [UIColor greenColor];
self.layer.borderColor = [UIColor blueColor].CGColor;
self.layer.borderWidth = 2;
// self.layer.masksToBounds = YES; //if write this line,the round corner appear
self.x_move = 0;
self.y_move = 300;
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();
CGContextSetLineWidth(context, 1);
CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
CGPathMoveToPoint(path, NULL, 0, 0);
for(float i=0; i<=300; i++){
float x=i;
float y = 5 * sin( 0.05 * x+ self.x_move) + self.y_move;
CGPathAddLineToPoint(path, nil, x, y);
}
CGPathAddLineToPoint(path, nil, 300, 0);
CGPathAddLineToPoint(path, nil, 0, 0);
CGContextAddPath(context, path);
CGContextFillPath(context);
CGContextDrawPath(context, kCGPathStroke);
CGPathRelease(path);
}
- (void)startAnimation {
if (self.waveTimer == nil) {
self.waveTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(refresh) userInfo:nil repeats:YES];
}
}
- (void)refresh {
self.x_move += 0.3;
self.y_move -= 0.2;
if(self.y_move - 100 < 0.00001){
[self.waveTimer invalidate];
}else{
[self setNeedsDisplay];
}
}
ViewController:
self.wave = [[waveAnimation alloc] init];
[self.wave startAnimation];
[self.view addSubview:self.wave];
This is a normal UIView. Its "masksToBunds" is NO, but its round corner shows normal. Compared with the examples above, why one should add, one does not need.
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(20, 60, 100, 100)];
view.backgroundColor = [UIColor greenColor];
view.layer.cornerRadius = 50;
view.layer.borderWidth = 2;
view.layer.borderColor = [UIColor blackColor].CGColor;
[self.view addSubview:view];
The reason for this is from your override of drawRect:(CGRect)frame.
You are attempting to set the corner radius of the layer that is not the element you assigned the fill color to. The reason setting masksToBounds achieves the desired rounded corner is because here you are telling the view to mask all of it's layers to the bounds from your frame.
In your second example with the UIView the corner radius appears as expected because you have not adjusted it's layers.
I suggest either adopting setting masksToBounds or redraw the view's bounds a different way if you need masksToBounds = NO. Since you have the "squiggle" sin curve and you want rounded corners, perhaps just create a generic rounded rect (one with the desired corner radius) then merge that with the path you have already created with the sin wave.
Merge multiple CGPaths together to make one path
That link may help you merge your rounded view with your custom view to achieve the desired end result.
Otherwise.. probably best bet to just set this to yes.
I want to make something like this:
Reference of image.
What I do: two UIImagesView, one with UIViewContentModeLeft and another with UIViewContentModeRight. I have a slider where I can change image frames. The solution seems to be ok, but I am not sure if this is the "right" one. Other suggestions are welcome.
Thanks!
use single Imageview for your concept it is my suggestion If you feel free use this else use your concept else go some thirdparty, where you need for modify the transparent, add the one Transparent UIView above the ImageView . set the frame as of Transparent UIView for Show as (0, 0, ImageView.frame.size.width/2,ImageView.frame.size.height) , for Hide (ImageView.frame.origin.X - 40, 0, ImageView.frame.size.width/2,ImageView.frame.size.height)
for example
To Show
TransparentView.hidden = NO;
TransparentView.alpha = 0.1;
[UIView animateWithDuration:0.25 animations:^{
TransparentView.frame = CGRectMake(0,
0,
ImageView.frame.size.width/2,
ImageView.frame.size.height);
TransparentView.alpha = 1.0f;
} completion:^(BOOL finished) {
// do some
}];
To hide
[UIView animateWithDuration:0.25 animations:^{
TransparentView.frame = CGRectMake(0 - self.view.frame.size.width,
0,
ImageView.frame.size.width/2,
ImageView.frame.size.height);
[TransparentView setAlpha:0.1f];
} completion:^(BOOL finished) {
TransparentView.hidden = YES;
}];
Much like other apps, my app has a "welcome" page controller with a quick overview of the features. During this overview, I draw a UITabBar and have a circle show where the relevant feature is seen below:
I draw the circle using the following code that is executed every time a page is drawn:
double circleSize = 75;
[circleView removeFromSuperview];
circleView = [[UIView alloc] initWithFrame:CGRectMake(circleX,
circleY,
circleSize,
circleSize)];
circleView.layer.cornerRadius = (circleSize / 2);
circleView.layer.borderColor = [UIColor VancityTransitBlue].CGColor;
circleView.layer.borderWidth = 2;
I wish to have this circle appear to "breath" (grow slowly then shrink back to its original size). I use the exact code from my answer to this question:
[UIView animateWithDuration:1
delay:0
options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat
animations:^{
circleView.transform = CGAffineTransformMakeScale(1.5, 1.5);
}
completion:nil];
This circle is shared across three pages of the page controller and draws just fine. The animation works just fine on the first page, periodically works on the second page, and never works on the third page.
How can I have the animation play on every page for every circle view?
Here is a solution that works across all tabs. The animation can be moved around while in progress. You may want to use a better mechanism to manage the animation so that it can be cancelled efficiently. The code below is implemented in the Tab Controller. Ensure -showOverTabBarItem: and -hideCircleView are executed on main thread. It has been built, linked, ran and tested.
Show
-(void)showOverTabBarItem:(CGFloat)x {
[self hideCircleView];
self.circleView.frame =({
CGRect frame = self.circleView.frame;
frame.origin.x = x;
frame;
});
[self.view addSubview:self.circleView];
[UIView animateWithDuration:1
delay:0
options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat
animations:^{
self.circleView.transform = CGAffineTransformMakeScale(1.5, 1.5);
}
completion:nil];
}
Hide
-(void)hideCircleView
{
[self.circleView removeFromSuperview];
}
Initialize
Such as in viewDidLoad.
double circleSize = 75;
CGFloat circleY = self.view.bounds.size.height-(circleSize/2);
self.circleView = [[UIView alloc] initWithFrame:CGRectMake(0,
circleY,
circleSize,
circleSize)];
self.circleView.layer.cornerRadius = (circleSize / 2);
self.circleView.layer.borderColor = [UIColor blueColor].CGColor;
self.circleView.layer.borderWidth = 2;
Invoke
Pass the horizontal position to your animation: [self showOverTabBarItem: self.view.bounds.size.width/2];
Keep the view around
This is a critical step: when your -removeFromSuperView, you want to make sure that the object does not get recycled.
#interface TabController ()
#property (nonatomic, retain) UIView * circleView;
#end
Why have you alloc the circle every time a page drawn?
You can remove these lines (just need these for the first init):
if (circleView == nil) {
circleView = [[UIView alloc] initWithFrame:CGRectMake(circleX,
circleY,
circleSize,
circleSize)];
circleView.layer.cornerRadius = (circleSize / 2);
circleView.layer.borderColor = [UIColor VancityTransitBlue].CGColor;
circleView.layer.borderWidth = 2;
}
For add to another page: remove from current page
[circleView removeFromSuperview];
[circleView.layer removeAllAnimations];
and then add it to another page:
[self.view addSubView:circleView];
[UIView animateWithDuration:1
delay:0
options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat
animations:^{
circleView.transform = CGAffineTransformMakeScale(1.5, 1.5);
}
completion:nil];
Does anyone know how to animate 3 parallel lines to a right arrow as happens in navigation menu bar to open up a side menu by applying CGAfflineRotation to 3 views .
I really need help on these as so that at-least I can get an idea to start it.
This is what it will be look like some how tried to draw it:-
_______
_______ \
_______ to ___________\
/
/
Any idea or suggestion will be helpful.
As you said, you should use CGAffineRotation. I'm giving simple example of what you want, everything should be ofc packed into proper methods, views should be with some basic autolayouts/layoutFrames etc. I'm just posting possible solution for rotation, quickly written in viewDidAppear, what should be changed.
Another option is to use eg firstView.layer.anchorPoint and set it to proper position.
#define degreesToRadians(x) (M_PI * x / 180.0)
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// let's create these 3 views as a lines
UIView *firstView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 50, 1)];
[firstView setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:firstView];
UIView *secondView = [[UIView alloc] initWithFrame:CGRectMake(50, 53, 50, 1)];
[secondView setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:secondView];
UIView *thirdView = [[UIView alloc] initWithFrame:CGRectMake(50, 56, 50, 1)];
[thirdView setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:thirdView];
// now we can perform rotation, mind the degree and offsets in transform.
[UIView animateWithDuration:1 animations:^{
CGAffineTransform transform = CGAffineTransformMakeTranslation(24, 1);
transform = CGAffineTransformRotate(transform, degreesToRadians(45));
transform = CGAffineTransformTranslate(transform, -24, 1);
firstView.transform = transform;
transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(24, -1);
transform = CGAffineTransformRotate(transform, degreesToRadians(-45));
transform = CGAffineTransformTranslate(transform, -24, -1);
thirdView.transform = transform;
} completion:^(BOOL finished) {}];
}
It is easier to do such animation with CALayer Animation instead of UIView Animation. You need to add three sub layers: top_line, middle_line, and bottom_line. Then draw the line on each layer and the right position (Hint: use CAShapeLayer for drawing lines). At last just rotate the top_line and bottom_line layer with a proper angle, you probably need to change the anchor point and layer's position as well. It is quite tricky at the last step, maybe just do some trials with different angle and anchor point values until you find the most proper ones.
When you successfully did such animation, try to do the reverse animation. Then create a Custom UIButton with these two animations embedded in. Congratulations! You have a hamburger button with cool animations which could be reused anywhere!
I am working on a quiz application where , every question have different Time period .
I wants to implement an animation where circumference of circle should be decrease as time is over & at the end of time it will be lost . as shown in image here
Same behaviour I want in every question .
Please help me ,if nay one have any confusion please let me know.
Have a look at this control or this one
It is also worth finding out about Cocoapods, although the first control doesn't have a Pod yet.
To use these controls you can just add a UIView in IB and then set the custom class of the UIView to the control (such as kkprogresstimer).
testView is a UIView class which draws the Circle. Initializing this in a UIViewController class.
self.testView = [[TestView alloc] initWithFrame:CGRectMake(0.0, 0.0, 500.0, 700.0)];
self.testView.backgroundColor = [UIColor blueColor];
[self.view addSubview:self.testView];
timeLabel is the label which shows the remaining time.
self.timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(195.0, 195.0, 20.0, 12.0)];
[self.timeLabel setText:#"10"];
self.timeLabel.textColor = [UIColor redColor];
[self.view addSubview:self.timeLabel];
aTimer is a NSTimer variable which calls the myAnimate method every 2 seconds.
NSTimer *aTimer = [[NSTimer alloc] init];
aTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(myAnimate) userInfo:nil repeats:YES];
myAnimate method reduces the circumference of the circle and also the value of the timeLabel.
- (void)myAnimate {
[UIView animateWithDuration:5.0 animations:^{
if (self.testView.aFloat >= 36) {
int a = [self.timeLabel.text intValue];
self.timeLabel.text = [NSString stringWithFormat:#"%d", a -1];
self.testView.aFloat = self.testView.aFloat - 36;
[self.testView setNeedsDisplay];
}
} completion:nil];
}
UITestView draws the circle.
UITestView.h
#interface TestView : UIView
#property (nonatomic) CGFloat aFloat;
- (void)myAnimate;
#end
UITestView.m
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextAddArc(context, 200.0, 200.0, 75.0, 0, [self DegreesToRadians:_aFloat], 0);
CGContextStrokePath(context);
}
- (CGFloat)DegreesToRadians:(CGFloat)degrees {
return degrees * M_PI / 180;
}
Hope, this was of some assistance.