Showing a subview temporary - iphone

What I am trying to achieve is showing a view during a couple of seconds without user intervention. Is the same effect as the ringer volume view that appears when pressing the volume controls on iphone:
I have a scroll view with an image, taping in the image, sound begin to play, another tap and it pauses. I would like to implement the above effect just to inform of the action (showing a play/pause images).
I hope that I have explained the problem perfectly.
Many thanks for your help.
Regards
Javi

Assume you have some class inherited from UIViewController. You can use the code below:
const int myViewTag = 10001;
const int myInterval = 1; // define the time you want your view to be visible
- (void)someAction {
//this could be your `IBAction` implementation
[self showMyView];
[NSTimer scheduledTimerWithTimeInterval:myInterval
target:self
selector:#selector(hideMyView)
userInfo:nil
repeats:NO];
}
- (void) showMyView {
//you can also use here a view that was declared as instance var
UIView *myView = [[[UIView alloc] initWithFrame:CGRectMake(100, 100, 120, 120)] autorelease];
myView.tag = myViewTag;
[self.view addSubview:myView];
}
- (void) hideMyView {
//this is a selector that called automatically after time interval finished
[[self.view viewWithTag:myViewTag] removeFromSuperview];
}
You can also add some animations here but this is another question :)

Related

simulate button pressed by single tap

