- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIDevice *device = [UIDevice currentDevice];
device.batteryMonitoringEnabled = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryLevelDidChangeNotification" object:device];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryStateDidChangeNotification" object:device];
}
- (void)batteryChanged:(NSNotification *)notification
{
UIDevice *device = [UIDevice currentDevice];
NSLog(#"State: %i Charge: %f", device.batteryState, device.batteryLevel);
batteryLabel.text = [NSString stringWithFormat:#"State: %i Charge: %f", device.batteryState, device.batteryLevel];
}
The UILabel is never updated. The event for the power source is never fired.
Am I doing something wrong?
I plan on only supporting iOS 5.x and 6
If you get the notification center working, but the UILabel isn't updating, isn't it simply because the app is in background when the notification is received?
I would try the following:
See if the uilabel is correctly connected to the storyboard
Update the uilabel once the app is awakened from sleep
IBOutlet UILabel *currentBatteryStatusLabel;
I changed the above code into the following and everything started working.
__weak IBOutlet UILabel *currentBatteryStatusLabel;
I am not sure why it makes such a big difference
Related
I would like to refresh a UIWebView whenever my app comes to the foreground. All I really have in my ViewController.m is a method that checks for internet access (hasInternet) and viewDidLoad.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize webview;
-(BOOL)hasInternet{
Reachability *reach = [Reachability reachabilityWithHostName:#"www.google.com"];
NetworkStatus internetStats = [reach currentReachabilityStatus];
if (internetStats == NotReachable) {
UIAlertView *alertOne = [[UIAlertView alloc] initWithTitle:#"You're not connected to the internet." message:#"Please connect to the internet and restart the app." delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alertOne show];
}
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self hasInternet];
[webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://warm-chamber-7399.herokuapp.com/"]] ];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Any advice on how to enable this functionality? Does it go in AppDelegate or do I create another method within ViewController.m?
You should register a UIApplicationWillEnterForegroundNotification in your ViewController's viewDidLoad method and whenever app comes back from background you can do whatever you want to do in the method registered for notification. ViewController's viewWillAppear or viewDidAppear won't be called when app comes back from background to foreground.
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doYourStuff)
name:UIApplicationWillEnterForegroundNotification object:nil];
}
-(void)doYourStuff{
[webview reload];
}
Don't forget to unregister the notification you are registered for.
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Note if you register your viewController for UIApplicationDidBecomeActiveNotification then your method would be called everytime your app becomes active, It would not be appropriate to register for this notification.
Register for the UIApplicationDidBecomeActiveNotification or the UIApplicationWillEnterForegroundNotification.
The function of how the device know the changement of orientation is
-(void)viewWillLayoutSubviews and
-(void)viewDidLayoutSubviews
But, they are just in the controllers;
Now I want to know is there any functions like these to know the changement of orientation in the file AppDelegate.m
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated {
UINavigationBar *morenavbar = navigationController.navigationBar;
UINavigationItem *morenavitem = morenavbar.topItem;
//We don't need Edit button in More screen.
morenavitem.rightBarButtonItem = nil;
morenavitem.title = nil;
UIImage *backgroundImage = [UIImage imageNamed:#"nav.png"];
[morenavbar setBackgroundImage:backgroundImage
forBarMetrics:UIBarMetricsDefault];
UIDeviceOrientation currentDeviceOrientation =
[[UIDevice currentDevice] orientation];
UIInterfaceOrientation currentInterfaceOrientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (UIDeviceOrientationIsLandscape(currentDeviceOrientation)||
UIDeviceOrientationIsLandscape(currentInterfaceOrientation)){
UIImage *backgroundImageLandscape = [UIImage imageNamed:#"navbar_landscape.png"];
[morenavbar setBackgroundImage:backgroundImageLandscape forBarMetrics:UIBarMetricsDefault];
}
}
You can register for notifications when rotation occurs
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleDidChangeStatusBarOrientationNotification:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
Then implement the method that gets called when the message is sent
- (void)handleDidChangeStatusBarOrientationNotification:(NSNotification *)notification;
{
// Do something interesting
NSLog(#"The orientation is %#", [notification.userInfo objectForKey: UIApplicationStatusBarOrientationUserInfoKey]);
}
Alternatively check out the docs for UIApplicationDidChangeStatusBarOrientationNotification which will provide you with the
If you are talking about the interface orientation you could observe theUIApplicationDidChangeStatusBarOrientationNotification and if you want to be notified when the device orientation changed you can observe UIDeviceOrientationDidChangeNotification
I'm having a very strange problem. I want a video to appear in landscape mode, but I can't seem to make it work. Even if I can't make it always show Landscape, at least I want it to show ok, and I can't make that either!! Here is my code:
#import "SplashViewController.h"
#import "MainViewController.h"
#import "MediaPlayer/MediaPlayer.h"
#interface SplashViewController ()
#property (nonatomic, retain) NSTimer *timer;
#end
#implementation SplashViewController
#synthesize timer = _timer;
-(BOOL)shouldAutorotateToInterfaceOrientation:UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
- (id)init
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self = [self initWithNibName:#"SplashViewController_iPhone" bundle:nil];
} else {
self = [self initWithNibName:#"SplashViewController_iPad" bundle:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSString *url = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"intro.mp4"];
playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:[playerViewController moviePlayer]];
[playerViewController shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight];
[self.view addSubview:playerViewController.view];
//play movie
MPMoviePlayerController *player = [playerViewController moviePlayer];
player.scalingMode = MPMovieScalingModeAspectFill;
[player play];
}
- (void) movieFinishedCallback:(NSNotification*) aNotification {
MPMoviePlayerController *player = [aNotification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
[player stop];
[player.view removeFromSuperview];
[self loadMainView];
}
- (void)loadMainView
{
MainViewController *mainVC = [[MainViewController alloc] init];
[self.navigationController pushViewController:mainVC animated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
And here comes the weirdness...
If I start the app with my iPad physically in Landscape Mode, the video shows like this (please not that the bar at the top is shorter than the widht! :O)
If I then rotate the iPad to Portrait, it looks like this:
But then, if I start the app with my iPad physically in Portrait Mode, the video shows like this:
And if I then rotate the iPad to Landscape, it looks like this:
Which is GREAT! This final image is what I would like the video to always look like.
Any ideas what I might be doing wrong???
Thanks!
EDIT 1
Ok, with #Tark answer I was able to fix the player display issue. Now it's showing fine no matter how I start the app. Thanks for that!! What is missing now is the always landscape mode.
I tried with the following methods:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation==UIInterfaceOrientationLandscapeRight)
return YES;
return NO;
}
I also tried inserting the row
Initial interface orientation = Landscape (right home button)
In the Info.plist
What I'm getting is that if I start the app in Landscape mode, if I rotate the iPad to Portrait, it stays in Landscape. GREAT!
But if I start the app in Portrait mode, the video shows in Portrait mode. Once I rotate it to Landscape, I can't rotate it back to Portrait, which is good, but I don't want it to start in Portrait!
EDIT 2
Ok, now this is even more weird. If I try it on an iPhone, it works great. No matter if I start the app in Landscape or Portrait, the video is shown always in Landscape.
But if I try it on an iPad, the problem in EDIT 1 arises... :S
Any ideas?
Thanks!
Have you tried setting the frame of the MPMoviePlayerViewControllers view when you add it as a subview?
...
playerViewController.view.frame = self.view.bounds;
[self.view addSubview:playerViewController.view];
...
To make the app only run in landscape mode, you should make sure that you have only selected the orientations you want in the app plist. In Xcode 4 there is a handy Supported Interface Orientations section in the target settings, make sure you only select landscape here. If you still have the issue, you have to make sure that you are disabling autorotation on all visible controllers in the view stack.
shouldAutorotateToInterfaceOrientation is deprecated as of iOS 6, Have you tried using supportedInterfaceOrientations?
If you are trying to support iOS 5 & 6 then I believe you need to use both:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
I haven't tested this so take it for what it's worth.
I'm using a tabbarcontroller in which one of the views has an MPMoviePlayer. It works fine, except that if I change tab, the movie doesn't stop and keeps playing in the background. Then if I try to tab back to the movie tab, it crashes.
I think the only code I have to release the MPMoviePlayer is when it's finished playing, but I want it to be released when I change views instead. Then if I go back to the Movie tab, we start fresh.
In my .h file have set up as:
import < UIKit/UIKit.h>
import < MediaPlayer/MediaPlayer.h>
#interface SecondViewController : UIViewController {
MPMoviePlayerController *player;
}
#end
and in my .m file have:
- (void)viewDidLoad {
NSString *url = [[NSBundle mainBundle]
pathForResource:#"vid"
ofType:#"m4v"];
player = [[MPMoviePlayerController alloc]
initWithContentURL:[NSURL fileURLWithPath:url]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
//--called when the movie view and then add it to the View window--
player.view.frame = CGRectMake(10, 10, 300, 300);
[self.view addSubview:player.view];
//--play movie--
[player pause];
[super viewDidLoad];
}
//--called when the movie is done playing--
- (void) movieFinishedCallback:(NSNotification*) aNotification {
MPMoviePlayerController *moviePlayer = [aNotification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[moviePlayer.view removeFromSuperview];
[player release];
}
Any suggestions? Thank you :)
If you really want to release MPMoviePlayer at tab switch, then do it in viewWillDisappear or viewDidDisappear. Now it's left alive at background, as you described. When you come back to tab, you try to create it again.
Difficult to say what would be the exact reason for crash, there seems to be several possibilities. Next time write a "Why did this crash" question with a call stack.
Maybe you could think about just pause/resume, so you wouldn't need to reallocate new moviePlayer every time user changes tabs? Do alloc/release in viewDidLoad and viewDidUnload, but play/pause in viewWillAppear and viewWillDisappear.
Does anybody knows, can I get the current input language and/or keyboard layout in iPhone application? Can I also get a notification when input language was changed?
In iOS 4.2 and later, you can use the UITextInputMode class to determine the primary language currently being used for text input.
[UITextInputMode currentInputMode].primaryLanguage will give you an NSString representing the BCP 47 language code such as “es”, “en-US”, or “fr-CA”.
You can register for the UITextInputCurrentInputModeDidChangeNotification to be alerted when the current input mode changes.
(You might also be interested in the "Getting Your Apps Ready for China and other Hot New Markets" WWDC session, and Internationalization Programming Topics.)
You can ask current first responder (UITextField, UISearchBar, etc.) via UIResponder method textInputMode:
// assume you have instance variable pointing to search bar currently entering
UITextInputMode *inputMode = [self.searchBar textInputMode];
NSString *lang = inputMode.primaryLanguage;
You can add an observer to the default notification center:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(inputModeDidChange:)
name:#"UIKeyboardCurrentInputModeDidChangeNotification"
object:nil];
This method prints the currently selected input language (like "en_US" or "de_DE"):
- (void)inputModeDidChange:(NSNotification*)notification
{
id obj = [notification object];
if ([obj respondsToSelector:#selector(inputModeLastUsedPreference)]) {
id mode = [obj performSelector:#selector(inputModeLastUsedPreference)];
NSLog(#"mode: %#", mode);
}
}
BUT: All the above is not documented and you should not use it in shipping code!
From the Apple Reference Library - "Getting the Current Language and Locale":
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:#"AppleLanguages"];
NSString* preferredLang = [languages objectAtIndex:0];
In line with the top answers, the following is a generic solution to getting the keyboard language whenever it is changed. Register for the notification UITextInputCurrentInputModeDidChangeNotification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(inputModeDidChange:) name:UITextInputCurrentInputModeDidChangeNotification object:nil];
Then in inputModeDidChange
-(void)inputModeDidChange:(NSNotification *)notification {
UIView *firstResponder = [UIView currentFirstResponder];
UITextInputMode *currentInputMode = firstResponder.textInputMode;
NSString *keyboardLanguage = [currentInputMode primaryLanguage];
NSLog(#"%#", keyboardLanguage); // e.g. en-US
}
Where currentFirstResponder is from a category on UIView to get the first responder view, as suggested in this SO post:
// UIView+Additions.h
#import <UIKit/UIKit.h>
#interface UIView (Additions)
+ (id)currentFirstResponder;
#end
Implementation
// UIView+Additions.m
#import "UIView+Additions.h"
static __weak id currentFirstResponder;
#implementation UIView (Additions)
+ (id)currentFirstResponder {
currentFirstResponder = nil;
// This will invoke on first responder when target is nil
[[UIApplication sharedApplication] sendAction:#selector(findFirstResponder:)
to:nil
from:nil
forEvent:nil];
return currentFirstResponder;
}
- (void)findFirstResponder:(id)sender {
// First responder will set the static variable to itself
currentFirstResponder = self;
}
#end
The way I would do it is as follows:
Register your ViewController as a listener to UIApplicationDidBecomeActiveNotification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
In applicationDidBecomeActive handler, check the current language using [NSLocale preferredLanguages] and act upon it accordingly.
This approach gives you what you want and is totally shippable without having to use private API.