- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
}
are not working, and i dont hv any idea,why.
When i try debugging, and rotate the device, these method not called.
I just want to detect the orientation
if orientation = landscape
perform action a
else
perform action b
Many Thanks
I agree with Clafou, how you setup your app can mess with rotation.
Add this and see if it fires:
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
BOOL isPortraitOrientation;
if ((self.interfaceOrientation == UIDeviceOrientationPortrait) || (self.interfaceOrientation == UIDeviceOrientationPortraitUpsideDown)){
isPortraitOrientation = YES;
} else if((self.interfaceOrientation == UIDeviceOrientationLandscapeLeft) || (self.interfaceOrientation == UIDeviceOrientationLandscapeRight)){
isPortraitOrientation = NO;
}
}
I have a toggle in my app that's "download on WiFi only". However, that toggle is useless for iPod touch or WiFi-iPads.
Is there a way to know if the device has cellular data capabilities in code? Something that would work in the future would be great too (like if an iPod touch 5th gen with 3G comes out).
Hi you should be able to check if it has the pdp_ip0 interface
#import <ifaddrs.h>
- (bool) hasCellular {
struct ifaddrs * addrs;
const struct ifaddrs * cursor;
bool found = false;
if (getifaddrs(&addrs) == 0) {
cursor = addrs;
while (cursor != NULL) {
NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
if ([name isEqualToString:#"pdp_ip0"]) {
found = true;
break;
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return found;
}
This doesn't use any private APIs.
3G by itself seems tough to find. You can find out whether a device can make calls using [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"tel://"]]. You can check whether a device can get to the internet, period (and by which method that can currently happen) using Reachability code:
NetworkStatus currentStatus = [[Reachability reachabilityForInternetConnection]
currentReachabilityStatus];
if(currentStatus == kReachableViaWWAN) // 3G
else if(currentStatus == kReachableViaWifi) // ...wifi
else if(currentStatus == kNotReachable) // no connection currently possible
..but aside from that, I don't think you can check for the existence of a 3G modem in the device.***** If it can't make a call, and doesn't currently have cell data turned on and wifi turned off, you won't be able to find out if it's 3G-capable.
An alternative way (not forward-compatible though, so you probably don't want to do this) is to compare the device's model with an exhaustive list, knowing which ones have 3G modems in them, as shown here.
***** As per bentech's answer, if you want to go digging around with device names (this may stop working with no advance warning if Apple decide to change the 3g interface name), call getifaddrs and check for the pdp_ip0 interface.
Swift 3.0 (UIDevice+Extension) of #bentech's answer
Add this line to your BridgingHeader.h:
#import <ifaddrs.h>
Somewhere else:
extension UIDevice {
/// A Boolean value indicating whether the device has cellular data capabilities (true) or not (false).
var hasCellularCapabilites: Bool {
var addrs: UnsafeMutablePointer<ifaddrs>?
var cursor: UnsafeMutablePointer<ifaddrs>?
defer { freeifaddrs(addrs) }
guard getifaddrs(&addrs) == 0 else { return false }
cursor = addrs
while cursor != nil {
guard
let utf8String = cursor?.pointee.ifa_name,
let name = NSString(utf8String: utf8String),
name == "pdp_ip0"
else {
cursor = cursor?.pointee.ifa_next
continue
}
return true
}
return false
}
}
In iOS 6.1, I've been able to use Core Telephony to successfully check for the presence of cellular baseband capabilities. This works on all iPads I tested: Verizon with service activated and without, AT&T with service currently deactivated, SIM card in and out, and a Wi-Fi-only iPad.
The code I used looks like this:
CTTelephonyNetworkInfo* ctInfo = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier* carrier = ctInfo.subscriberCellularProvider;
self.hasWWANCapability = carrier != nil;
For all the iPads with cellular baseband hardware, carrier is not nil. For the Wi-Fi-only iPad, carrier is nil.
I'd think you should be able to use the CoreTelephony Framework.
It does call out that it is for carriers to use, so I am not sure if it is against TOS to access it.
Carriers can use this information to write applications that provide services only for their own subscribers
One way of doing it is to ask for the users location. When it is as accurate as possibLe, you will know if the device have GPS. All devices that have GPS will have 3G. And those that don't GPS won't have 3G.
Apple provided code here.
https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html
You should copy Reachability.h and Reachability.m to your project and import
Reachability.h to your class,then
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
while (networkStatus==NotReachable) {
NSLog(#"not reachable");
//no internet connection
return;
}
while (networkStatus==ReachableViaWWAN) {
NSLog(#" ReachableViaWWAN ");
}
while (networkStatus==ReachableViaWiFi) {
NSLog(#"ReachableViaWiFi");
}
Another way is to extend this: https://github.com/monospacecollective/UIDevice-Hardware/blob/master/UIDevice-Hardware.m with this:
-(bool) hasCellular:(NSString*)modelIdentifier {
if ([modelIdentifier hasPrefix:#"iPhone"]) return YES;
if ([modelIdentifier hasPrefix:#"iPod"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad1,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,2"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,3"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,4"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,5"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,6"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,7"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad3,2"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,3"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,4"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad3,5"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,6"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad4,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad4,2"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,5"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,6"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,7"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad4,4"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad4,5"]) return YES;
if ([modelIdentifier isEqualToString:#"i386"]) return NO;
if ([modelIdentifier isEqualToString:#"x86_64"]) return NO;
return YES;
}
(Clearly it could be edited down to remove either the NO or YES only depending on which way you want to err in case there is a new model...)
EDIT: The given answer works on the device, but beware it fails on the simulator.
When my iPad starts up, I show a loading label, centered in the middle of the screen. I set its autoresizingMask so it recenters on orientation change.
As the app starts up, the label's text changes, so I want to recenter the label based on its new length. However, the following piece of code doesn't center the label correctly:
- (void) setLabelText:(NSString*)text {
CGSize maximumLabelSize = CGSizeMake(500,20);
CGSize expectedLabelSize = [text sizeWithFont:loadingLabel.font
constrainedToSize:maximumLabelSize
lineBreakMode:loadingLabel.lineBreakMode];
loadingLabel.frame = CGRectMake(self.view.frame.size.width/2-expectedLabelSize.width/2,
loadingLabel.frame.origin.y,
expectedLabelSize.width,
loadingLabel.frame.size.height);
loadingLabel.text = text;
}
I also considered checking [[UIDevice currentDevice]orientation], and if the iPad is in landscape mode, then I'd use self.view.frame.size.height to set the xOrigin of the label.
However, if the device is face up or face down, (and not landscape or portrait) then this method fails. I also have a lastOrientation variable in my appDelegate, which remembers if the app is in landscape or portrait, even when face up or face down, based on the device's last known orientation. However, at start-up, this variable isn't necessarily set.
Is there some simple solution I am missing here, so I can resize and center my label?
EDIT: I tried checking UIStatusBarOrientation based on the advice posted, but it doesn't work:
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft
|| [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
NSLog(#"landscape");
width = self.view.frame.size.height;
} else {
NSLog(#"portrait");
}
This always logs portrait, at least on start-up, on the simulator.
Check [[UIApplication sharedApplication] statusBarOrientation]
I found a trick to solve the FaceUp orientation issue!!!
Delay the orientation check till AFTER the app has started running, then set variables, view sizes, etc.!!!
//CODE
- (void)viewDidLoad {
[super viewDidLoad];
//DELAY
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(delayedCheck)
userInfo:nil
repeats:NO];
}
-(void)delayedCheck{
//DETERMINE ORIENTATION
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait ){
FACING = #"PU";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown ){
FACING = #"PD";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft ){
FACING = #"LL";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight ){
FACING = #"LR";
}
//DETERMINE ORIENTATION
//START
[self setStuff];
//START
}
-(void)setStuff{
if( FACING == #"PU" ){
//logic for Portrait
}
else
if( FACING == #"PD" ){
//logic for PortraitUpsideDown
}
else{
if( FACING == #"LL"){
//logic for LandscapeLeft
}
else
if( FACING == #"LR" ){
//logic for LandscapeRight
}
}
//CODE
You can addSubviews, position elements, etc. in the 'setStuff' function ... anything that would initially depend on the orientation!!!
:D
-Chris Allinson
I am trying hard to emulate the basic functionality of the built in camera app. Thus far I have become stuck on the 'tap to focus' feature.
I have a UIView from which I am collecting UITouch events when a single finger is tapped on the UIView. This following method is called but the camera focus & the exposure are unchanged.
-(void)handleFocus:(UITouch*)touch
{
if( [camera lockForConfiguration:nil] )
{
CGPoint location = [touch locationInView:cameraView];
if( [camera isFocusPointOfInterestSupported] )
camera.focusPointOfInterest = location;
if( [camera isExposurePointOfInterestSupported] )
camera.exposurePointOfInterest = location;
[camera unlockForConfiguration];
[cameraView animFocus:location];
}
}
'camera' is my AVCaptureDevice & it is non-nil. Can someone perhaps tell me where I am going wrong?
Clues & boos all welcome.
M.
This snippet might help you...There is a CamDemo provided by apple floating around which allows you to focus, change exposure while tapping, set flash, swap cameras and more, it emulates the camera app pretty well, not sure if youll be able to find it since it was part of wwdc, but if u leave some email address in the comments i can email you the sample code...
- (void) focusAtPoint:(CGPoint)point
{
AVCaptureDevice *device = [[self videoInput] device];
if ([device isFocusPointOfInterestSupported] && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
NSError *error;
if ([device lockForConfiguration:&error]) {
[device setFocusPointOfInterest:point];
[device setFocusMode:AVCaptureFocusModeAutoFocus];
[device unlockForConfiguration];
} else {
id delegate = [self delegate];
if ([delegate respondsToSelector:#selector(acquiringDeviceLockFailedWithError:)]) {
[delegate acquiringDeviceLockFailedWithError:error];
}
}
}
}
I'm writing an app that will be playing videos alot using the MPMoviePlayerController on the iPad. The problem is the app was working fine and playing the videos when I stopped working about 15 hours ago but now the videos do not play. The MPMoviePlayerController will show the first frame from the video, and in full screen view I can scrub through the movie fine but when I hit play it just pauses right away. I have the code below, when debugging i noticed that when I call play it sends an MPMoviePlayerPlaybackStateDidChangeNotification with the playbackState being MPMoviePlaybackStatePlaying and then right away it sends another MPMoviePlayerPlaybackStateDidChangeNotification notification with playbackState being MPMoviePlaybackStatePaused. Not sure if that helps but please let me know if you see anything wrong in my code or have an ideas, thanks.
- (void)handleNotification:(NSNotification *)notification {
if ([[notification name] isEqualToString:MPMoviePlayerPlaybackStateDidChangeNotification]) {
if (_videoPlayer.playbackState == MPMoviePlaybackStatePlaying) {
_playButtonLarge.hidden = YES;
_scrubber.maximumValue = _videoPlayer.duration;
[_playPauseButton setBackgroundImage:[UIImage imageNamed:#"video_controls_pause.png"] forState:UIControlStateNormal];
if (_updateScrubberTimer == nil) {
_updateScrubberTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateScrubber) userInfo:nil repeats:YES];
}
} else if (_videoPlayer.playbackState == MPMoviePlaybackStatePaused || _videoPlayer.playbackState == MPMoviePlaybackStateStopped) {
[_playPauseButton setBackgroundImage:[UIImage imageNamed:#"video_controls_play.png"] forState:UIControlStateNormal];
_playButtonLarge.hidden = NO;
if (_updateScrubberTimer != nil) {
[_updateScrubberTimer invalidate];
_updateScrubberTimer = nil;
}
if (_videoPlayer.playbackState == MPMoviePlaybackStateStopped) {
_scrubber.value = 0.0f;
_timePlayedLabel.text = #"0:00";
_timeRemainingLabel.text = #"-0:00";
_videoPlayerBG.hidden = NO;
}
}
} else if ([[notification name] isEqualToString:MPMoviePlayerPlaybackDidFinishNotification]) {
NSNumber *reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
if ([reason intValue] == MPMovieFinishReasonPlaybackEnded) {
_videoPlayerBG.hidden = NO;
}
_scrubber.value = _scrubber.maximumValue;
}
}
- (void)playPause {
if ([_videos count] > 0) {
if (_videoPlayer.playbackState == MPMoviePlaybackStatePaused || _videoPlayer.playbackState == MPMoviePlaybackStateStopped) {
_playButtonLarge.hidden = YES;
_videoPlayerBG.hidden = YES;
if ([_videoPlayer contentURL] == nil) {
Video *video = [_videos objectAtIndex:0];
[_videoPlayer setContentURL:video.videoURL];
}
if (![_videoPlayer isPreparedToPlay]) {
[_videoPlayer prepareToPlay];
}
[_videoPlayer play];
} else if (_videoPlayer.playbackState == MPMoviePlaybackStatePlaying) {
_playButtonLarge.hidden = NO;
[_videoPlayer pause];
}
}
}
I think I figured it out, I put the following code before every call to play
if (![_videoPlayer isPreparedToPlay]) {
[_videoPlayer prepareToPlay];
}
works now, if anyone else has any input let me know