Is it possible to have a UIIView with a textured background image and an opacity gradient? i.e., the bg image should fade in from left to right against the background container view.
thanks
Save your background image with an alpha channel (i.e. PNG) and do the fade in whatever graphics app you use.
Then, put it as the first child of your UIView as a UIImageView
- (void)viewDidLoad {
[super viewDidLoad];
image1=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"Default.png"]];
image1.frame=CGRectMake(0, 0, 320, 460);
image2=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"directoryPage.png"]];
image2.frame=CGRectMake(0, 0, 320, 480);
[self.navigationController setNavigationBarHidden:YES];
}
- (void)fade
{
image2.alpha = 0;
[self.view addSubview:image2];
// The upper layer will transition from alpha 1 to 0s
[self.view addSubview:image1];
BSheepAppDelegate *appD=(BSheepAppDelegate *)[[UIApplication sharedApplication]delegate];
if(appD.flag==0){
timer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(fadeTimerEvent) userInfo:nil repeats:YES];
appD.flag=1;
}
else if (appD.flag==1) {
[self.view addSubview:image2];
image2.alpha=1;
}
}
// Rate of transition for alpha values
#define FADE_IN_RATE 1.0/100.0
#define FADE_OUT_RATE 2.0/200.0
- (void)fadeTimerEvent
{
if (image2.alpha >= 1)
{
// At this point, image2 is now visible
[timer invalidate];
timer = nil;
}
else
{
// Fade lower layer in (increase alpha)
image2.alpha += FADE_IN_RATE;
// Fade upper layer out (decrease alpha)
image1.alpha -= FADE_OUT_RATE;
}
}
use this code to set
Related
In my iPhone app i need to implement a different type of transition.
that was
next view open from the current view,
it stats like a dot, and the dot expands slowly like a circle with in the circle next view is to be displayed partially with in the part of the circle , finally the circle expands totally the next view appears completely.
I search lots of transitions like CATransitions, and some animations on cocoa controller, but i didn't find this type of transition, can any one help me please.
Well I think I can offer you a workaround. Instead of pushing to the next view like a dot . I suggest you add a simple dot animation in the ViewWillAppear of the view in which you have to get pushed. Now the push method would remain the same like
[self.navigationController pushViewController:NewView animated:YES];
But in the ViewWillAppear the code would be such that the dot would expand to a circle and reveal the New View beneath it. Hope you understand the logic I am trying to explain here. Any issue do let me know .
in my case I did it that way:
set a CAShapeLayer instance as the layer's mask property of your custom view subclass
#interface MyCustomView ()
#property (nonatomic, strong) CircleShapeLayer *circleShapeLayer;
#end
#implementation MyCustomView
- (id) initWithFrame: (CGRect) frame {
self = [super initWithFrame: CGRectZero];
if (self) {
self.layer.mask = self.shapeLayer;
[self.layer.mask setValue: #(0) forKeyPath: #"transform.scale"];
}
return self;
}
zoom this mask layer to fullsize. code of your view:
- (void) zoom {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath: #"transform.scale"];
animation.fromValue = [self.layer.mask valueForKeyPath: #"transform.scale"];
animation.toValue = #(1);
animation.duration = 2.0;
animation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut];
animation.delegate = self;
// Important: change the actual layer property before installing the animation.
[self.layer.mask setValue: animation.toValue forKeyPath: animation.keyPath];
// Now install the explicit animation, overriding the implicit animation.
[self.layer.mask addAnimation: animation forKey: animation.keyPath];
return;
}
- (CAShapeLayer *) circleShapeLayer {
if (!_ circleShapeLayer) {
_circleShapeLayer = [SGMaskLayer layer];
_circleShapeLayer.delegate = _shapeLayer;
_circleShapeLayer.frame = self.bounds;
_circleShapeLayer.needsDisplayOnBoundsChange = YES;
}
return _circleShapeLayer;
}
#end
the code of the mask layer:
#interface CircleShapeLayer : CAShapeLayer
#end
#implementation CircleShapeLayer
- (void) drawLayer: (CALayer *) layer inContext: (CGContextRef) ctx {
UIGraphicsPushContext(ctx);
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect: self.bounds];
self.path = circlePath.CGPath;
UIGraphicsPopContext();
}
#end
from the documentation:
The layer’s alpha channel determines how much of the layer’s content
and background shows through. Fully or partially opaque pixels allow
the underlying content to show through but fully transparent pixels
block that content.
The default value of this property is nil nil. When configuring a
mask, remember to set the size and position of the mask layer to
ensure it is aligned properly with the layer it masks.
so I drew a circle with UIBezierPath to achieve the round mask. at the beginning I set the mask's scale factor to 0 so nothing of the view's layer is visible. then the scale factor is set to 1 (filling the layer's bounds) animated which gives a nice animation of a circle increasing it's radius from the center.
you might need one more animation shifting the center point of your view. both animations can be wrapped in a CAAnimationGroup.
Open in first view:
//Delegate method for annotation did select
- (void)tapOnAnnotation:(RMAnnotation *)annotation onMap:(RMMapView *)map;
{
//To get the touch point of the GMS marker to set them as circle transiton pos
CGPoint markerPoint = annotation.position;
x = markerPoint.x;
y = markerPoint.y;
circleSize = 10;
radiusChange = 0;
//Populate Same Values to next view to close
VenueScreen.x = x;
VenueScreen.y = y;
VenueScreen.view.hidden = YES;
timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(openVenueScreen) userInfo:nil repeats:YES];
VenueScreen.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:VenueScreen.view];
}
//Circular transition to open Next view
-(void)openVenueScreen
{
VenueScreen.view.hidden = NO;
VenueScreen.view.userInteractionEnabled = NO;
VenueScreen.view.alpha = 0.9;
self.view.userInteractionEnabled = NO;
int rChange = 0; // Its doing proper masking while changing this value
int radius = circleSize-rChange;
CAShapeLayer *circleShapeLayer = [CAShapeLayer layer];
// Make a circular shape
circleShapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x+radiusChange, y+radiusChange, 2.0*radius, 2.0*radius)
cornerRadius:radius].CGPath;
radiusChange = radiusChange-10;
// Configure the apperence of the circle
[[VenueScreen.view layer] setMask:circleShapeLayer];
//Start Transition
circleSize = circleSize+10;
if (circleSize > 480)
{
[[VenueScreen.view layer] setMask:nil];
[timer invalidate]; //Stop titmer
VenueScreen.view.userInteractionEnabled = YES;
self.view.userInteractionEnabled = YES;
VenueScreen.view.alpha = 1;
//Populate to next view to close
VenueScreen.radiusChange = radiusChange;
}
}
Close in Next View:
//Close button Action
-(IBAction)DismissVenueScreen:(id)sender;
{
timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(dismissVenueScreen) userInfo:nil repeats:YES];
NSLog(#"close button clciked");
}
//Circular trasition to Close window
-(void)dismissVenueScreen
{
int rChange = 0; // Its doing proper masking while changing this value
int radius = circleSize-rChange;
CAShapeLayer *circleShapeLayer = [CAShapeLayer layer];
// Make a circular shape
circleShapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x+radiusChange,y+radiusChange, 2.0*radius, 2.0*radius)
cornerRadius:radius].CGPath;
// Configure the apperence of the circle
[[self.view layer] setMask:circleShapeLayer];
self.view.layer.masksToBounds = YES;
radiusChange = radiusChange+10;
circleSize = circleSize-10;
if (circleSize <= 0)
{
[timer invalidate]; //Stop titmer
[[self.view layer] setMask:nil];
[self.view removeFromSuperview];
circleSize = 480;
}
}
I've made a program that generates an image at a random x-coordinate at the top of the screen. The image then falls down to the bottom. However, I want to keep generating new images (of the same image) every few seconds so that it's as though these duplicates of the same image are continually "raining" from the top.
How can I make all of this code repeat every 0.5 seconds?
#implementation ViewController {
UIImageView *_myImage;
}
- (void)viewDidLoad
{
srand(time(NULL));e
int random_x_coordinate = rand() % 286;
CGRect myImageRect = CGRectMake(random_x_coordinate, 0.0f, 40.0f, 40.0f);
UIImageView *myImage = [[UIImageView alloc] initWithFrame:myImageRect];
[myImage setImage:[UIImage imageNamed:#"flake.png"]];
myImage.opaque = YES;
[self.view addSubview:myImage];
_myImage = myImage;
//FALLING BIRDS TIMER
moveObjectTimer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:#selector(moveObject) userInfo:nil repeats:YES];
}
//FALLING BIRDS MOVER
-(void) moveObject { // + means down and the number next to it is how many pixels y moves down per each tick of the TIMER above
_myImage.center = CGPointMake(_myImage.center.x, _myImage.center.y +1);
}
Just put animation cycle inside the method you call on timer, something like
- (void)viewDidLoad
{
[super viewDidLoad];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(animate)
userInfo:nil repeats:YES];
[timer fire];
}
- (void)animate
{
CGFloat hue = ( arc4random() % 256 / 256.0 ); // 0.0 to 1.0
CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from white
CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from black
UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view.backgroundColor = color;
[self.view addSubview:view];
[UIView animateWithDuration:1.0 animations:^{
view.frame = CGRectMake(0, 200, 50, 50);
}];
}
Will give you squares dropping down from top, continuously. Just remember to clean up unused views regularly to avoid memory issues.
I want to smothly animate an image in an UIImageView to turn into the next one within one second like UIModalTransitionStyleCrossDissolve does.
Currently, I've got an UIImageView * called "imageView" and a function which is called "imageForState" which returns me a UIImage * for the correct image.
So what I want to do is to animate the image A smoothly into image B if there is one.
Currently, my function is like that:
- (UIImage *) imageForState{
NSLog(#"state: %d", [save state]);
switch ([save state]) {
case 0:
case 1:
return [UIImage imageNamed:#"Sakuya_Debug.PNG"];
case 2:
return [UIImage imageNamed:#"Sakuya_2_Debug.PNG"];
default:
return NULL;
//Never called
}
}
-(void) tap{
[imageView setAnimationImages:[NSArray arrayWithObjects:[imageView image], [self imageForState], nil]];
imageView.animationDuration = 2.0;
[imageView startAnimating];
save.state++;
}
My problem is, that 1.) the animation goes on forever (when I set imageView.animationRepeatCount to 1, I end up at the first image again) and b.) the animation is not smooth; just like I would have used "setImage";
What am I doing wrong?
I suggest doing it with two imageViews and an animation block. In the following example I assume two square images with a siza of 100px. If you add the two imageViews as subviews make sure that imageB is added after imageA so it covers it.
Init the imageViews:
UIImageView *imageA = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Sakuya_Debug.PNG"]];
UIImageView *imageB = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Sakuya_2_Debug.PNG"]];
// hide the second image
imageB.alpha = 0.0;
// put the image with the same size at same position
imageA.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
imageB.frame = imageA.frame;
Blend method:
- (void)crossDissolveImageAtoB
{
[UIView animateWithDuration:1.0
animations:^{
imageB.alpha = 1.0;
}
completion:^(BOOL finished){
// do something after the animation finished,
// maybe releasing imageA if it's not used anymore...
}];
}
In my application after the view load, an image should appear from left to right.
I am writing this code in in viewdidload or viewwillappear:
UIImage *image = [UIImage imageNamed:#"PG05(REV).jpg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
for (int i=-1024; i<=0; i++) {
NSLog(#"i: %d",i);
sleep(5);
imageView.frame = CGRectMake(i,0, 1024, 768);
NSLog(#"done");
[self.view addSubview:imageView];
}
[imageView release];
But problem is that, before loading view it executes the above code than loads the view, so that it seems that view loaded and a static image is there.
But my requirement is that first view load completely then image should display from left to right.
Please help me out.
First of all, you should not call the -(void)addSubview: inside your for loop. You just need to call it once.
Secondly, if you want to animate your imageView from left to right, UIView class provides great functionalities for this using blocks.
Your code should look like this :
UIImage *image = [UIImage imageNamed:#"PG05(REV).jpg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(-1024, 0, 1024, 768);
[self.view addSubview:imageView];
[imageView release]; //Your imageView is now retained by self.view
//Animation
[UIView animateWithDuration:2.0
animations:^(void) {
imageView.frame = CGRectMake(0, 0, 1024, 768);
}];
The animateWithDuration: method will handle the animation timer for you, just set the duration argument according to your needs.
You can use a function and call it using timer method.
timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(moveImage) userInfo:nil repeats:NO];
-(void)moveImage
{
//Your condition
}
This is a job for UIView animations.
Put your imageView down at -1024 left, then go:
[imageView animateWithDuration:5 animations:^{
[imageView.frame = CGRectMake(0,0, 1024, 768)];
}];
Ta-da! A five second animation of your image sliding to the right.
Check out the animation methods of UIView (of which UIImageView is a subclass):
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html
I know there is most probably something seriously wrong here because I only started on iOS yesterday but I can't seem to get this to update the screen properly, the count works fine and it's incrementing and checking the conditions correctly just that the screen doesn't get displayed, can anybody point me in the right direction please?
#implementation draw2D
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
[self myTimer];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
[self updateBackground];
}
NSTimer *timer = nil;
int count = 0;
- (void)myTimer
{
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(updateBackground) userInfo:nil repeats:NO];
if (count < 1) {
count++;
} else {
count = 0;
}
}
- (void)updateBackground:
{
if(count == 1)
{
UIImage *myImage = [UIImage imageNamed:#"bg.png"];
CGRect imageRect = CGRectMake(0, 0, 320, 480);
[myImage drawInRect:imageRect];
[myImage release];
// count++;
}
else
if (count == 0)
{
UIImage *myImage = [UIImage imageNamed:#"SCENE_002.png"];
CGRect imageRect = CGRectMake(0, 0, 320, 480);
[myImage drawInRect:imageRect];
[myImage release];
// count = 0;
}
[self myTimer];
}
#end
EDIT: It displays the first image, but never swaps to the second.
On second look, you have two things methods calling updateBackground, one is drawRect, which can be called any time you're updating the display, and on the timer fire. In the myTimer method, you're changing the count value, with the expectation the screen will refresh 0.5 seconds later.
I'm suspicious that the reason one image is never displayed is that it may be being drawn, but the call to drawInRect might fire drawRect, which could then blit the other image on top of the recently drawn image.
So, basically I'd remove the call to updateBackground from drawRect:
** ORIGINAL ANSWER:
[UIView drawRect] is only called when necessary. After the initial call, UIKit just caches the result internally and continues to redraw the cached copy to the display.
What you need to do is send a signal to the view that it needs to be refresh. You can do that by adding the line:
[self setNeedsDisplay];
In your updateBackground selector.
Also, why are you re-creating the timer after each time it fires, instead of changing the repeats parameter to YES?