I have a problem in my iOS application that I'm looking for some help with. I'm relatively new to iOS programming to I'm sure that there is some relatively simple solution to my problem.
First, I'm going to explain the hierarchy of the application:
It uses a UITabBarController to show a couple of different screens.
It uses a SWRevealViewController to show a sidebar
The sidebar is accessed from a Bar button item that is present in the Navigation bar of the application.
That the application uses SWRevealViewController https://github.com/John-Lluch/SWRevealViewController doesn't directly affect the problem that I have. If you are not familiar with this code base, just think of a Simple Bar Button that is shown at all times.
Now to the problem:
The Bar button that I want to show is associated with a few lines of code. (A property declaration and some methods).
This code should be used on a major part of the different view controllers in the application.
Now in the normal case, I'd just subclass UIViewController and make it the superclass of all my views that should show this button. However, my application should also show other types of views, such as a UITableViewController, so subclassing doesn't solve the entire problem.
If Objective-C supported Multiple Inheritance, I would make a class containing this code and let my other classes extend any subclass of UIViewController and my ugly support class at the same time.
Notes:
For now, my app is based on Storyboards
The TabBarController points to a number of UINavigationControllers, and not to any views that doesn't have a Navigation Bar.
I have tried implementing this with Objective-c Category where I add a category to UIViewController that does setup of my UIViewController. But I got stuck on this solution when I needed to add a #Property for the button and linking it to the XIB/Storyboard. Got the idea from this post Add the same UIBarButtonItem to several UIViewControllers but it doesn't contain any details.
tl;dr: I want to show the very same UIBarButtonItem on many of my applications views. The UIBarButtonItem is associated with some code, that is also the same for all these views.
What would be a good way to achieve this?
If i understood you correctly.
You want to show button for all your UIViewControllers.
There are many ways to achieve this. Please try this one.
1. Create a subclass of UIView with its XIB. It contains your button. create Properties and IBAction.
2. Implement your action on this subclass.
3. On .m file write the below code
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
if (![self.subviews count])
{
NSBundle *mainBundle = [NSBundle mainBundle];
NSArray *loadedViews = [mainBundle loadNibNamed:#"MyView" owner:nil options:nil];
return [loadedViews firstObject];
}
return self;
}
where, MyView is the name of your view.
4. Drag and drop a UIViewand place it on every `UIViewController XIB (or storyboard in your case) and set its custom class to "MyView" (or the name of your newly created class).
5. Run your project.
For reference: May i help you?
I have now solved this problem and I will post it here for reference:
This solves the problem with adding a sidebar button to several views in the project, but the code should be usable for any UIBarButton. The solution is the create a Category for UIViewController that specifies a setup method. This setup method is called from the different Views.
Category .h file:
#import <UIKit/UIKit.h>
#interface UIViewController (SidebarCompliance)
- (void)setupSidebar;
#end
Category .m file:
#import "UIViewController+SidebarCompliance.h"
#import "SWRevealViewController.h"
#implementation UIViewController (SidebarCompliance)
- (void)setupSidebar {
SWRevealViewController *revealViewController = self.revealViewController;
if (revealViewController) {
UIBarButtonItem *sidebarButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"menu.png"] landscapeImagePhone:[UIImage imageNamed:#"menu.png"] style:UIBarButtonItemStylePlain target:self.revealViewController action:#selector(revealToggle:)];
self.navigationItem.rightBarButtonItem = sidebarButton;
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
}
#end
And then an example of one of my views:
View .h file:
#import <UIKit/UIKit.h>
#import "UIViewController+SidebarCompliance.h"
#interface NumeroUno : UIViewController
#end
View .m file:
#import "NumeroUno.h"
#implementation NumeroUno
- (void)viewDidLoad {
[super viewDidLoad];
[self setupSidebar];
}
#end
Related
I am working on an iOS project and wanted to include a UIView that is reused on multiple screens in the application (appearing at the bottom of different UIViews). I am using a storyboard for the UI work so far but created an .xib file to be used by the reusable view (playerView in code below).
The view gets added but the button I have added to the View is unresponsive, also my background color cannot be changed on the view. I have tried to set background color programmatically and in the .xib with no luck. Very weird symptoms and I tried to instantiate the view from #5 of this article and probably did something wrong. I dont fully understand everything in the article which makes me nervous - for instance my showSubclassedView method returns IBAction but I just call the function name in code and dont use a button (I did hook up the buttons in the view as the article described though).
Here is the code:
EventViewController.m (where I trry and add PlayerView)
#import "EventViewController.h"
#import "PlayerView.h"
#interface EventViewController ()
-(IBAction)showSubclassedView;
#end
#implementation EventViewController
-(IBAction)showSubclassedView
{
[PlayerView presentInViewController:self];
}
PlayerView.h (.h for reusable view)
#import <UIKit/UIKit.h>
#import "Utils.h"
#class PlayerView;
#protocol PlayerViewDelegate
-(void)playerViewTouchedUp:(PlayerView*) playerView;
-(void)playerViewDidDismiss:(PlayerView*) playerView;
#end
#interface PlayerView : UIView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate>*) playerView;
-(IBAction)viewTouchedUp;
-(IBAction)dismiss;
#end
PlayerView.m (.m for reusable view)
#import "PlayerView.h"
#interface PlayerViewOwner : NSObject
#property(nonatomic,weak) IBOutlet PlayerView *playerView;
#end
#implementation PlayerViewOwner
#end
#interface PlayerView ()
#property (nonatomic, weak) UIViewController <PlayerViewDelegate> *delegateViewController;
#end
#implementation PlayerView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate> *)viewController
{
PlayerViewOwner *owner = [PlayerViewOwner new];
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:owner options:nil];
owner.playerView.delegateViewController = viewController;
[viewController.view addSubview:owner.playerView];
}
-(IBAction)viewTouchedUp
{
//forward to delegate
NSLog(#"you clicked a button");
[self.delegateViewController playerViewTouchedUp:self];
}
-(IBAction)dismiss
{
[self removeFromSuperview];
// Forward to delegate
[self.delegateViewController playerViewDidDismiss:self];
}
#end
PlayerView.xib has a UIbutton on it that connects it to viewTouchedUp method in PLayerView.m
Is there anything I did wrong in the code above? Is this the best way to do a reusable view to display on other views?
Thank you!
Here's a workaround I found after not being able to solve this.
New implementation is from this article
I reverted my changes from my initial question and implemented this. It lacks the nice protocol separation for talking back and forth and I might need something like this later but I think now I can still implement a protocol to solve this.
At least with this solution I have usable items in my view and a background that changes!
I started a project with storyboards and it has a lot of views, each one of them has the same header (with an image, company name and two buttons). I want to do this once in the main View, and make it reusable for the other views.
You could create a containing view controller with your header. Then, add your current root view controller (the current initial view controller in your storyboard) to this containing view controller.
Create a custom view named HeaderView with XIB:
in HeaderView.h you have to define a protocol and the properties related to controls you want to display in header.
#protocol HeaderViewDelegate <NSObject>
- (void)onBackButtonTapped;
#end
#interface HeaderView : UIView
#property (nonatomic, strong) IBOutlet UIImageView *headerImageView;
#property (nonatomic, weak) id <HeaderViewDelegate> delegate;
-(IBAction)backButtonTapped:(id)sender;
#end
In Header.m:
#implementation HeaderView
-(IBAction)backButtonTapped:(id)sender
{
if (delegate != nil && [delegate respondToSelector:#selector(onBackButtonTapped)])
{
[delegate onBackButtonTapped];
}
}
#end
Now what you have to do is to create a BaseViewController and every controller should be extended from this controller in order to show the same header in all the views.
Let me know you have any questions regarding the implementation.
I have managed to create reusable views according to this post.
Create a class named SharedView which extends UIView
Create a nib with the same name
Set the ‘File’s Owner’ property in the nib to the SharedView class
Create an outlet from your view to the SharedView class, and call it ‘contentView’
Replace initWithCoder with the following:
-(void)awakeFromNib {
//Note that you must change #”BNYSharedView’ with whatever your nib is named
[[NSBundle mainBundle] loadNibNamed:#"BNYSharedView" owner:self options:nil];
[self addSubview: self.contentView];
}
In your ViewControllers create views, and set their class to SharedView
Another solution is to use Container View Controller, and as to your specific situation, I have tried to implement a demo for you, please try it!
Hope it could help!
Why don't you use NavigationController as rootviewControoler with leftBarbutton and rightbarButton
so that it can be in your whole app
I am trying to create a new control for Xcode to implement into a new iOS app. The end idea is to display the formation of a football squad graphically. I realise that this could all be coded programmatically but I want to create a new control to represent a player and then load the formation accordingly as I may add other player information to the control in the future.
I have created a xib view file, in which is a label for displaying their name. I have tried the following but the label's text doesn't show up. Am I missing something obvious?
[I have included the correct headers and have connected the label up and set the xib to the new class]
header file for xib:
#interface playerObject : UIControl
#property (nonatomic, strong) NSString *playerNameLabel;
#end
implementation file for xib:
#import "playerObject.h"
#interface playerObject ()
#property (strong, nonatomic) IBOutlet UILabel *nameLabel;
#end
#implementation playerObject
- (void) setPlayerNameLabel:(NSString *)playerNameLabel
{
self.nameLabel.text = playerNameLabel;
}
View Controller Implementation File:
- (void)viewDidLoad
{
...
playerObject *newPlayer = [[playerObject alloc] initWithFrame:CGRectMake(10, 10, 100, 150)];
[newPlayer setPlayerNameLabel:#"TEST"];
[newPlayer setBackgroundColor:[UIColor redColor]];
[self.view addSubview:newPlayer];
}
Thanks in advance!
You may have created a xib file containing a label however you do not appear to be using it. You are creating a new instance of the playerObject class instead of loading one from a xib file. Take a look at the UINib class documentation instead.
You are instantiating your custom view without loading it from the .xib file.
In order to make it work, follow these steps:
Make your playerObject inherit from UIView instead of UIControl.
Open your .xib file.
Select the root view on the left pane.
On the right pane, switch to the Identity Inspector tab.
Type playerObject into the first text field "Class".
Make sure that you connected all your IBOutlets within Interface Builder.
Do the following to load your custom UIView from the .xib file:
playerObject *newPlayer = (playerObject *)[[[NSBundle mainBundle] loadNibNamed:#"MyXibFilename" owner:nil options:nil] firstObject];
newPlayer.playerNameLabel = #"Lionel Messi";
Note aside: I strongly recommend you to start using "namespaces" for your classes (it's just a two-letter prefix), such as XXPlayerObject, with XX being something else you consider describes your app / module. All other related custom classes should "share" this namespace. Look at what Apple does with its classes.
I hope this helps you!
I am struggling to make a simple thing (at least I think it's simple) but I just can't do it!
I will try to explain a little bit.
It's an app which displays information. When the user is inside a view, he can click on a button, which displays a popoverview, where he can choose which information he wants to know.
Actually, I can't create an action that changes the UILabel text I created in the main view when the user clicks on the popoverview's buttons.
Anyone has any idea?
Just for you to know: the main view I created a class for it, and also for the popoverview. Although, the popover view I created its design in a XIB file (I don't know if this is important, that's why I am putting this).
Well, I hope you guys were able to understand my question.
Thanks in advance.
Fernando.
Just create a property from the viewcontroller and access it from the consumer (other viewcontroller )
You will have to use delegation in order to see changes in the main view when you are making different actions inside the popover. First, you need to create a protocol inside your popover controller header file:
#import <Foundation/Foundation.h>
#class MyPopoverController;
#protocol MyPopoverDelegate
- (void)valueChanged:(NSString*) newVal;
#end
#interface MyPopoverController: UIPopoverController
#property (weak) id<MyPopoverDelegate> delegate;
#end
Then in .m you implement it like this:
- (void) someActionOccured
{
if([self.delegate respondsToSelector:#selector(valueChanged:)]){
[self.delegate valueChanged:valueYouWantToSendBack];
}
}
Remember that in your main class you have to implement MyPopoverDelegate protocol:
#interface MainViewController: UIViewController <MyPopoverDelegate>
And when you instantiate your popover controller:
/*
** inside MainViewController.m
*/
// remember to assign it's delegate
MyPopoverController *popoverController = [MyPopoverController alloc] init];
popoverController.delegate = self;
Also, you'll have to implement the protocol's method:
/*
** inside MainViewController.m
*/
- (void)valueChanged:(NSString*) newVal
{
// process the string and display it where you need it
}
I am new to IOS, Xcode and MVC. I am on a steep learning curve and am failing with what I assume is a most basic task.
I have a tabbed application with two tabs. Both tab views communicate with a web service and I want to add an image to each tab view, changing the image to indicate the connection state.
So, I created a third .xib file with a controller class (IconViewController). I am hoping to add and remove an instance of this icon view in each of the tab views.
Here is the pseudo code for my icon view:
#interface IconViewController : UIViewController
{
UIImageView *_icon;
}
#property (nonatomic) IBOutlet UIImageView *icon;
- (void)setForBusy;
- (void)setForOk;
- (void)setForFail;
And implementation:
#implementation IconViewController
#synthesize icon = _icon;
-(void)setForBusy
{
// Set Busy Icon Image
}
-(void)setForOk
{
// Set Ok Icon Image
}
-(void)setForFail
{
// Set Fail Icon Image
}
The icon IBOutlet is connected to an UIImageView on the accompanying xib file.
Here is one of the root tab controllers:
#import "IconViewController.h"
#interface TaboneViewController : UIViewController
{
IconViewController *_iconViewController;
}
#property (nonatomic) IBOutlet IconViewController *iconViewController;
and implementation:
#synthesize iconViewController = _iconViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
self.iconViewController = [[IconViewController alloc]
initWithNibName:#"iconViewController"
bundle:nil];
[self.view addSubview:self.iconViewController.view];
}
In the tabView xib Interface Builder I added an Object and made it a class type IconViewController. I connected the Icon View Controller Object->Reference Outlet to the File Owner->iconViewController Outlet.
Running the project I get the error:
loaded the "iconViewController" nib but the view outlet was not set.
I have experimented with other connections but with no luck. It seems to me that my first connection should work but it doesn't.
Any idea what I am misunderstanding? Is the principle good (loading an instance of third view into two root views)? If so, what outlet needs connecting?
Many thanks, Polly
I see your issue. You want to have common stage of image for both tab. I think it is better to implement subclass of UIView (or UIImageView) and implement all methods like set (void)setForBusy and etc. The stage of image you should receive from parent ViewController, something like UINavigationView controller (if you have it). Otherwise you should save stage somewhere else. My personal opinion it is too expensive to create new controller just for your purpose.
Hope it helps.