I have a UINavigationController/UITableView and I want to present a UIView over top of it when the table is empty to give the user a prompt on how to add items to the table.
I've never make a UIView (as opposed to a UIViewController before) so I'll step through what I did to make it:
Make a new UIView Class - MakeSentenceHelperView
Make a nib called MakeSentenceHelperView.xib
Set File's owner to MakeSentenceHelperView
Load the nib in the MakeSentenceHelperView:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSLog(#"makesentencehelperview init");
[[NSBundle mainBundle] loadNibNamed:#"MakeSentenceHelperView" owner:self options:nil];
}
return self;
}
and present the MakeSentenceHelperView in the UITableViewController:
//present the placeholder view for sentences
MakeSentenceHelperView *makeSentenceHelperView = [[MakeSentenceHelperView alloc] init];
NSLog(#"present placeholder: self.navigationcontroller.view: %#", self.navigationController.view);
//Something like this:
[self.navigationController.view addSubview:makeSentenceHelperView];
[self.navigationController.view bringSubviewToFront:makeSentenceHelperView];
The class loads and logs ok, but nothing appears in front of the UITableView - where have I gone wrong?
UPDATE: if I add [self.tableView setHidden:YES]; then the tableview disappears and the space is black and empty. I'm assuming this means I'm setting up the View wrong, somewhere.
You can use https://github.com/ecstasy2/toast-notifications-ios/ for showing Toast view liek Android. Check array size and if table view is not showing then called this one and show any custom method.
Thanks to #Aadhira for their link which led me to the problem.
I needed to add awakeFromNib
I was missing [self addSubview:self.view]; at the end of initWithFrame.
Related
I will start off by describing what I'm trying to accomplish and then follow by describing what I've tried already. I am pretty sure what I've tried is NOT the best approach so please correct my approach as needed!
I have a ViewController.m and a Custom View which is laid out in CustomView.xib. The custom view has UIButtons and UILabels which are populated from an Array of Custom Objects.
The user flow should go as such: ViewController starts off showing CustomView with its labels populated by
CustomObjectArray[0] -> User presses button -> Another "copy" of CustomView slides into the view, over the previous version.
It's labels and buttons are populated by CustomObjectArray[1] -> User presses button -> repeat until end of Array.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So far I made a ViewController.m/h, a CustomView.m/h AND a CustomView.xib file. I used interface builder to do the layout.
On the "Custom Class" tab for the top-level View in XIB file, I type in "CustomView". I also drag IBOutlets from the XIB file to the CustomView HEADER (.h) file.
In the ViewController, under -(instancetype) init method, I create a custom view using the normal initWithNib method. And then I do:
self.view = CustomViewVariableName;
When I run the program, the view show's up fine. However, when I try to selector's, nothing's getting recognized by the buttons:
[currentCustomView.continueButton addTarget:self action:#selector(continueButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
What did I do wrong here?
More importantly, given my described goals up top, am I even doing this right? Do I need to have CustomView.m/h files? Or can I do the same thing with ONLY the XIB and the ViewController file. Remember that I need to have "multiple copies" and slide them on top of each other until the end of my custom objects array.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some more code as requested.
In ViewController:
- (instancetype)init
{
currentCustomView = [[[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:nil] objectAtIndex:0];
self.view = currentQuizQuestionView;
.......
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[currentCustomView.continueButton addTarget:self action:#selector(continuePressed:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)continuePressed:(id)sender{
NSLog(#"Current position");
//[self moveInQuestion];
}
In CustomView.h:
#import <UIKit/UIKit.h>
#interface CustomView : UIView
#property (weak, nonatomic) IBOutlet UIButton *continueButton;
#end
In CustomView.m:
this is just the default page, I added nothing in this file.
CustomView.xib:
I'm not sure if I fully understand your requirements. Let's assume you would like to have several CustomViews as subviews of your ViewController and those subviews can be display each by each after pressing its own button.
First thing about adding subview:
self.view = CustomViewVariableName;
Since CustomsViews will be subviews according to my assumption, above line is an error. You probably would like to have something like this.
for (NSInteger i = 0; i < 5; i++) {
CustomView *v = [[CustomView alloc] initWithNib];
[v.button addTarget:self
action:#selector(continuePressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:v];
}
Second, I noticed you would like to have an array as a handler to refer all the subviews. We can add above CustomView into a mutable array by insert one more line into above for-loop.
[_customObjectArray addObject:v.button];
Finally, I created a simple project and tried to implement things you mentioned. Maybe you can take it for a reference. https://db.tt/Och2tzyG
My Views Hierarchy is next:
My root View Controller that contains custom view
My custom UIView that contain custom UITableView
My custom UITableView
And i want to use delegate methods of my custom UITableView, but i don't really know how to access it's delegates because UITableView is added in my custom UIView class. Please clear me up, i'm little confused about this question.
Here's my code:
Adding my custom UITableView to UIView(i'm using CollapseClick):
-(void) initMehod{
DetailsView *testView = [[[NSBundle mainBundle] loadNibNamed:#"DetailsView" owner:self options:nil] lastObject];
test1View = testView;
//collapse click init
CGRect viewRect = [test1View frame];
viewRect.origin.x = 10;
test1View.frame = viewRect;
[test1View setBackgroundColor:[UIColor magentaColor]];
self.myCollapseClick.CollapseClickDelegate = self;
[self.myCollapseClick reloadCollapseClick];
// If you want a cell open on load, run this method:
[self.myCollapseClick openCollapseClickCellAtIndex:0 animated:NO];
}
...
And i'm using PagedFlowView in my root View Controller to add CustomView:
- (UIView *)flowView:(PagedFlowView *)flowView cellForPageAtIndex:(NSInteger)index{
mainDetailV = (MainDetailView *)[flowView dequeueReusableCell];
if (!mainDetailV) {
mainDetailV = [[[NSBundle mainBundle] loadNibNamed:#"MainDetailView" owner:self options:nil] lastObject];
//mainDetailV.layer.cornerRadius = 6;
mainDetailV.layer.masksToBounds = YES;
}
[usedViewControllers insertObject:mainDetailV atIndex:index];
return mainDetailV;
}
Everything works perfectly, except i can't use my custom UITableView delegate (for example didSelectRowAtIndexPath: method).
EDIT: I have fixed my problem, PagedFlowView actually handles tag gesture recogniser and overrides my custom tableView delegate methods.
Similar question:
UITableView as a subview?
First of all your collapsable tableview abstracts tableview delegates (i.e its a wrapper).
It provides you with a method didClickCollapseClickCellAtIndex instead. Use that.
It seems to be that you have some problem in understanding delegation pattern.
Avoid breaking the cascading effect of delegation pattern. It makes debugging easy
and helps to understand the flow of the code. Below diagram might help you to understand what I mean
Implement you didSelectRowAtIndexPath in custom view instead of rootViewcontroller.
// This is your custom view
-(id)init{
----
self.myCollapseClick.CollapseClickDelegate = self;
----
}
//collapsable delegate
-(void)didClickCollapseClickCellAtIndex:(int)index isNowOpen:(BOOL)open {
// you need to create your own custom view delegate with mehthod didSelectIndex:index
[self.customViewDelegate didSelectIndex:index];
}
In your rootviewcontroller you need to do this
customView.customViewDelegate = self;
-(void)didSelectIndex:(int)index{
// do your stuff here
}
In my app I habe a view controller that calls several views. All these views are UIViews. That works fine, but not in every case. One of the views that are called has some labels, textfields and two UITextViews. Everything is shown correctly but the UITextViews. The view is called in that way:
[[self view] addSubview:tasteView];
//tasteView = [[TasteView alloc] init];
[self setCurrentView:tasteView];
I call the init method of the view to display the UITextViews:
EDIT: After a comment of Phillip Mills this was slightly changed! Init isn't called anymore.
- (id)init
{
if (self)
{
[tv1 setNeedsDisplay];
CGRect frame = tv1.frame;
frame.size.height += 1;
tv1.frame = frame;
}
return self;
}
As I saw that setNeedsDisplay had no effect, I changed the size of the corresponsing frame to force a redraw. Unfortunately that had no effect, too.
Btw, the view is initially loaded in the viewDidLoad of the view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
[self setCurrentView:placeholder];
[self configureView];
wineryView = [self loadWineryView];
wineView = [self loadWineView];
tasteView = [self loadTasteView];
}
A method for loading the views looks like this:
- (UIView *) loadTasteView
{
NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:#"TasteView" owner:self options:nil];
UIView *tView;
for (id view in nibViews)
{
if ([view isKindOfClass:[TasteView class]])
{
tView = (TasteView*) view;
}
}
return tView;
}
I do not know why those UITextViews are not shown. Did I forget something? To show really everything, here are the connections that I made in InterfaceBuilder:
Does anyone know what I did wrong and can help me?
I think your initial code should be like this :
tasteView = [[TasteView alloc] init];
[[self view] addSubview:tasteView];
[self setCurrentView:tasteView];
addSubView after it is allocated
Hope it helps you
If you are creating the view in code (your first sample), alloc and init the view before trying to add it as a subview.
If you're loading it from another nib (last code section), you still need to add it to the view hierarchy.
HI have a custom view class that is loaded and placed within my main view using the following code. The reason it that i want to populate it with different content so rather than build a view in code each time if I create a custom class i can reuse this in a loop etc, I got this to work just fine in code, that is laying out the buttons label etc.
But rather than hand code it all I thought if i create a new User Interface View, then construct visually my text fields, labels and buttons on this view.
Then connect it to my custom class.
Bu this is where I am having an issue, how do I connect this view xib file so that it becomes visible when placed on my my code. I have assigned the custom class attribute within the xib file to my custom file, but what else am i missing?
.h File:
#import <UIKit/UIKit.h>
#interface blogView : UIView
#end
.m File:
#import "blogView.h"
#implementation blogView
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 478, 220)];
if (self != nil)
{
NSLog(#"Blog View loaded");
self.backgroundColor = [UIColor yellowColor];
UILabel *titleLbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 400, 40)];
[titleLbl setText:#"This is the Title"];
[self addSubview:titleLbl];
}
return self;
}
#end
my xib file has the same name blogView.xib which is a View User Interface.
Within my main view controller and in the ViewDidLoad i have
blogView *blogItem = [[blogView alloc]init];
[self.view addSubview:blogItem];
When I run this is all works fine, but I would like to link to a .xib file to save time etc.
Thanks
Well having look around and trying bits of clues and suggestion I managed to do this with the following:
Within my .m file I placed/Changed the following:
self = [super init];
if (self != nil)
{
NSArray *theView = [[NSBundle mainBundle] loadNibNamed:#"blogView" owner:self options:nil];
UIView *nv = [theView objectAtIndex:0];
.. rest of code.
[self addSubview:nv];
.. rest of code.
Many Thanks
I struggled with this for an hour when I RENAMED my viewcontroller class. This is what worked for me in Xcode 5
Go to your XIB file
Click on Files owner transparent box on the left
Open up your inspections tab(Third button on right in the View Section - in between Editor and Organizer)
Go to your identity Inspector(3rd from the left) underneath the editor organizer view tab.
Fix the custom class - Class option to whatever class you want it to respond to.
Lets just say I was extremely annoyed after wasting time with that
You might want to create a controller for your view and load that view using initWithNibName:bundle:
I can't figure out what the problem is here. I have a very simple UIViewController with a very simple viewDidLoad method:
-(void)viewDidLoad {
NSLog(#"making game view");
GameView *v = [[GameView alloc] initWithFrame:CGRectMake(0,0,320,460)];
[self.view addSubview:v];
[super viewDidLoad];
}
And my GameView is initialized as follows:
#interface GameView : UIView {
and it simply has a new drawRect method:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
NSLog(#"drawing");
}
In my console, I see "making game view" being printed, but "drawing" never is printed. Why? Why isn't my drawRect method in my custom UIView being called. I'm literally just trying to draw a circle on the screen.
Have you tried specifying the frame in the initialization of the view? Because you are creating a custom UIView, you need to specify the frame for the view before the drawing method is called.
Try changing your viewDidLoad to the following:
NSLog(#"making game view");
GameView *v = [[GameView alloc] initWithFrame:CGRectMake(0,0,320,460)];
if (v == nil)
NSLog(#"was not allocated and/or initialized");
[self.view addSubview:v];
if (v.superview == nil)
NSLog(#"was not added to view");
[super viewDidLoad];
let me know what you get.
Check if your view is being displayed. If a view is not currently on screen, drawRect will not be getting called even if you add the view to its superview. A possibility is that your view is blocked by the some other view.
And as far as I know, you don't need to write [super drawRect];
Note that even if viewDidLoad is called on a view controller it doesn't necessarily indicate the view controller's view is displayed on screen. Example: Assume a view controller A has an ivar where a view controller B is stored and view controller A's view is currently displayed. Also assume B is alloced and inited. Now if some method in A causes B's view to be accessed viewDidLoad in B will be called as a result regardless whether it's displayed.
If you're using a CocoaTouch lib or file you may need to override the initWithCoder method instead of viewDidLoad.
Objective-C:
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
//Do Stuff Here
}
return self;
}
I had a view that was offscreen, that I would load onscreen and then redraw. However, while cleaning up auto-layout constraints in XCode, it decided my offscreen view should have a frame (0,0,0,0) (x,y,w,h). And with a (0,0) size, the view would never load.
Make sure your NSView has a nonzero frame size, or else drawRect will not be called.