as titled, would like to tap the screen, screen will be a bit dark translucent, while the finger leaves the screen, the screen turn back to normal, which is similar as UIButton does.
In this case, I know UIButton is much easier, but here is just a sample
my codes as the following:
- (IBAction)tapped:(UITapGestureRecognizer *)sender
{
UIView * tintView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.view addSubview:tintView];
switch (sender.state) {
case UIGestureRecognizerStateRecognized: {
[tintView setBackgroundColor:[UIColor colorWithRed:.25 green:.25 blue:.25 alpha:.5]];
NSLog(#"begin");
}
default: {
[tintView setBackgroundColor:[UIColor clearColor]];
NSLog(#"ended");
}
}
}
But, when tapping the screen, it won't be changed as above codes looks, although begin and ended are captured in the console.
If interchanging those codes between case and default like
switch (sender.state) {
case UIGestureRecognizerStateRecognized: {
[tintView setBackgroundColor:[UIColor clearColor]];
NSLog(#"begin");
}
default: {
[tintView setBackgroundColor:[UIColor colorWithRed:.25 green:.25 blue:.25 alpha:.5]];
NSLog(#"ended");
}
}
begin and ended could be shown in the console, but the screen will be darker and darker when tapping, never back to normal, clear color.
What's wrong with my codes? How to make it happen?
Thanks!
[self performSelector: withObject: afterDelay:] would be the usual way to accomplish something like this.
You'd setup your method which dismisses the darkened view separately, then reference it as the selector
[self performSelector:#selector(methodWhichDismissesDarkView:) withObject:nil afterDelay:0.2]
call this immediately after you darken the view, and 0.2 seconds later it will fire.
To really do it right though, make sure you can gracefully handle interruptions that happen during the delay by using this:
[NSObject cancelPreviousPerformRequestsWithTarget:self];
Which will cancel the pending action when the app no longer needs to handle it.
by following #ryancumley 's hint, below is updated codes.
#property (strong, nonatomic) UIView * tintView;
#synthesize tintView;
- (IBAction)tapped:(UITapGestureRecognizer *)sender
{
switch (sender.state) {
case UIGestureRecognizerStateRecognized: {
[self.tintView setBackgroundColor:[UIColor colorWithWhite:0.000 alpha:0.150]];
[self performSelector:#selector(setTintView:) withObject:nil afterDelay:.25];
NSLog(#"begin");
}
default: {
break;
NSLog(#"ended");
}
}
}
- (void)setTintView:(UIView *)tintView
{
[self.tintView setBackgroundColor:[UIColor colorWithRed:.25 green:.25 blue:.25 alpha:0]];
}
It works finally and looks like tapping a button. But, NSLog(#"ended") not triggered.
Why my original can't work?
Is this updated a correct approach or workaround?

Entering UIImagePickerController editing mode

I use a UIImagePickerController (photoPicker) to take pictures with the camera, and edit those picture (allowEditing = YES). The user can switch between Camera and Library with a button in photoPicker.view, but I want to remove this button when photoPicker is in editing mode.
In photoLibrarySourceType the picker uses a push to show editing mode, so it works with this method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (navigationController == photoPicker) {
NSLog(#"navigation ");
if ([navigationController.viewControllers indexOfObject:viewController] == 1)
{
// If second UIViewController, set your overlay.
NSLog(#"editing");
}
}
}
But in cameraSourceType, there is no navigation between camera and editing mode.
I came up with a little hack and it works for me. Am still a little new so please optimize at will as i couldn't find another way to do it.
The basic idea is to create an invisible button over the default camera button that performs a method that calls [uiimagepickercontroller takePicture]
here is my sample code
#implementation myViewController
{
UIImagePickerController *myImagePickerController;
UIButton * fakeCameraButton;
}
- (IBAction)showImagePicker:(id)sender{
// accessible camera validations implied
myImagePickerController = [[UIImagePickerController alloc]init];
myImagePickerController.sourceType=UIImagePickerControllerSourceTypeCamera;
myImagePickerController.showsCameraControls = YES;
myImagePickerController.delegate=self;
myImagePickerController.allowsEditing=YES;
CGFloat myViewHeight = 100; // you play around with the positions to get your desired frame size. This worked for me
UIView * myView = [[UIView alloc] initWithFrame:CGRectMake(0, myImagePickerController.view.frame.size.height - myViewheight, picker.view.frame.size.width, myViewheight)];
fakeCameraButton = [[UIButton alloc] initWithFrame:CGRectMake(myView.frame.size.width / 2 - 30, myView.frame.size.height/2-15, 60, 60)];// position it over the default camera button
[fakeCameraButton addTarget:self action:#selector(cameraButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[fakeCameraButton setTitle:#"" forState:UIControlStateNormal];
[myView addSubview:fakeCameraButton];
myImagePickerController.cameraOverlayView = myView;
[self presentViewController:myImagePickerController animated:YES completion:nil];
}
-(void)cameraButtonPressed{
// Make sure you check if camera is ready before this method.
[myImagePickerController takePicture];
// you are in editing/preview mode here if allowsEditing = YES
// you can remove all your custom overlay views by
myImagePickerController.cameraOverlay = nil
}
Like i said before just make sure you check if camera is ready. You can find answers here on stackoverflow on how to do it.
This code may suck so editing or alternative solutions are welcomed.
I need dev buddy to help me learn more about ios dev and ask questions. anyone interested?

NSTimer scheduledTimerWithTimeInterval and CoreAnimation [duplicate]

This question already has an answer here:
How to make marquee UILabel / UITextField / NSTextField
(1 answer)
Closed 9 years ago.
I am writing an app using a cocoa control that animates text,
https://www.cocoacontrols.com/controls/marqueelabel
It uses CoreText and QuartzCore.
It's a pretty great control, but i'm having trouble.
When instantiated the animated labels that I create using the control start to scroll immediately, however I'm finding that when I create an animated label using NSTimer it is not animating.
I am using
- (void)viewDidLoad
{
[super viewDidLoad];
....
[self.view addSubview:continuousLabel1];
[NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(updatePrice)
userInfo:nil repeats:YES];
}
to call a method that creates the animated label, when I call the method directly the labels create and animate, however when called using the above scheduled timer, new labels created only animate on the first call, not on the timers repeat calls to the method.
I have checked that my method is being call on the main thread/ main runloop, any ideas?
For clarity the work flow is:
Timer calls method --> Label 1 is created and starts to Animate.
5 Seconds Late...
Timer calls method again --> Label 2 is created However is does not begin to animate as expected.
EDIT:
- (void)updatePrice
{
MarqueeLabel *continuousLabel2 = [[MarqueeLabel alloc] initWithFrame:CGRectMake(10, 230, self.view.frame.size.width-20, 20) rate:100.0f andFadeLength:10.0f];
continuousLabel2.tag = 101;
continuousLabel2.marqueeType = MLContinuous;
continuousLabel2.animationCurve = UIViewAnimationOptionCurveLinear;
continuousLabel2.continuousMarqueeExtraBuffer = 50.0f;
continuousLabel2.numberOfLines = 1;
continuousLabel2.opaque = NO;
continuousLabel2.enabled = YES;
continuousLabel2.shadowOffset = CGSizeMake(0.0, -1.0);
continuousLabel2.textAlignment = NSTextAlignmentLeft;
continuousLabel2.textColor = [UIColor colorWithRed:0.234 green:0.234 blue:0.234 alpha:1.000];
continuousLabel2.backgroundColor = [UIColor clearColor];
continuousLabel2.font = [UIFont fontWithName:#"Helvetica-Bold" size:17.000];
continuousLabel2.text = #"This is another long label that doesn't scroll continuously with a custom space between labels! You can also tap it to pause and unpause it!";
[self.view addSubview:continuousLabel2];
if( [NSThread isMainThread])
{
NSLog(#"In Main Thread");
}
if ([NSRunLoop currentRunLoop] == [NSRunLoop mainRunLoop]) {
NSLog(#"In Main Loop");
}
}
The problem is that you are calling updatePrice every 5 seconds and in this method you are creating a new label, that that is stacking up, and notice that it is going darker and darker every 5 seconds.
And if you check the label is scrolling.
Solution:
If you want multiple instances of the label change its coordinates.
If you want single instance then compare check and create it just once.
You should read the section Important Animation Note from the README file.
My guess is that you will need to call controllerLabelsShouldAnimate: passing your current view controller to animate those labels added after the view controller has already been shown.

How do I release/delete a UIImageView class?

I'm new to iPhone programming, so I might not even be using the correct methods... anyway, I'm trying to make a game, and when I want to create an enemy I make a new UIImageView, like this:
enemyBird *asdf = [[enemyBird alloc] initWithFrame:CGRectMake(30, -20, 45, 30)];
[self.view addSubview:asdf];
When enemyBird initializes, an NSTimer is made so the enemyBird can fly around and do its own thing. Now, I want to get rid of the bird after it leaves the screen, in this code here:
if (self.center.y > 500)
{ //[self dealloc]; //doesn't work
//[self release]; //doesn't work
//[self removeFromSuperview]; //this makes it disappear, but the NSTimer is still running
}
But I don't know how to do that. Am I doing this properly? Or is there an entirely different way I should be doing this? Thanks in advance.
for game development better use cocos2d framework: It´s quite easy
As view retains all its subviews you can release your imageView right after you add it to controller's view:
enemyBird *asdf = [[enemyBird alloc] initWithFrame:CGRectMake(30, -20, 45, 30)];
[self.view addSubview:asdf];
[enemyBird release];
In your timer handler when bird leaves the screen remove it from superview, set reference to nil (to make sure you won't access deallocated instance) and invalidate timer so it won't fire again:
if (self.center.y > 500)
{
[enemyBird removeFromSuperview];
enemyBird = nil;
[timer invalidate];
}
You have to send removeFromSuperview to your image view, to put it out of the main view.
In the same time, you invalidate the timer, and you might be fine.
Also just after alloc/init the image view and add it to the main view, you should release it.

iPhone - Splash Screen with progress bar

I tried to create a SplashView which display the Default.png in the background and a UIProgressBar in front. But the splash screen is not being updated...
Inside my view controller I load first the splash view with a parameter how many steps my initialisation has and then I start a second thread via NSTimer and after each initialisation step I tell the SplashView to display the new progress value.
All looks good in theory, but when running this app the progress bar is not being updated (the method of the splash screen receives the values, I can see it in the logs). I also tried to add usleep(10000); in between to give the view updates a bit time and also instead of using the progress bar I drew directly on the view and called [self setNeedsDisplay]; but all didn't work :/
What am I doing wrong?
Thanks for your help!
Tom
Here is some code:
SPLASHSCREEN:
- (id)initWithFrame:(CGRect)frame withStepCount:(int)stepCount {
if (self = [super initWithFrame:frame]) {
// Initialization code
background = [[UIImageView alloc] initWithFrame: [self bounds]];
[background setImage: [UIImage imageWithContentsOfFile: [NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], #"Default.png"]]];
[self addSubview: background];
progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
[progressView setFrame:CGRectMake(60.0f, 222.0f, 200.0f, 20.0f)];
[progressView setProgress: 0.0f];
stepValue = 1.0f / (float)stepCount;
[self addSubview:progressView];
}
return self;
}
- (void)tick {
value += stepValue;
[progressView setProgress: value];
}
VIEWCONTROLLER:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
splashView = [[SplashView alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 320.0f, 480.0f) withStepCount:9];
[self setView: splashView];
NSTimer* delayTimer;
delayTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(finishInitialization) userInfo:nil repeats:NO];
}
return self;
}
- (void)finishInitialization {
// do some stuff, like allocation, opening a db, creating views, heavy stuff...
[splashView tick]; // this should update the progress bar...
// do some stuff, like allocation, opening a db, creating views, heavy stuff...
[splashView tick]; // this should update the progress bar...
// init done... set the right view and release the SplashView
}
As mentioned in another answer, for some finite amount of time, as your app is being launched, Default.png is displayed and you have no control over it. However, if in your AppDelegate, you create a new view that displays the same Default.png, you can create a seamless transition from the original Default.png to a view that you can add a progress bar to.
Now, presumably, you have created a view or similar and you are updating a progress bar every so often in order to give the user some feedback. The challenge here is that your view is only drawn when it gets called to do a drawRect. If, however, you go from AppDelegate to some initialization code to a viewcontroller's viewDidLoad, without the run loop getting a chance to figure out which views need to have drawRect called on, then your view will never display its status bar.
Therefore in order to accomplish what you want, you have to either make sure that drawRect gets called, such as by pushing off a lot of your initialization code into other threads or timer tasks, or you can force the drawing by calling drawRect yourself, after setting up contexts and such.
If you go with the background tasks, then make sure your initialization code is thread-safe.
Default.png is just a graphic, a static image shown while the application is launching. If you want to show further progress, you'll have to show everything at the applicationDidLaunch phase. Show your modal "Splash Screen" there first (Create a view controller, add its view as a subview of your main window) and dismiss it when you are done whatever additional loading you needed to do.
Also, you need to do update your progress bar in a seperate thread. Updating your GUI in the same thread where a lot of business is going on is (in my opinion, but I could be wrong) a bad idea.
The main thread is, as far as I know, the only one that can safely do GUI things, and its event loop (that is, the main application thread's) is the one that does the actual displaying after you've called -setNeedsDisplay. Spawn a new thread to do your loading, and update the progress on the main thread.