I'm adding a subview the following way"
SettingsViewController *SVC = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.parentViewController addChildViewController:SVC];
[self.view addSubview:SVC.view];
My subview is 300 x 360 and is centered on the screen. The problem occurs when I attempt to remove it (Getting released).
When I press the close button in this new view, I get exc bad access. What's the correct way to add my view? I have a SettingsViewController.xib linked up to a .h and .m file.
Here's what my close button in my settings view looks like:
-(IBAction)close:(id)sender {
[self.view removeFromSuperview];
[self removeFromParentViewController];
}
But even when I comment out everything inside, just triggering the button crashes the app.
This is what my .h file looks like:
#import <UIKit/UIKit.h>
#interface SettingsViewController : UIViewController
#property (nonatomic, strong) IBOutlet UIView *alertView;
#property (nonatomic, strong) IBOutlet UIButton *closeButton;
#property (nonatomic, strong) IBOutlet UILabel *musicLabel;
#property (nonatomic, strong) IBOutlet UILabel *soundFXLabel;
#property (nonatomic, strong) IBOutlet UILabel *vibrateLabel;
- (IBAction)close:(id)sender;
#end
and my implementation file:
#import "SettingsViewController.h"
#interface SettingsViewController ()
#end
#implementation SettingsViewController
#synthesize alertView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.alpha = 0;
self.alertView.layer.cornerRadius = 10.0f;
self.alertView.layer.borderColor = [UIColor whiteColor].CGColor;
self.alertView.layer.borderWidth = 4.0f;
self.closeButton.layer.cornerRadius = 5.0f;
self.closeButton.titleLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:20];
self.musicLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
self.soundFXLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
self.vibrateLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.view.alpha = 1;
}
completion:^(BOOL finished){
//Display Players View
}];
}
- (IBAction)close:(id)sender {
//[self.view removeFromSuperview];
//[self removeFromParentViewController];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
And last but not least, here's a snapshot of my storyboard / xib order:
create a property for your SettingsViewController where you add & assign it where you create it.
// in .h file or private category on top
#property (nonatomic, strong) SettingsViewController *settingsController;
// your usual code + assigning controller
SettingsViewController *SVC = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.parentViewController addChildViewController:SVC];
[self.view addSubview:SVC.view];
self.settingsController = SVC;
Side Note : the reason for this behavior is after the .view property of the ViewController is added to your view, the controller gets deallocated (only the .view is alive now). So when you try to hit the butons on view there is no SettingsViewController to callback those events, hence crash. When you create the property & assign it, the controller lives.
Related
When using JSQMessagesViewController as detailView in UISplitViewController, KeyBoardToolBar needs to appear in DetailViewController only
late answer...
if u want to reduce the inputToolbar you need to create a subclass of JSQMessagesToolbarContentView and provide your own view for the tool bar's content view.
below i am giving the sample example, create a subcalss of JSQMessagesToolbarContentView name it as JSQMessagesToolbarContentView_custom in the subcalss add below code,
#import "JSQMessagesToolbarContentView.h"
#interface JSQMessagesToolbarContentView_custom : JSQMessagesToolbarContentView
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *holderViewLeadingConstraint;
#end
and in JSQMessagesToolbarContentView_custom.m file,
#import "UIView+JSQMessages.h"
#import "JSQMessagesToolbarContentView_custom.h"
#implementation JSQMessagesToolbarContentView_custom
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass([JSQMessagesToolbarContentView_custom class])
bundle:[NSBundle bundleForClass:[JSQMessagesToolbarContentView_custom class]]];
}
#pragma mark - Initialization
- (void)awakeFromNib
{
[super awakeFromNib];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.backgroundColor = [UIColor clearColor];
}
//below method will place the contentview to desired position
- (void)layoutSubviews
{
[super layoutSubviews];
self.holderViewLeadingConstraint.constant = 320;
}
#pragma mark - Setters
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
[super setBackgroundColor:backgroundColor];
self.leftBarButtonContainerView.backgroundColor = backgroundColor;
self.rightBarButtonContainerView.backgroundColor = backgroundColor;
}
- (void)setLeftBarButtonItem:(UIButton *)leftBarButtonItem
{
[super setLeftBarButtonItem:leftBarButtonItem];
}
- (void)setLeftBarButtonItemWidth:(CGFloat)leftBarButtonItemWidth
{
// self.leftBarButtonContainerViewWidthConstraint.constant = leftBarButtonItemWidth;
[self setNeedsUpdateConstraints];
}
- (void)setRightBarButtonItem:(UIButton *)rightBarButtonItem
{
[super setRightBarButtonItem:rightBarButtonItem];
}
- (void)setRightBarButtonItemWidth:(CGFloat)rightBarButtonItemWidth
{
// self.rightBarButtonContainerViewWidthConstraint.constant = rightBarButtonItemWidth;
[self setNeedsUpdateConstraints];
}
- (void)setRightContentPadding:(CGFloat)rightContentPadding
{
// self.rightHorizontalSpacingConstraint.constant = rightContentPadding;
[self setNeedsUpdateConstraints];
}
- (void)setLeftContentPadding:(CGFloat)leftContentPadding
{
// self.leftHorizontalSpacingConstraint.constant = leftContentPadding;
[self setNeedsUpdateConstraints];
}
#pragma mark - UIView overrides
- (void)setNeedsDisplay
{
[super setNeedsDisplay];
[self.textView setNeedsDisplay];
}
//return the custom view that we are going to create next
- (JSQMessagesToolbarContentView_custom *)loadToolbarContentView
{
NSArray *nibViews = [[NSBundle bundleForClass:[JSQMessagesToolbarContentView_custom class]] loadNibNamed:NSStringFromClass([JSQMessagesToolbarContentView_custom class]) owner:nil options:nil];
return nibViews.firstObject;
}
after this you need to create add new .xib file name it as JSQMessagesToolbarContentView_custom.xib this file contains our small content view for the inputToolbar and more importantly set the out let connections as doing the demo example and aslo set the view class name to JSQMessagesToolbarContentView_custom. hear i can only add image of the custom view.
now create a outlet for leading constraint to reduce the size of the content view as give below,
and add the constraints outlet's as given in the demo. so if u add some constrians without modifying the base class it will give error or runtime error so edit the base class also
now go to JSQMessagesToolbarContentView.h and add the blow properties form JSQMessagesToolbarContentView.m just cut and past and make it public.
#interface JSQMessagesToolbarContentView : UIView
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftBarButtonContainerViewWidthConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightBarButtonContainerViewWidthConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftHorizontalSpacingConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightHorizontalSpacingConstraint;
//...rest of the code
now in the JSQMessagesInputToolbar.m file, in order to make the tool bar transperent for half of the splitview,
- (void)awakeFromNib
{
[super awakeFromNib];
//...rest of the code
[self setBackgroundImage:[UIImage new]//imageNamed:#"topbar"]
forToolbarPosition:UIToolbarPositionAny
barMetrics:UIBarMetricsDefault];
[self setShadowImage:[UIImage new] forToolbarPosition:UIBarPositionAny];
[self setBackgroundColor:[UIColor clearColor]];
}
thats it now run the project, and change the leading constraints constant you see below output,
This is firstPopoverViewController.h code:
#import <UIKit/UIKit.h>
#interface firstPopoverViewController : UIViewController
#end
This is my firstPopoverViewController.m code:
#import "firstPopoverViewController.h"
#interface firstPopoverViewController ()
#end
#implementation firstPopoverViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.contentSizeForViewInPopover = CGSizeMake(300, 290);
// Header label
UILabel *h1 = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 85)];
h1.font = [UIFont fontWithName:#"myFont" size:22.0];
h1.textColor = [UIColor blackColor];
h1.textAlignment = NSTextAlignmentCenter;
h1.text = #"Heading";
h1.numberOfLines = 0;
h1.backgroundColor = [UIColor greenColor];
// Ok button BG View
UIView *buttonBG = [[UIView alloc] initWithFrame:CGRectMake(0, 300-75, 300, 75)];
buttonBG.backgroundColor = [UIColor greenColor];
// Ok button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(300/2-130/2, 290-35-15, 130, 35);
button.backgroundColor = [UIColor whiteColor];
[button setTitle:#"OK" forState:UIControlStateNormal];
[button addTarget:self action:#selector(closePop) forControlEvents:UIControlEventTouchUpInside];
button.adjustsImageWhenHighlighted=YES;
// Adding views
[self.view addSubview:h1];
[self.view addSubview:buttonBG];
[self.view addSubview:button];
}
-(void)closePop {
}
#end
Then there's ViewController.h:
#import <UIKit/UIKit.h>
#import "firstPopoverViewController.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) UIButton *popButton;
#property (strong, nonatomic) firstPopoverViewController *firstPopoverViewController;
#property (strong, nonatomic) UIPopoverController *firstPopover;
#end
And finally ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
/* ##### UIPopController stuff ##### */
UIImage *popButtonImage = [UIImage imageNamed:#"menu.png"];
_popButton = [UIButton buttonWithType:UIButtonTypeCustom];
_popButton.frame = CGRectMake(0, 0, 73, 66);
[_popButton addTarget:self action:#selector(openPop) forControlEvents:UIControlEventTouchUpInside];
_popButton.adjustsImageWhenHighlighted=NO;
[_popButton setImage:popButtonImage forState:UIControlStateNormal];
[self.view addSubview:_popButton];
}
-(void)openPop {
if (_firstPopoverViewController == nil) {
//Create the _firstPopoverViewController.
_firstPopoverViewController = [[firstPopoverViewController alloc] init];
}
if (_firstPopover == nil) {
_firstPopover = [[UIPopoverController alloc] initWithContentViewController:_firstPopoverViewController];
_firstPopover.popoverContentSize = CGSizeMake(300, 290);
[_firstPopover presentPopoverFromRect:CGRectMake(0,0, 73, 66) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
NSLog(#"show");
} else {
NSLog(#"dismiss");
[_firstPopover dismissPopoverAnimated:YES];
_firstPopover = nil;
}
}
#end
It's pretty basic code that displays a button and when I click this button it shows popover. I want to close this popover using button that's inside firstPopoverViewControll.m file. There's a closePop{} method, what should I put inside it to close this popover? Thanks.
By the way I'm beginner as you can see, I researched stackoverflow and there are some solutions with delegates, which seems to be working for others, but didn't work for me, could you please show me a solution on my code that I posted? Thank you people very much.
There may be a simpler method that I'm not aware of, but the following method should work:
Use NSNotificationCenter to post a notification back to the ViewController containing the UIPopOverController to tell it to dismiss the popover.
First, in ViewController.m viewDidLoad add:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(closePop:) name:#"ClosePopOver" object:nil];
Then add the following method to ViewController.m:
- (void)closePop:(NSNotification *)notification {
[_firstPopover dismissPopoverAnimated:YES];
}
Then in irstPopoverViewController.m:
- (void)closePop {
[[NSNotificationCenter defaultCenter] postNotificationName:#"ClosePopOver" object:nil];
}
That should do the trick.
A delegate is the way to go. I do admit though that I was confused by them at first, but they are quite simple to setup.
In your firstPopoverController.h put this:
#import <UIKit/UIKit.h>
#protocol FirstPopoverDelegate
- (void) closedPopover;
#end
#interface firstPopoverViewController : UIViewController
#property (nonatomic, assign) id< FirstPopoverDelegate > delegate;
#end
Then in your .m of you popover,
-(void)closePop
{
[self.delegate closedPopover];
}
In your main UIViewController's .h:
#import <UIKit/UIKit.h>
#import "firstPopoverViewController.h"
#interface ViewController : UIViewController <FirstPopoverDelegate>
#property (strong, nonatomic) UIButton *popButton;
#property (strong, nonatomic) firstPopoverViewController *firstPopoverViewController;
#property (strong, nonatomic) UIPopoverController *firstPopover;
#end
Then in the .m, first register to listen of the delegate by adding this to your openPop method:
this is important and easy to forget.. nothing will happen if it is not set
_firstPopoverViewController.delegate = self;
Finally, in your .m add the delegate method:
- (void)closedPopover
{
//you can also pass data back in this function, just modify its parameters here and when you define it in the .h of the popover
[_firstPopoverViewController dismissPopoverAnimated:YES];
}
I feel silly again but I don't manage to navigate back and forth between the subviews of my project. I can add as many subviews as I want as long as it just goes forward, but as soon as I want to come back to one of the views previously visited I have a problem...
here is my simplified code:
C4Workspace.h
#import "C4CanvasController.h"
#import "FirstView.h"
#interface C4WorkSpace : C4CanvasController{
FirstView *firstView;
}
#end
C4Workspace.m
#import "C4Workspace.h"
#implementation C4WorkSpace
-(void)setup {
firstView=[FirstView new];
firstView.canvas.frame=CGRectMake(0, 0, self.canvas.width, self.canvas.height);
firstView.canvas.userInteractionEnabled=YES;
[firstView setup];
firstView.mainCanvas=self.canvas;
[self.canvas addSubview:firstView.canvas];
}
#end
FirstView.h
#import "C4CanvasController.h"
#import "SecondView.h"
#interface FirstView : C4CanvasController{
C4Label *goToSecondView;
SecondView *secondView;
}
#property (readwrite, strong) C4Window *mainCanvas;
#end
FirstView.m
#import "FirstView.h"
#implementation FirstView
-(void)setup{
goToSecondView=[C4Label labelWithText:#"go to second View"];
goToSecondView.origin=CGPointMake(20, 50);
[self.canvas addLabel:goToSecondView];
[self listenFor:#"touchesBegan" fromObject:goToSecondView andRunMethod:#"goToSecondView"];
}
-(void)goToSecondView{
[goToSecondView removeFromSuperview];
C4Log(#"second view");
secondView=[SecondView new];
secondView.canvas.frame=CGRectMake(0, 0, self.canvas.width, self.canvas.height);
secondView.canvas.userInteractionEnabled=YES;
[secondView setup];
secondView.mainCanvas=self.canvas;
[self.canvas addSubview:secondView.canvas];
}
#end
SecondView.h
#import "C4CanvasController.h"
#import "FirstView.h"
#interface SecondView : C4CanvasController{
C4Label *goToFirstView;
FirstView *firstView;
}
#property (readwrite, strong) C4Window *mainCanvas;
#end
SecondView.m
#import "SecondView.h"
#implementation SecondView
-(void)setup{
goToFirstView=[C4Label labelWithText:#"go to First View"];
goToFirstView.origin=CGPointMake(20, 50);
[self.canvas addLabel:goToFirstView];
[self listenFor:#"touchesBegan" fromObject:goToFirstView andRunMethod:#"goToFirstView"];
}
-(void)goToFirstView{
[goToFirstView removeFromSuperview];
C4Log(#"first view");
firstview=[FirstView new];
firstview.canvas.frame=CGRectMake(0, 0, self.canvas.width, self.canvas.height);
firstView.canvas.userInteractionEnabled=YES;
[firstView setup];
firstView.mainCanvas=self.canvas;
[self.canvas addSubview:firstView.canvas];
}
#end
I think you're over complicating the procedure.
The "control" of which subview should be done by the containing view controller, so, if the two views are on the canvas then it should be the canvas that deals with the switching instead of the objects themselves.
Thing to help improve your approach:
Get rid of references to the canvas from the subclasses.
The views of your subclassed controllers all post touchesBegan notifications... Use these in the workspace i.e. [self listenFor:#"touchesBegan" fromObject:firstOrSecondView.canvas and runMethod:#"switch:"];
Switch by either changing the zPosition or hiding / revealing the appropriate view...
I reduced your implementations to the following:
FirstView.m
#import "FirstView.h"
#implementation FirstView
-(void)setup{
goToSecondView=[C4Label labelWithText:#"go to second View"];
goToSecondView.origin=CGPointMake(20, 50);
[self.canvas addLabel:goToSecondView];
goToSecondView.userInteractionEnabled = NO;
}
#end
SecondView.m
#import "SecondView.h"
#implementation SecondView
-(void)setup{
goToFirstView=[C4Label labelWithText:#"go to First View"];
goToFirstView.origin=CGPointMake(20, 50);
[self.canvas addLabel:goToFirstView];
goToFirstView.userInteractionEnabled = NO;
}
#end
C4WorkSpace.m
#import "C4Workspace.h"
#import "FirstView.h"
#import "SecondView.h"
#implementation C4WorkSpace {
FirstView *firstView;
SecondView *secondView;
}
-(void)setup {
firstView=[FirstView new];
firstView.canvas.frame = self.canvas.frame;
[firstView setup];
firstView.canvas.userInteractionEnabled = YES;
[self.canvas addSubview:firstView.canvas];
secondView=[SecondView new];
secondView.canvas.frame = self.canvas.frame;
[secondView setup];
secondView.canvas.userInteractionEnabled = YES;
[self.canvas addSubview:secondView.canvas];
secondView.canvas.hidden = YES;
[self listenFor:#"touchesBegan"
fromObjects:#[firstView.canvas, secondView.canvas]
andRunMethod:#"switchView:"];
}
-(void)switchView:(NSNotification *)aNotification {
C4View *v = (C4View *)aNotification.object;
if([v isEqual:firstView.canvas]) {
firstView.canvas.hidden = YES;
secondView.canvas.hidden = NO;
} else {
firstView.canvas.hidden = NO;
secondView.canvas.hidden = YES;
}
}
#end
This should work for you in the case that your views need differing functionality, like FirstView will have significantly different internal functionality than SecondView... If they are the same then you should think about collapsing them into the same subclass.
I'm trying to create a simple popup called Add Notes on a button click which has a save and cancel button to save the notes created by the user and to cancel the pop-up. This is pop-up classes
AddNotesPopUp.h
#import <UIKit/UIKit.h>
#import "UIImage+Buttons.h"
typedef enum AddNotesViewType
{
AddNotesPopUpSimple
}AddNotesPopUpType;
#protocol AddNotesDelegate<NSObject>
#optional
-(void)saveButtonClicked:(id) popUp;
-(void)cancelAddButtonClicked:(id)popUp;
#end
#interface AddNotesPopUp : UIView
#property AddNotesPopUpType atype;
#property (nonatomic,assign) id <AddNotesDelegate> delegate;
-(id)initWithDelegate:(id)parent type:(AddNotesPopUpType) type;
#property (weak, nonatomic) IBOutlet UIView *popView;
#property (strong, nonatomic) IBOutlet UIButton *titleButton;
#property (weak, nonatomic) IBOutlet UIButton *cancelAddButton;
#property (weak, nonatomic) IBOutlet UIButton *saveButton;
#property (weak, nonatomic) IBOutlet UITextView *textArea;
- (IBAction)saveButtonAction:(id)sender;
- (IBAction)cancelButtonAction:(id)sender;
-(void)show;
-(void)hide;
#end
AddNotesPopUp.m
#import "AddNotesPopUp.h"
#import <QuartzCore/QuartzCore.h>
#implementation AddNotesPopUp
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self=(AddNotesPopUp*)[[[NSBundle mainBundle] loadNibNamed:#"AddNotesPopUp" owner:nil options:nil] lastObject];
}
return self;
}
-(id)initWithDelegate:(id)parent type:(AddNotesPopUpType) type
{
if (self = [super initWithFrame:CGRectMake(0, 0, 300, 300)])
{
// Initialization code
self=(AddNotesPopUp*)[[[NSBundle mainBundle] loadNibNamed:#"AddNotesPopUp" owner:nil options:nil] lastObject];
}
self.delegate=parent;
self.atype=type;
UIViewController *parentView=(UIViewController*)parent;
[parentView.view addSubview:self];
if (type==AddNotesPopUpSimple)
{
[self.titleButton setImage:[UIImage buttonWithText:#"Add Notes" fontSize:15 bold:YES buttonSize:self.titleButton.frame.size baseColor:[UIColor colorWithRed:73.0/255.0 green:90.0/255.0 blue:100.0/255.0 alpha:1] downTo:[UIColor colorWithRed:57.0/255.0 green:70.0/255.0 blue:77.0/255.0 alpha:1]] forState:UIControlStateNormal];
[self.saveButton setImage:[UIImage buttonWithTextAlignCenter:#"Save" fontSize:15 bold:YES buttonSize:self.saveButton.frame.size baseColor:[UIColor colorWithRed:117.0/255.0 green:185.0/255.0 blue:83.0/255.0 alpha:1] downTo:[UIColor colorWithRed:95.0/255.0 green:144.0/255.0 blue:64.0/255.0 alpha:1]] forState:UIControlStateNormal];
[self.cancelAddButton setImage:[UIImage buttonWithTextAlignCenter:#"Cancel" fontSize:15 bold:YES buttonSize:self.cancelAddButton.frame.size baseColor:[UIColor colorWithRed:174.0/255.0 green:174.0/255.0 blue:174.0/255.0 alpha:1] downTo:[UIColor colorWithRed:124.0/255.0 green:124.0/255.0 blue:124.0/255.0 alpha:1]] forState:UIControlStateNormal];
}
self.popView.layer.masksToBounds=YES;
self.popView.layer.cornerRadius=5.0f;
self.popView.layer.borderWidth=1.0f;
self.popView.layer.borderColor=[[UIColor blackColor]CGColor];
self.popView.hidden=YES;
self.hidden=YES;
self.textArea.hidden=YES;
return self;
}
-(void)show
{
self.popView.hidden=NO;
self.textArea.hidden=NO;
[self.popView setTransform:CGAffineTransformMakeScale(0.1,0.1)];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.25];
[self.popView setTransform:CGAffineTransformMakeScale(1.0,1.0)];
[UIView commitAnimations];
}
-(void) hide
{
self.popView.hidden=YES;
}
- (IBAction)saveButtonAction:(id)sender {
[self.delegate saveButtonClicked:self];
}
- (IBAction)cancelButtonAction:(id)sender {
[self.delegate cancelAddButtonClicked:self];
}
#end
This is how I call the popup in my viewcontroller button action
- (IBAction)addNotes:(id)sender {
AddNotesPopUp *pop=[[AddNotesPopUp alloc] initWithDelegate:self type:AddNotesPopUpSimple];
[pop show];
}
I have checked with breakpoints and the execution goes successfully through the initwithDelegate and show methods in AddNotesPopUp.m but the pop-up doesnt appears, what am I missing here? I have added the delegates and classes of AddNotesPopUp in my viewcontroller and I dont receive any error either. I'm using Xcode 4.6. Any Suggestions?
Turns out it was a simple issue, I just needed to add
self.hidden=NO; in the show method
I'm very new to iOS programming (Coming from Java / C++). I'm trying to set up an app with a TabBarController of which one tab should be a SplitView. I've done my research and I know that UISplitview will not work and everywhere people recommend using the MGSplitViewController. I've looked at the demo but I just can't figure out how to use it without it beeing the app's root view and can't find any sample code that could help
So here is what I do with the classes from the demo in a separate UIViewController class that I afterwards add to the TabBarController: This is my class:
#import <UIKit/UIKit.h>
#import "MGSplitCornersView.h"
#import "RootViewController.h"
#import "DetailViewController.h"
#interface ChannelViewController : UIViewController {
MGSplitViewController *splitViewController;
RootViewController *rootViewController;
DetailViewController *detailViewController;
}
#property (nonatomic, retain) MGSplitViewController *splitViewController;
#property (nonatomic, retain) RootViewController *rootViewController;
#property (nonatomic, retain) DetailViewController *detailViewController;
#end
And this is my desperate try to set it up
- (id)initWithTabBar
{
self = [super init];
//this is the label on the tab button itself
self.title = #"SplitView";
//use whatever image you want and add it to your project
//self.tabBarItem.image = [UIImage imageNamed:#"name_gray.png"];
// set the long name shown in the navigation bar at the top
self.navigationItem.title=#"Nav Title";
self.splitViewController = [[MGSplitViewController alloc] init];
self.rootViewController = [[RootViewController alloc] init];
self.detailViewController = [[DetailViewController alloc] init];
[self.splitViewController setDetailViewController:detailViewController];
[self.splitViewController setMasterViewController:rootViewController];
[self.view addSubview:splitViewController.view];
[self.rootViewController performSelector:#selector(selectFirstRow) withObject:nil afterDelay:0];
[self.detailViewController performSelector:#selector(configureView) withObject:nil afterDelay:0];
if (NO) { // whether to allow dragging the divider to move the split.
splitViewController.splitWidth = 15.0; // make it wide enough to actually drag!
splitViewController.allowsDraggingDivider = YES;
}
return self;
}
I guess I'm doing something wrong with delegates? Or do I have something else mixed up?
Is the demo doing things in the IB that I can't see in the code?
I get the split view but no content and especially no navigation bar with the buttons the demo comes with.
I'd be very thankful for hints or sample code!
Ok manny, here we go. This is my working code for the interface:
#import <UIKit/UIKit.h>
#import "MGSplitViewController.h"
#import "ecbView.h"
#import "ecbCalc.h"
#interface splitMain : MGSplitViewController <UIPopoverControllerDelegate,
MGSplitViewControllerDelegate>
{
IBOutlet UIPopoverController* popoverController;
IBOutlet UINavigationController* naviController;
IBOutlet ecbCalc* viewCalcLeft;
IBOutlet ecbView* euroRatesRight;
UIBarButtonItem* savedButtonItem;
BOOL keepMasterInPortraitMode;
BOOL memoryWasDropped;
BOOL viewLoaded;
}
#property (nonatomic, retain) UIPopoverController* popoverController;
#property (nonatomic, retain) UINavigationController* naviController;
#property (nonatomic, retain) ecbCalc* viewCalcLeft;
#property (nonatomic, retain) ecbView* euroRatesRight;
#property (nonatomic, retain) UIBarButtonItem* savedButtonItem;
#property (nonatomic, readonly) BOOL keepMasterInPortraitMode;
#property (nonatomic, readonly) BOOL memoryWasDropped;
#property (nonatomic, readonly) BOOL viewLoaded;
- (void)dismissPopoverController: (BOOL)animated;
- (void)settingsChanged;
#end
and here excerpts from implementation file:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
// my initialization...
}
return self;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
CGRect rectFrame = CGRectMake(0.0, 20.0, 768.0, 1004.0 - 48.0); // being above a tab bar!
viewLoaded = NO;
self.view = [[UIView alloc] initWithFrame:rectFrame];
viewCalcLeft = [[ecbCalc alloc] initWithNibName:#"ecbCalc" bundle:nil];
euroRatesRight = [[ecbView alloc] initWithNibName:#"ecbView-iPad" bundle:nil];
naviController = [[UINavigationController alloc] initWithRootViewController:self.viewCalcLeft];
naviController.navigationBar.barStyle = UIBarStyleBlack;
naviController.title = nil;
viewCalcLeft.title = NSLocalizedString(#"BtnTitleCalc", #"");
viewCalcLeft.view.hidden = NO;
NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];
if ([prefs objectForKey:#"iPadAlwaysSplitTableView"] != nil)
self.keepMasterInPortraitMode = [prefs boolForKey:#"iPadAlwaysSplitTableView"];
else
self.keepMasterInPortraitMode = YES;
NSArray* theViewControllers = [NSArray arrayWithObjects:self.naviController, self.euroRatesRight, nil];
[self setViewControllers:theViewControllers];
[self setDelegate:self];
[self setShowsMasterInPortrait:keepMasterInPortraitMode];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
// protection because this one is called twice
if (viewLoaded)
return;
[super viewDidLoad];
if (memoryWasDropped)
{
if (!self.keepMasterInPortraitMode && UIInterfaceOrientationIsPortrait(self.interfaceOrientation))
{
// recreate popover controller
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:self.viewCalcLeft];
}
}
viewLoaded = YES;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
memoryWasDropped = YES;
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[self dismissPopoverController:NO];
self.popoverController = nil;
self.naviController = nil;
self.viewCalcLeft = nil;
self.euroRatesRight = nil;
viewLoaded = NO;
}
My MainWindow.xib has a UITabBarController and the button for splitMain is configured for this class but with an empty xib entry. So creation has to go via loadView. Maybe I could have done the viewDidLoad stuff within loadView ... but so I had to protect viewDidLoad from being called twice. That happens in loadView as soon as the view is instantiated from MGSplitViewController class because the initWithCoder there is calling [self setup]. In that function the frame rect is calculated with self.view.bounds so that viewDidLoad is called again because the view doesn't exist yet. Maybe one could implement a workaround within MGSplitViewController.m but I was too lazy doing that.
To get this working on a tab bar controller please make sure you commit most of the changes that are published on the MGSplitViewController's git page. Good luck.