I have an app that should display a Youtube video and I'm using the Youtube ios helper API.
I have a subclass of UITabBarController that is used to present two youtube videos and the UITabBarController is inside a NavController and is pushed to from a UITableViewController. So the setup looks like
[NAVController] -- relationship --> [UITableViewController] -- push --> [UITabBarController] -- relationship --> [CustomViewController]
Now my CustomViewController.h looks like:
#import <UIKit/UIKit.h>
#import "YTPlayerView.h"
#interface CustomViewController : UIViewController<YTPlayerViewDelegate>
#property (strong, nonatomic) YTPlayerView *youtubeView;
#property (strong, nonatomic) NSString *videoID;
#end
and my .m file has
#import "CustomViewController.h"
#import "YTPlayerView.h"
#interface CustomViewController ()
#end
#implementation CustomViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.youtubeView.delegate = self;
self.view.backgroundColor = [UIColor blueColor];
self.youtubeView.frame = self.view.frame;
self.youtubeView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.youtubeView];
NSLog(#"Subviews %lu", (unsigned long)[self.view.subviews count]);
NSLog(#"Subviews %#", self.views.subviews);
BOOL b = [self.youtubeView loadWithVideoId:self.videoID];
NSLog(#"Loaded? %d", b);
[self.youtubeView playVideo];
}
What I end up with is a navigation bar at the top (as it should be), a tab bar at the bottom (as it should be), but with a blue background instead of a red background (and needless to say, no Youtube video loads). When I run this, it prints
Subviews 0
Subviews (
)
Loaded? 0
Clearly the addSubView: call is not working.
I've seen this post, but it didn't help.
(For those unfamiliar with the youtube ios helper library:
The youtube-ios-player-helper is an open source library that helps you embed a YouTube iframe player into an iOS application. The library creates a UIWebView and a bridge between your application’s Objective-C code and the YouTube player’s JavaScript code, thereby allowing the iOS application to control the YouTube player.
(Using iOS 7 and Xcode 5.1)
Since I don't see that you're using an IBOutlet, I believe you need to initialize the self.youtubeView:
self.youtubeView = [[YTPlayerView alloc]init];
self.youtubeView.delegate = self;
self.view.backgroundColor = [UIColor blueColor];
self.youtubeView.frame = self.view.frame;
self.youtubeView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.youtubeView];
The YouTube api isn't the problem here, UINavigation controller and UITabBarController just dont play nicely together. What you should do instead is make a view controller to handle the tabbar instead of a UITabBarController. This shows some insight on how to get it done.
Related
How to create an App using the Single View App template where the main window does not rotate but its rootViewController and everything else autorotates?
Apple does that on CIFunHouse but because the code is poorly explained in that matter, it is impossible to know how they did it. If you run the app you will see that the camera's preview window does not autorotate because the preview was added to the window but everything else does.
Apple uses this technique on their native iPad camera app.
So the answer is not clean but I can give you a fix. At some point the main application window must not have autorotated like it does now but at some point it started rotating according to the rootviewcontroller. At least this source code suggests that. I started developing at the end of iOS 6 and I think this source was written about that time. The best fix I could find for allowing everything to rotate in the example for me but having the preview to not rotate was to add a second window. Set the main window background to clear. Then add the previewLayer to the second window behind the main window. In code it would look like this.
The AppDelegate looked like this.
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
#interface FHAppDelegate : UIResponder <UIApplicationDelegate>
{
#private
CMMotionManager *_motionManager;
}
#property (strong, readonly, nonatomic) CMMotionManager *motionManager;
//future preview window
#property (strong, nonatomic) UIWindow *previewWindow;
#property (assign, readonly, nonatomic) UIDeviceOrientation realDeviceOrientation;
#end
Then in the viewDidLoad of the FHViewController instead of adding to the main window I did this and it added where they get the main window I add the previewView to that.
// we make our video preview view a subview of the window, and send it to the back; this makes FHViewController's view (and its UI elements) on top of the video preview, and also makes video preview unaffected by device rotation
//nothing special about this viewcontorller except it has
//-(BOOL)shouldAutorotate{
//return NO;
//}
TestViewController *test = [[TestViewController alloc]initWithNibName:#"TestViewController" bundle:nil];
FHAppDelegate *delegate = ((FHAppDelegate *)[UIApplication sharedApplication].delegate);
delegate.previewWindow = [[UIWindow alloc]initWithFrame:window.bounds];
UIWindow *previewWindow = delegate.previewWindow;
[window setBackgroundColor:[UIColor clearColor]];
previewWindow.rootViewController = test;
previewWindow.windowLevel = UIWindowLevelNormal - 1;
[previewWindow setBounds:delegate.window.bounds];
[previewWindow makeKeyAndVisible];
[previewWindow addSubview:_videoPreviewView];
[previewWindow sendSubviewToBack:_videoPreviewView];
Because the previewWindow has to have a rootviewcontroller and it determines the rotation you can see my testviewcontroller has autorotate of NO. Hope this helps. It is working for me on iOS 10.
Edit: The view in the example above does not rotate but the window animation on rotation is bad visually. It can be removed by overriding
willTransitionToSize
[UIView setAnimationsEnabled:NO];
and after completion
[UIView setAnimationsEnabled:YES];
See swift version on GitHub
For an iPad requires Full Screen must be check.
With using navigation controller you can create an Objective-C category like and use these in sub viewcontrollers
#import "UINavigationController+Orientation.h"
#implementation UINavigationController (Orientation)
- (NSUInteger)supportedInterfaceOrientations {
return [self.topViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate {
return YES;
}
#end
For Swift
extension UINavigationController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .portrait
}
open override var shouldAutorotate: Bool {
return true
}
}
I want to change the value of a label in my default view controller from a different class.
So I start a simple 'Single View Application' iOS project (Xcode5)
This automatically generates a ViewController for me (which I
understand is the root view controller)
I now add a label in my View and connect it to the ViewController (via IBOutlet mechanism)
I call this outlet 'gameStateLabel', so it looks like this in the ViewController.h file
#property (weak, nonatomic) IBOutlet UILabel *gameStateLabel;
Next, I have a completely separate class which has the logic for my code, and based on a condition in the logic I want to change the UIlabel.
So I try to do this from my other class:
Get an instance of the root view controller like this:
UIViewController * uvc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
I think I now have an instance of the rootviewcontroller in uvc and should be able to reach in and change gameStateLabel.
BUT: I CANNOT do this uvc.gameStateLabel simply does not show up as a property even though it is clearly declared as a property and I've added the #synthesize for it also.
Any help will be greatly appreciated - I've been going nuts over this.
(For ref. I'm used to doing something similar on the Mac side where I'd declare a label as a property of the AppDelegate, get the instance of the Appdelegate and simply refer to the label property and change its text]
Here's the ViewController. Note that gameStateLable is a property
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *gameStateLabel;
#end
#implementation ViewController
#synthesize gameStateLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
And here is my class cls1 (which inherits from NSObject)
#import "cls1.h"
#import "ViewController.h"
#implementation cls1
-(void) dummy{
UIViewController * uvc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
// uvc does NOT show gameStateLabel in intellisense, i.e. uvc.gameStateLabel does NOT work
}
Add #import "mainRootVC.h" in you CustomClass.m file
And create object of mainRootVC such like,
mainRootVC *obj = [[mainRootVC alloc] init];
// Now you can access your label by
obj.gameStateLabel...
Do like this...
YourViewController *rootController =[(YourViewController*)[(YourAppDelegate*)
[[UIApplication sharedApplication]delegate] window] rootViewController];
Try the following too:
ViewController *controller = (ViewController*)self.window.rootViewController;
It will return the initial view controller of the main storyboard.
For sending information from a viewController to other viewController you have:
Delegates:Definiton and examples
NSNotificationCenter: Apple Documentation
NSString *label = #"label text";
[[NSNotificationCenter defaultCenter] postNotificationName:NAVIGATETO object:label userInfo:nil];
You can found tons of examples about those two. I recommend you use one of those.
Hope this helps a bit.
OK. I found two issues.
I had copied the code over from my Mac project and modified it. Something seems to have gone wrong.
I retyped the entire function and it solved most of the problem
uvc should be of the type ViewController* - not UIViewController* as I was doing
Thanks everyone for your replies - much appreciated.
I have a UIViewController with a single button and an activity indicator.
In the class for this VC MainViewController.m I do the following in viewDidAppear:
- (void)viewDidLoad
{
[super viewDidLoad];
_actLoadLoc.color = [UIColor blueColor];
_startButton.enabled = NO;
[_startButton setTitle:#"Fetching Location" forState:UIControlStateDisabled];
}
Another method in my MainViewController.m is called readyToGo and is implemented as follows:
-(void) readyToGo
{
[NSThread sleepForTimeInterval:1.0f];
NSLog(#"Done sleeping");
_startButton.enabled = YES;
[_startButton setTitle:#"Start" forState:UIControlStateNormal];
_actLoadLoc.stopAnimating;
}
I have properties for both UIButton, UIActivityIndicatorView and a declaration of the readyToGo method in my MainViewController.h as follows:
#property (weak, nonatomic) IBOutlet UIButton *startButton;
#property (weak, nonatomic) IBOutlet UIActivityIndicatorView *actLoadLoc;
-(void) readyToGo;
The readyToGo method is called from another class abc.[h/m] which imports MainViewController.h. The call happens after one of the functions in abc.m completes filling an array with calculated data.
The call works since Done Sleeping shows in the output, however the startButton is not enabled, its test does not change and the actLoadLoc does not stop animating... Any idea what's wrong with my code/method?
Thanks in Advance!
You are calling the readyToGo on the wrong instance of the view controller. You have an instance which is displaying content on the screen and you are, in some way, creating a new one to call the method on. You need to get the existing one instead.
It's not ideal, but you should be able to get the controller with:
UINavigationController *n = (UINavigationController *)[UIApplication sharedApplication].keyWindow.rootViewController;
SDPPMainViewController *mvc = (SDPPMainViewController *)[n viewControllers][0];
(Will need to add some casts, and should probably break out to multiple lines)
I need something what looks like UIAlertView (same background transparent and not full screen), blocks other UI parts and has some custom content.
This custom content are: two check-boxes with labels and two buttons YES/NO at the bottom.
Sub-classing or customizing UIAlertView doesn't looks useful (see this answer) and it is dangerous (code can be rejected by Apple). I was thinking to create own custom UIView (possible with UIViewController), but I have no idea how to make it look and feel like UIAlertView. I mean I'd like to make it that it changes its appearance dependent on iOS version (iOS7).
update:
I can abandon os version dependency, it would be nice to have, but this is additional feature.
The main question is: is there a good way to make such view which will look and feel like UIAlertView without large amount of work? Customizing UIAlertView directly looks complicated and dangerous.
I created my own custom view to look like iOS UIAlertView 7. With that technique you can create a custom alert for both iOS 6 and iOS 7.
For that, I created a UIView in my xib file of my UIViewController :
I added some #property for this view :
// Custom iOS 7 Alert View
#property (nonatomic, weak) IBOutlet UIView *supportViewPopup; // My UIView
#property (nonatomic, weak) IBOutlet UIView *supportViewPopupBackground; // The grey view
#property (nonatomic, weak) IBOutlet UIView *supportViewPopupAction; // The white view with outlets
// Property for customize the UI of this alert (you can add other labels, buttons, tableview, etc.
#property (nonatomic, weak) IBOutlet UIButton *buttonOK;
#property (nonatomic, weak) IBOutlet UIButton *buttonCancel;
#property (nonatomic, weak) IBOutlet UILabel *labelDescription;
On my viewDidLoad :
- (void)viewDidLoad
{
[super viewDidLoad];
// Support View
self.supportViewPopupAction.layer.cornerRadius = 5.0f;
self.supportViewPopupAction.layer.masksToBounds = YES;
// Add Support View
[self.view addSubview:self.supportViewPopup];
// Center Support view
self.supportViewPopup.center = self.view.center;
// Alpha
self.supportViewPopup.alpha = 0.0f;
self.supportViewPopupBackground.alpha = 0.0f;
self.supportViewPopupAction.alpha = 0.0f;
}
Action to display Popup :
- (IBAction)displayPopup
{
// Support View
self.supportViewPopup.alpha = 1.0f;
self.supportViewPopupBackground.alpha = 0.5f;
// Animation
[UIView animateWithDuration:0.5f
animations:^{
self.supportViewPopupAction.alpha = 1.0f;
}];
}
Action to dismiss Popup :
- (IBAction)dismissModal
{
// Animation
[UIView animateWithDuration:0.5f
animations:^{
self.supportViewPopup.alpha = 0.0f;
self.supportViewPopupBackground.alpha = 0.0f;
self.supportViewPopupAction.alpha = 0.0f;
}];
}
So, with that you can configure your supportViewPopupAction like you want with buttons, table view, labels, collection view, etc...
I spent time to write this example of alert view. I hope this will help you !
Custom views can be passed to PXAlertView: https://github.com/alexanderjarvis/PXAlertView
Some components as UIButtons and UITextFields are going to look different depending on the version, so that's going to be fine, the problem I see is going to be in the view that contains then.
My suggestion is to detect the version where the app is running and then draw the alert view based on that, or just create a custom design that will fit both.
Creat view depending on the iOS versions!
NSString *version = [[UIDevice currentDevice] systemVersion];
int major = [version intValue];
if (major < 7)
//alert for the iOS 6
else
//alert for the iOS 7
I have create a UIVeiw class and a .xib. Within this .xib view I have its set to freeform with the dimensions of 400x200 and I have assigned it to my custom class with the same name:
Storyboard: blogView
Class Files: blogView.h & blogView.m
Within in the .xib i have added a label and a text field and linked them up to variable within the .h files etc (See code below).
blogCont.h
#import <UIKit/UIKit.h>
#interface blogCont : UIView
#property (strong, nonatomic) IBOutlet UILabel *lbBlogDate;
#property (strong, nonatomic) IBOutlet UITextView *txtBlogTitle;
#end
blogCont.m
#import "newsStoryView.h"
#implementation blogCont
#synthesize lbBlogDate;
#synthesize txtBlogTitle;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code place a log to see if it loads
NSLog(#"View Loaded");
}
return self;
}
#end
Now with in my main viewController.m file i have added the following code to init this view class, and I have added a background colour to see if this loads in.
viewController.m
UIView *blogCont = [[blogView alloc] init];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Now when I run this it all works well but as I do not see the purple background it looks as if the view does not load, but within the log I do see the NSLog message I have within this view NSLog(#"View Loaded"); so it seems it initiating this, but I cannot for the life of me get this to display?
Now if I change the code slightly to my main View Controller.m fiel to:
CGRect blogFrame;
blogFrame.origin.x = 20;
blogFrame.origin.y = 20;
blogFrame.size = CGRectMake(400,200);;
newsStoryView *blogCont = [[blogView alloc] blogFrame];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Then I get my view display a nice purple box, so this shows up when I set a frame size and the init the view with it 'blogFrame', bu tI thought that all this would be set within the .xib settings so no need to do this?
SO how can I create this external view class and assign it into another view and then manipulate its data, as accessing the label in the .xib using blogCont.lbBlogDate.text does not seem to work that is it probably does but as I cannot view it i cannot confirm it.
What am i doing wrong?
Thanks
Seems I nearly answered my own question then did:
I was not setting the size within my separate class view I was asking for a size when init it:
- (id)initWithFrame:(CGRect)frame
this is asking for a size
so I could do the following to the above:
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 478, 220)];
.... rest of code
Setting the size within the view load.
But I could also set it when I init it in my main view controller as below:
newsStoryView *blogCont = [[blogView alloc] initWithFrame:CGRectMake(0, 0, 400, 200)];
This is better as I can control the position of each one. Hope this helps anyone