I have a view controller loaded from xib with a table view and a text field as titleView in the navigation bar. Simple.
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#end
#implementation ViewController
#synthesize tableView;
- (void)viewDidLoad {
[super viewDidLoad];
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
[tableView reloadData];
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
self.navigationItem.titleView = tf;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 42;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#""];
cell.textLabel.text = #"test cell";
return cell;
}
#end
I tap the text field, let the keyboard show and start to drag the table view to interact with keyboard.
The problem is when I release touch while interacting and let the keyboard fully show: it goes up without animation. If I release to hide it works.
Furthermore this is only in iOS 8. It works in iOS 7.
Am I missing anything?
Related
I have a viewController that contains a programmatically created tableView.
#property (strong, nonatomic) UITableView *numbersTableView;
//...
self.numbersTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, -100, self.view.frame.size.width-20, 50)];
self.numbersTableView.delegate = self;
self.numbersTableView.dataSource = self;
self.numbersTableView.tag = 1;
self.numbersTableView.layer.cornerRadius = 5;
[self.numbersTableView setBounces:false];
[self.numbersTableView setHidden:true];
[self.numbersTableView registerClass:[AZGCountryCell class] forCellReuseIdentifier:#"NumbersTableViewCell"];
[self.view addSubview:self.numbersTableView];
For the prototype cell I want to use a prototype that I created somewhere else in another viewController and I designed It in storyboard.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if (tableView.tag == 1) { //tableView == self.numbersTableView
NSString *cellID = #"NumbersTableViewCell";
AZGCountryCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[AZGCountryCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.countryName.text = self.numbersArray[indexPath.row].number;
cell.flagImageView.image = [UIImage imageNamed:self.numbersArray[indexPath.row].country];
return cell;
}
}
And my custom cell contains one UIImageView and one UILabel but when I run the code the cells are empty and I can see the UIImageView and UILabel are nil!
#import <UIKit/UIKit.h>
#interface AZGCountryCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIImageView *flagImageView;
#property (strong, nonatomic) IBOutlet UILabel *countryName;
#property (strong, nonatomic) IBOutlet UILabel *countryCode;
#end
#import "AZGCountryCell.h"
#implementation AZGCountryCell
#synthesize flagImageView;
#synthesize countryName;
- (void)awakeFromNib {
[super awakeFromNib];
self.flagImageView.layer.cornerRadius = self.flagImageView.frame.size.width/2;
self.flagImageView.layer.masksToBounds = YES;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
#end
Then what should I do to have properly filled cells in my numbersTableView?
Unfortunately you can't reuse a table cell you've defined in a table view in a storyboard in your separate class.
In order for you to be able to share your cell between the different views, you'll have to extract the view to a separate nib and register that nib go be used on both tables.
Alternatively you can implement the cell's UI in code in the table view cell subclass.
You getting empty cell because custom tableview cell not registered, use
[self.numbersTableView registerNib:[UINib nibWithNibName:#"AZGCountryCell" bundle:nil] forCellReuseIdentifier:#"NumbersTableViewCell"];
instead of
[self.numbersTableView registerClass:[AZGCountryCell class] forCellReuseIdentifier:#"NumbersTableViewCell"];
I can't figure out how to get this UITableView to display.
The code creates the table fully programmatically except for the nib.
The nib is a simple cell that works in other UITableViews in the same app.
When the table view is created and added as a subview to the view and reloadData is called then numberOfSectionsInTableView: and tableView:numberOfRowsInSection: are both called. They both return 1. (I checked in the debugger.)
However tableView:cellForRowAtIndexPath: is never called.
I add the tableView to it's parent view with a NSLayoutConstraint that forces it's height, but nothing is displayed in that spot.
The view hierarchy debugger shows nothing in that spot and that there isn't a view on top of the table.
The app runs without any error or crashes.
I would appreciate your help.
#interface MyViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *button;
#end
#implementation MyViewCell
#end
#interface MyDataTableEntry : NSObject
#property (nonatomic, strong) NSString* title;
#end
#implementation MyDataTableEntry
#end
#interface MyDataTable : NSObject <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) UITableView *tableView;
#property (strong, nonatomic) NSArray *rows;
#property (strong, nonatomic) UINib* nib;
#end
#implementation MyDataTable
- (UINib*)getAndRegisterNib:(NSString*)reuseIdentifier {
UINib* nib = [UINib nibWithNibName:reuseIdentifier bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:reuseIdentifier];
return nib;
}
- (id)initWithRows:(NSArray*) rows andView:(UIView*)view {
if (self = [super init]) {
self.rows = rows;
self.tableView = [[UITableView alloc] initWithFrame:view.bounds style:UITableViewStylePlain];
self.nib = [self getAndRegisterNib:#"PrototypeCell"];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.backgroundColor = [UIColor grayColor];
}
return self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.rows.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PrototypeCell" forIndexPath:indexPath];
MyDataTableEntry* entry = self.rows[indexPath.row];
[cell.button setTitle:entry.name forState:UIControlStateNormal];
cell.button.backgroundColor = [UIColor blueColor];
return cell;
}
#end
Here is a snippet that creates the table:
MyDataTableEntry* entry = [[MyDataTableEntry alloc] init];
entry.title = #"hello";
self.dataTable = [[MyDataTable alloc] initWithRows:#[entry] andView:self.view];
[self.view addSubview:self.dataTable.tableView];
[self.dataTable.tableView setNeedsLayout];
[self.dataTable.tableView layoutIfNeeded];
[self.dataTable.tableView reloadData];
Without confirming in a debugger:
The problem is here:
self.dataTable = [[MyDataTable alloc] initWithRows:#[entry] andView:self.view];
[self.view addSubview:self.dataTable];
self.dataTable is an NSObject. The second line should read something like this:
[self.view addSubview:self.dataTable.tableView];
I would also suggest that you engage in some refactoring. MyDataTable is not a view. It's a controller. So rename to MyDataTableController. Then the bug would have been more obvious.
I would also ask why you are doing this in code? you are already using nibs. So why not go to storyboards. Doing that and using UITableViewController as a base class should enable you to remove a lot of the code and potential bugs.
Case is following: I want to create UITableView from separate class.
Currently I have following:
// Menu.h
#interface Menu : UITableViewController <UITableViewDelegate, UIAlertViewDelegate> {
UITableView *tableView;
}
#property (nonatomic,retain) NSMutableArray *navigationItems;
- (void)initMenu:(UIView *)view;
#end;
Then
// Menu.m
#import <Foundation/Foundation.h>
#import "Menu.h"
#implementation Menu
- (void) initMenu:(UIView *)view {
self.navigationItems = [[NSMutableArray alloc] initWithObjects:#"One",#"Two",#"Three",#"Four",#"Five",#"Six",#"Seven",#"Eight",#"Nine",#"Ten",nil];
UIView *mainmenu=[[UIView alloc]initWithFrame:CGRectMake(0, 50, 320, 420)];
[mainmenu setBackgroundColor:[UIColor yellowColor]];
[view addSubview:mainmenu];
UITableView *menutableView = [[UITableView alloc] initWithFrame:view.bounds style:UITableViewStylePlain];
menutableView.backgroundColor = [UIColor whiteColor];
menutableView.delegate = self;
menutableView.dataSource = self;
[mainmenu addSubview:menutableView];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableViewi cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableViewi dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [self.navigationItems objectAtIndex:indexPath.row];
return cell;
}
#end
And in different .m file I call method:
...
#import "Menu.h"
...
- (void)viewDidLoad
{
[super viewDidLoad];
...
Menu *menu = [[Menu alloc] init];
[menu initMenu: self.view];
}
Running this will crash application and Xcode won't give any detailed report. However, if I combine Menu.m to the .m file where I'm calling "initMenu" it won't crash.
Also if I comment out menutableView.dataSource = self; it will run with our crash (no rows in table of course...).
Passing a view into an init method and then creating/adding subviews in said init method is an odd design pattern. Change your Menu class to a viewcontroller, then move your UIView and UITableView declarations to the viewDidLoad method. The crash is likely happening because the tableview is trying to display data before its parent view has finished loading.
I have UITableView with custom UITableViewCell. Custom cell contains UIButton and UILabel.
Here I observe that UILabel text is change as I expected but UIButton text is not changing.
When I scroll out the button outside of the screen, change the label of UIButton.
Why it is not working? I have use Xcode 6 and use below code.
ViewController.h
#import <UIKit/UIKit.h>
#import "customTableViewCell.h"
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView registerNib:[UINib nibWithNibName:#"customTableViewCell" bundle:nil] forCellReuseIdentifier:#"customTableViewCell"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
customTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"customTableViewCell" forIndexPath:indexPath];
cell.button.titleLabel.text = #"Label does not change immediately";
cell.label.text = #"change label";
return cell;
}
customeTableViewCell.h
#import <UIKit/UIKit.h>
#interface customTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *button;
#property (weak, nonatomic) IBOutlet UILabel *label;
#end
This is because the UIButton class has multiple states (Normal, Selected, Highlighted, Disabled). When you change the text property of it's internal UILabel (textLabel property of UIButton), it's property is overriden by setState function, which is called when table is loaded.
To change text in the label of a button you need to call setTitle:forState: method. Here is your code fixed to work:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
customTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"customTableViewCell" forIndexPath:indexPath];
[cell.button setTitle:#"Now it works" forState:UIControlStateNormal];
cell.label.text = #"change label";
return cell;
}
For the sake of completion, you can also use setAttributedTitle:forState: method with NSAttributedString, so you can actually set your own specifically formatted string as a title.
Use this
[cell.button setTitle:#"MyNewTitle" forState:UIControlStateNormal];
I am trying to show a UIViewController on top of other UIViewcontroller using addChildViewController functionality.The childViewController is a tableView which shows up on top of my MainViewController however I do not see the table view that it has.If I execute the childViewController separately , the tableView works fine , so what am I missing here.
Here's how I am adding a childVC:
#implementation Test2ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)showChildVC:(id)sender
{
TestTableViewController *tVC = [[TestTableViewController alloc]init];
tVC.view.frame = CGRectMake(50, 50, 200, 200);
[self addChildViewController:tVC];
[self.view addSubview:tVC.view];
[tVC didMoveToParentViewController:self];
}
And this is the childVC that I want to show: .h
#import <UIKit/UIKit.h>
#interface TestTableViewController : UIViewController<UITableViewDataSource>
{
NSArray *array;
}
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
And: .m
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
array = [NSArray arrayWithObjects:#"One",#"Two",#"Three",#"Four", nil];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [array objectAtIndex:indexPath.row];
return cell;
}
I see your table view in the second view controller is an IBOutlet, so you are placing it in Storyboard.
Then when you instantiate it, you can't do: [[TestTableViewController alloc]init]; you have to do:
[storyBoard instantiateViewControllerWithIdentifier:#"tVCStoryBoardID"];