When I load my tableView, the images change sizes as I filter through the uisegmentedcontrol.
Here is the code for my tableView (I have the fixed constraints for the UIImageView's width and height, but somehow they aren't adhered to):
#import "ScheduleTableViewController.h"
#import "TFHpple.h"
#import "Game.h"
#import "ScheduleCellTableViewCell.h"
#import "GameModel.h"
#define team #"Muskegon"
#interface ScheduleTableViewController ()
{
GameModel *_homeModel;
}
#property (nonatomic, strong) UISegmentedControl *segmentedControl;
#property (nonatomic, strong) NSMutableArray *omahaHomeGames;
#property (nonatomic, strong) NSMutableArray *omahaAwayGames;
#property (nonatomic, strong) NSMutableArray *omahaAllGames;
#property (nonatomic, strong) NSArray *objects;
#property UIActivityIndicatorView *spinner;
#end
#implementation ScheduleTableViewController
-(void)itemsDownloaded:(NSArray *)items
{
// This delegate method will get called when the items are finished downloading
// Filter through all the games for the games that contain Omaha as a home team and add them to the property omahaHomeGames
for (Game *game in items) {
if ([game.homeTeam containsString:team]) {
[_omahaHomeGames addObject:game];
}
}
// Filter through all the games for the games that contain Omaha as an away team and add them to the property omahaAwayGames
for (Game *game in items) {
if ([game.awayTeam containsString:team]) {
[_omahaAwayGames addObject:game];
}
}
// Filter through all the games for the games that contain Omaha as a home or away team and add them to the property omahaAllGames
for (Game *game in items) {
if ([game.homeTeam containsString:team] || [game.awayTeam containsString:team]) {
[_omahaAllGames addObject:game];
}
}
[_spinner stopAnimating];
// Reload the table view
[self.tableView reloadData];
}
- (instancetype) initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Create new HomeModel object and assign it to _homeModel variable
_homeModel = [[GameModel alloc] init];
// Set this view controller object as the delegate for the home model object
_homeModel.delegate = self;
// Call the download items method of the home model object
[_homeModel downloadItems];
// add a segmented control to filter by Home/Away
NSArray *divisions = [[NSArray alloc] initWithObjects:#"All", #"Home", #"Away", nil];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:divisions];
segmentedControl.frame = CGRectMake(0, 0, 120, 30);
segmentedControl.tintColor = [UIColor orangeColor];
[segmentedControl addTarget:self action:#selector(filterByHomeAway:) forControlEvents:UIControlEventValueChanged];
segmentedControl.selectedSegmentIndex = 0;
self.navigationItem.titleView = segmentedControl;
self.segmentedControl = segmentedControl;
// alloc and init properties
self.omahaAllGames = [[NSMutableArray alloc] init];
self.omahaHomeGames = [[NSMutableArray alloc] init];
self.omahaAwayGames = [[NSMutableArray alloc] init];
}
return self;
}
- (IBAction)filterByHomeAway:(id)sender
{
NSLog(#"Filter: %ld", (long)self.segmentedControl.selectedSegmentIndex);
[self.tableView reloadData];
}
- (void)viewDidLoad {
[super viewDidLoad];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
spinner.center = CGPointMake(screenWidth/2.0, screenHeight/5.0);
spinner.hidesWhenStopped = YES;
[self.view addSubview:spinner];
[spinner startAnimating];
self.spinner = spinner;
// Load the Cell NIB file
UINib *nib = [UINib nibWithNibName:#"ScheduleCellTableViewCell" bundle:nil];
// Register this NIB, which contains the cell
[self.tableView registerNib:nib forCellReuseIdentifier:#"ScheduleCell"];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section {
// Return the number of rows in the section.
if (self.segmentedControl.selectedSegmentIndex == 0) {
return (self.omahaAllGames.count);
}
if (self.segmentedControl.selectedSegmentIndex == 1) {
return (self.omahaHomeGames.count);
}
if (self.segmentedControl.selectedSegmentIndex == 2) {
return self.omahaAwayGames.count;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Get a new or recycled cell
ScheduleCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ScheduleCell" forIndexPath:indexPath];
if (self.segmentedControl.selectedSegmentIndex == 0) {
_objects = _omahaAllGames;
}
if (self.segmentedControl.selectedSegmentIndex == 1) {
_objects = _omahaHomeGames;
}
if (self.segmentedControl.selectedSegmentIndex == 2) {
_objects = _omahaAwayGames;
}
// Configure the cell
Game *thisGame = [_objects objectAtIndex:indexPath.row];
if (self.segmentedControl.selectedSegmentIndex == 0) {
cell.versusLabel.text = [NSString stringWithFormat:#"%# vs. %#", thisGame.homeTeam, thisGame.awayTeam];
}
if (self.segmentedControl.selectedSegmentIndex == 1) {
cell.versusLabel.text = [NSString stringWithFormat:#"%# vs. %#", team, thisGame.awayTeam];
}
if (self.segmentedControl.selectedSegmentIndex == 2) {
cell.versusLabel.text = [NSString stringWithFormat:#"%# vs. %#", team, thisGame.homeTeam];
}
// Trim the white space from before and after the date/time
NSString *day = [thisGame.dayString substringFromIndex: 8];
NSString *dayModified = [day substringWithRange: NSMakeRange(0, 11)];
NSString *time = [thisGame.timeString substringFromIndex:9];
NSString *timeModified = [time substringWithRange: NSMakeRange(0, 8)];
NSString *dateAndTime = [NSString stringWithFormat:#"%# %#", dayModified, timeModified];
cell.dateLabell.text = dateAndTime;
cell.locationLabel.text = thisGame.arena;
// Assign the image of the away team if home, and the home team if away, and the team that isn't Omaha if all
if (self.segmentedControl.selectedSegmentIndex == 0) {
[thisGame assignAllTeamImage];
cell.imageView.image = thisGame.image;
}
if (self.segmentedControl.selectedSegmentIndex == 1) {
[thisGame assignHomeTeamImage];
cell.imageView.image = thisGame.image;
}
if (self.segmentedControl.selectedSegmentIndex == 2) {
[thisGame assignAwayTeamImage];
cell.imageView.image = thisGame.image;
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 70;
}
#end
How do I make them stay a consistent size? I just can't seem to make it work. Thank you.
Instead of displaying the image in the default imageView of cell, try creating a new imageView and adding it to the cell.
UIImageView *imageViewIcon = [[UIImageView alloc] initWithFrame:CGRectMake(5, 0, 50, 50)];
[cell addSubview:imageViewIcon];
if (self.segmentedControl.selectedSegmentIndex == 0) {
[thisGame assignAllTeamImage];
//cell.imageView.image = thisGame.image;
imageViewIcon.image = thisGame.image;
}
if (self.segmentedControl.selectedSegmentIndex == 1) {
[thisGame assignHomeTeamImage];
//cell.imageView.image = thisGame.image;
imageViewIcon.image = thisGame.image;
}
if (self.segmentedControl.selectedSegmentIndex == 2) {
[thisGame assignAwayTeamImage];
//cell.imageView.image = thisGame.image;
imageViewIcon.image = thisGame.image;
}
In the above code change the frame of the imageViewIcon as per your requirement.
And since you are using dequeueReusableCellWithIdentifier don't forget to give the imageViewIcon a tag and remove it at the beginning.
Hope this helps you. :)
Related
i am doing feedback form using UITableview in that using custom checkbox for selection.In a UITableviewcell i placed four static buttons for options like,Very
Good,Good,Average,Below Average.
What i want is,i want to select only one button checked in a row, if i select another button checked automatically previous selected button should be unchecked.
Example: In same row suppose if i select Very Good first again i selected Average , previous selected Very Good should be unchecked.
Check My code Below for reference:
This is in cellforrowatindexpath
[cell.R1_BTN setImage:[UIImage imageNamed:#"Touch_G.png"] forState:UIControlStateNormal];
[cell.R1_BTN addTarget:self action:#selector(BtnClicked:) forControlEvents:UIControlEventTouchUpInside];
cell.R1_BTN.tag=1;
Click event here..
-(void)BtnClicked:(id)sender
{
//Need Code Here..
}
updated code for reference..
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [GNM count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [GNM objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([[NM objectAtIndex:section] isKindOfClass:[NSArray class]])
{
return [[NM objectAtIndex:section] count];
}
else
{
return 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FeedBackFormTVC *cell = [FeedBack_TV dequeueReusableCellWithIdentifier:#"ListCell" forIndexPath:indexPath];
cell.FBName_LBL.text = [[NM objectAtIndex:indexPath.section] isKindOfClass:[NSArray class]]
? [[NM objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]
: [NM objectAtIndex:indexPath.section];
// below for assigning code action event..
....
....
...
}
I tried using Tags,but i didn't get what i want, pls help me.. thanks in Advance.
I think that you should use model to set for UITableViewCell. Your model's .h file like :
#import <Foundation/Foundation.h>
typedef enum : NSInteger {
UNKNOWN = 0,
VERY_GOOD = 1,
GOOD = 2,
AVERAGE = 3,
BELOW_AVERAGE = 4
}RangeMark;
#interface CellModel : NSObject
#property(nonatomic, assign) RangeMark range;
#end
.m file like:
#import "CellModel.h"
#implementation CellModel
#end
than you should init a table cell with .xib file looks like:
and its .h file like :
#import <UIKit/UIKit.h>
#import "CellModel.h"
#interface TableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *veryGoodButton;
#property (weak, nonatomic) IBOutlet UIButton *goodButton;
#property (weak, nonatomic) IBOutlet UIButton *averageButton;
#property (weak, nonatomic) IBOutlet UIButton *belowAverageButton;
- (void)setupCellWithModel:(CellModel*)model;
#end
its .m file like :
#import "TableViewCell.h"
#implementation TableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)setupCellWithModel:(CellModel *)model {
if(model.range == VERY_GOOD) {
self.veryGoodButton.backgroundColor = [UIColor greenColor];
}
else if(model.range == GOOD) {
self.goodButton.backgroundColor = [UIColor blueColor];
}
else if(model.range == AVERAGE) {
self.averageButton.backgroundColor = [UIColor yellowColor];
}
else if(model.range == BELOW_AVERAGE) {
self.belowAverageButton.backgroundColor = [UIColor redColor];
}
}
- (void)prepareForReuse {
[super prepareForReuse];
self.veryGoodButton.backgroundColor = [UIColor lightGrayColor];
self.goodButton.backgroundColor = [UIColor lightGrayColor];
self.averageButton.backgroundColor = [UIColor lightGrayColor];
self.belowAverageButton.backgroundColor = [UIColor lightGrayColor];
}
#end
Finally your view controller .h file should look like :
#import <UIKit/UIKit.h>
#import "TableViewCell.h"
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
and .m file should look like :
#import "ViewController.h"
#interface ViewController () <UITableViewDelegate, UITableViewDataSource>{
NSMutableArray<CellModel*> *modelList;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 600;
self.tableView.rowHeight = UITableViewAutomaticDimension;
modelList = [NSMutableArray<CellModel*> new];
for (int i=0; i<50; i++) {
CellModel *cellModel = [[CellModel alloc] init];
cellModel.range = UNKNOWN;
[modelList addObject:cellModel];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
TableViewCell *cell = (TableViewCell*)[tableView dequeueReusableCellWithIdentifier:#"TableViewCell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
[cell setupCellWithModel:[modelList objectAtIndex:indexPath.row]];
cell.veryGoodButton.tag = indexPath.row;
cell.goodButton.tag = indexPath.row;
cell.averageButton.tag = indexPath.row;
cell.belowAverageButton.tag = indexPath.row;
[cell.veryGoodButton addTarget:self action:#selector(veryGood:) forControlEvents:UIControlEventTouchUpInside];
[cell.goodButton addTarget:self action:#selector(good:) forControlEvents:UIControlEventTouchUpInside];
[cell.averageButton addTarget:self action:#selector(average:) forControlEvents:UIControlEventTouchUpInside];
[cell.belowAverageButton addTarget:self action:#selector(belowAverage:) forControlEvents:UIControlEventTouchUpInside];
return cell;
return nil;
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return modelList.count;
}
- (void) veryGood:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = VERY_GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void) good:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void) average:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void) belowAverage:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = BELOW_AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void)setCellDynamicly:(NSIndexPath*)indexPath withCellModel:(CellModel*)cellModel {
TableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell prepareForReuse];
[cell setupCellWithModel:cellModel];
}
#end
that s all :)
At the end app looks like :
yes this will be a solution for you, at least I hope like this :)
first of all create a custom button .h file like this :
#import <UIKit/UIKit.h>
#interface CustomButton : UIButton
#property (assign) NSInteger sectionTag;
#property (assign) NSInteger rowTag;
#end
custom button .m file like this :
#import "CustomButton.h"
#implementation CustomButton
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
#end
then I changed a few things in TableViewCell .h file like this :
#import <UIKit/UIKit.h>
#import "CellModel.h"
#import "CustomButton.h"
#interface TableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet CustomButton *veryGoodButton;
#property (weak, nonatomic) IBOutlet CustomButton *goodButton;
#property (weak, nonatomic) IBOutlet CustomButton *averageButton;
#property (weak, nonatomic) IBOutlet CustomButton *belowAverageButton;
#property (weak, nonatomic) IBOutlet UILabel *itemLabel;
- (void)setupCellWithModel:(CellModel*)model;
#end
TableViewCell .m file like this :
#import "TableViewCell.h"
#implementation TableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)setupCellWithModel:(CellModel *)model {
if(model.range == VERY_GOOD) {
self.veryGoodButton.backgroundColor = [UIColor greenColor];
}
else if(model.range == GOOD) {
self.goodButton.backgroundColor = [UIColor blueColor];
}
else if(model.range == AVERAGE) {
self.averageButton.backgroundColor = [UIColor yellowColor];
}
else if(model.range == BELOW_AVERAGE) {
self.belowAverageButton.backgroundColor = [UIColor redColor];
}
[self.itemLabel setText:model.itemText];
}
- (void)prepareForReuse {
[super prepareForReuse];
self.veryGoodButton.backgroundColor = [UIColor lightGrayColor];
self.goodButton.backgroundColor = [UIColor lightGrayColor];
self.averageButton.backgroundColor = [UIColor lightGrayColor];
self.belowAverageButton.backgroundColor = [UIColor lightGrayColor];
}
and its .xib like this :
on the other side, there is only one change on CellModel .h file like this :
#import <Foundation/Foundation.h>
typedef enum : NSInteger {
UNKNOWN = 0,
VERY_GOOD = 1,
GOOD = 2,
AVERAGE = 3,
BELOW_AVERAGE = 4
}RangeMark;
#interface CellModel : NSObject
#property(nonatomic, assign) RangeMark range;
#property(nonatomic, copy) NSString* itemText;
- (id)initWith:(NSString*)itemText withRangeMark:(RangeMark)range;
#end
and its .m file like this :
#import "CellModel.h"
#implementation CellModel
- (id)initWith:(NSString*)itemText withRangeMark:(RangeMark)range {
self = [super init];
if(self) {
self.itemText = itemText;
self.range = range;
}
return self;
}
#end
finally view controller .h file same but .m like this :
#import "ViewController.h"
#interface ViewController () <UITableViewDelegate, UITableViewDataSource>{
NSMutableArray *modelList;
NSMutableArray<NSString*> *sectionTitleList;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 600;
self.tableView.rowHeight = UITableViewAutomaticDimension;
sectionTitleList = [NSMutableArray<NSString*> new];
[sectionTitleList addObject:#"RESERVATION"];
[sectionTitleList addObject:#"FRONT DESK"];
[sectionTitleList addObject:#"CASHIER"];
[sectionTitleList addObject:#"HOUSE KEEPING"];
modelList = [[NSMutableArray alloc] initWithCapacity: 4];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Service Speed" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Good Speed" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Confirmation Quality" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Quick Service in Reservetion" withRangeMark:UNKNOWN],nil] atIndex:0];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Check In" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Happy on Their Service" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Coutesey" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Quick Service at Check In" withRangeMark:UNKNOWN],nil] atIndex:1];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Front Office & Reception" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Overall Quality of Room" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Check" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Response Time" withRangeMark:UNKNOWN],nil] atIndex:2];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Room Decor" withRangeMark:UNKNOWN],nil] atIndex:3];
// [modelList addObject: [[CellModel alloc] initWith:#"Service Speed" withRangeMark:UNKNOWN]];
// [modelList addObject: [[CellModel alloc] initWith:#"Good Speed" withRangeMark:UNKNOWN]];
// [modelList addObject: [[CellModel alloc] initWith:#"Confirmation Quality" withRangeMark:UNKNOWN]];
// [modelList addObject: [[CellModel alloc] initWith:#"Quick Service in Reservetion" withRangeMark:UNKNOWN]];
// for (int i=0; i<5; i++) {
// CellModel *cellModel = [[CellModel alloc] init];
// cellModel.range = UNKNOWN;
// cellModel.itemText = #"";
// [modelList addObject:cellModel];
// }
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
TableViewCell *cell = (TableViewCell*)[tableView dequeueReusableCellWithIdentifier:#"TableViewCell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSLog(#"section: %ld - row : %ld - item text : %#", (long)indexPath.section, (long)indexPath.row, ((CellModel*)[[modelList objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]).itemText);
[cell setupCellWithModel:[[modelList objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]];
((CustomButton*)cell.veryGoodButton).rowTag = indexPath.row;
((CustomButton*)cell.veryGoodButton).sectionTag = indexPath.section;
((CustomButton*)cell.goodButton).rowTag = indexPath.row;
((CustomButton*)cell.goodButton).sectionTag = indexPath.section;
((CustomButton*)cell.averageButton).rowTag = indexPath.row;
((CustomButton*)cell.averageButton).sectionTag = indexPath.section;
((CustomButton*)cell.belowAverageButton).rowTag = indexPath.row;
((CustomButton*)cell.belowAverageButton).sectionTag = indexPath.section;
[cell.veryGoodButton addTarget:self action:#selector(veryGood:) forControlEvents:UIControlEventTouchUpInside];
[cell.goodButton addTarget:self action:#selector(good:) forControlEvents:UIControlEventTouchUpInside];
[cell.averageButton addTarget:self action:#selector(average:) forControlEvents:UIControlEventTouchUpInside];
[cell.belowAverageButton addTarget:self action:#selector(belowAverage:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[modelList objectAtIndex:section] count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sectionTitleList.count;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, tableView.frame.size.width, 18)];
[label setFont:[UIFont boldSystemFontOfSize:12]];
[label setTextColor:[UIColor whiteColor]];
NSString *string =[sectionTitleList objectAtIndex:section];
[label setText:string];
[view addSubview:label];
[view setBackgroundColor:[UIColor darkGrayColor]];
return view;
}
- (void) veryGood:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = VERY_GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void) good:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void) average:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void) belowAverage:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = BELOW_AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void)setCellDynamicly:(NSIndexPath*)indexPath withCellModel:(CellModel*)cellModel {
TableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell prepareForReuse];
[cell setupCellWithModel:cellModel];
}
#end
I think that it will work fine for you. Just do some change part of array init on code to dynamic :)
last appearance :
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 600;
self.tableView.rowHeight = UITableViewAutomaticDimension;
sectionTitleList = [NSMutableArray<NSString*> new];
for (NSString* sectionTitle in yourSectionResponseArray) {
[sectionTitleList addObject: sectionTitle];
}
modelList = [[NSMutableArray alloc] initWithCapacity: [sectionTitleList count]];
//your row title array has to be 2D array.
for(int i = 0; i < [sectionTitleList count]; i++) {
NSMutableArray* rowStringArray = [NSMutableArray new];
for(NSString* rowTitle in [your2DRowResponseArray objectAtIndex:i]) {
[rowStringArray addObject: rowTitle];
}
[modelList insertObject: rowStringArray];
}
}
May be this can help you.
Since you haven't provided us the API response details as requested earlier we are forced to use static value. Please replace sectionTitleList & modelList from the array API response. Please find the below code to be used to assign you API response to model created by #Gökhan Aydın .
sectionTitleList = #[#"RESERVATION",#"FRONT DESK",#"CASHIER",#"HOUSE KEEPING",#"COMMON"];
modelList = #[
#[
#"Service Speed",
#"Good Service",
#"Confirmation quality",
#"Quick Service in Reservation"
],
#[
#"Check In",
#"Happy on their Service",
#"Courtesey",
#"Quick Service at Checkin"
],
#[
#"Front office & reception",
#"Overall Quality of Room",
#"Check",
#"Response time"
],
#[
#"Room Decor",
#"Time taken to serveTime taken to serveTime taken t",
#"Bathroom",
#"Facilities in the Room",
#"Choice of menu",
#"Housekeeping",
#"Room Service"
],
#[
#"Overall Comments",
#"Will you come back again"
]
];
self.navigationItem.title = [modelList lastObject];
GNM = [sectionTitleList mutableCopy];
NM = [[NSMutableArray alloc]init];
for (NSArray *feedbacktitles in modelList) {
if ([feedbacktitles isKindOfClass:[NSArray class]]) {
__block NSMutableArray *tempArray = [NSMutableArray new];
[feedbacktitles enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL * _Nonnull stop) {
FeedbackModel *model = [[FeedbackModel alloc]initWith:title withRangeMark:UNKNOWN];
[tempArray addObject:model];
if (idx == [feedbacktitles count] - 1 ) {
*stop = TRUE;
[self->NM addObject:tempArray];
tempArray = [NSMutableArray new];
}
}];
}
}
or by simple for loop
for (NSArray *feedbacktitles in modelList) {
NSLog(#"%#",feedbacktitles);
NSMutableArray* rowStringArray = [NSMutableArray new];
if ([feedbacktitles isKindOfClass:[NSArray class]]) {
for(int i = 0; i < [feedbacktitles count]; i++) {
NSString* rowTitle = [feedbacktitles objectAtIndex:i];
FeedbackModel *model = [[FeedbackModel alloc]initWith:rowTitle withRangeMark:UNKNOWN];
[rowStringArray addObject: model];
if (i == [feedbacktitles count] - 1) {
[NM addObject: rowStringArray];
rowStringArray = [NSMutableArray new];
}
}
}
}
I have a UITableView for an Instagram feed. I have implemented UIRefreshControl for pull to refresh functionality.
After drag and release the refresh control, and while the spinner is going, I'm able to drag the tableview down without the app crashing. However, if I scroll the tableview upwards, the app crashes (maybe because of cell 2, 3 etc?)
Here's a video showing the problem: http://www.screenmailer.com/v/DukT4lt2aUGm8c5MLRlGMg/2586/3a23tXo7uXs.mp4
Why is this happening?
Code for the .m file:
#import "InstagramViewController.h"
#import "InstagramCell.h"
#import <InstagramKit/InstagramKit.h>
#import "UIImageView+AFNetworking.h"
#interface InstagramViewController ()
{
NSMutableArray *mediaArray;
}
#property (nonatomic, strong) InstagramPaginationInfo *currentPaginationInfo;
#end
#implementation InstagramViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
//mediaArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void)viewDidLoad
{
mediaArray = [[NSMutableArray alloc] init];
[super viewDidLoad];
[self loadMedia];
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(reloadMedia) forControlEvents:UIControlEventValueChanged];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
-(void)reloadMedia
{
self.currentPaginationInfo = nil;
[mediaArray removeAllObjects];
[self loadMedia];
}
-(IBAction)loadMedia
{
// start network indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[[InstagramEngine sharedEngine] getMediaWithTagName:#"AUFsommer" count:10 maxId:self.currentPaginationInfo.nextMaxId withSuccess:^(NSArray *media, InstagramPaginationInfo *paginationInfo) {
if (paginationInfo)
{
self.currentPaginationInfo = paginationInfo;
}
[mediaArray addObjectsFromArray:media];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self reloadData];
} failure:^(NSError *error) {
NSLog(#"Search Media Failed");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}];
}
-(void)reloadData
{
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] init];
headerView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.9f];
InstagramMedia *media = mediaArray[section];
// create imageview for profile photo
AsyncImageView *profilePhoto = [[AsyncImageView alloc] initWithFrame:CGRectMake(8, 8, 32, 32)];
profilePhoto.layer.borderColor = [[UIColor colorWithRed:204.0/255.0f green:204.0/255.0f blue:204.0/255.0f alpha:1.0f] CGColor];
profilePhoto.layer.borderWidth = 1;
profilePhoto.layer.masksToBounds = YES;
profilePhoto.layer.cornerRadius = 16.0;
[profilePhoto loadImageFromURL:[media.user.profilePictureURL absoluteString]];
// uifont settings
UIFont *labelFont = [UIFont boldSystemFontOfSize:13.0];
// create label for username
UILabel *usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(48, 0, 210, 48)];
usernameLabel.text = media.user.username;
usernameLabel.font = labelFont;
usernameLabel.textColor = [UIColor colorWithRed:235.0/255.0 green:24.0/255.0 blue:22.0/255.0 alpha:1.0f];
// create label for timestamp
UILabel *timestampLabel = [[UILabel alloc] initWithFrame:CGRectMake(250, 0, 54, 48)];
timestampLabel.textAlignment = NSTextAlignmentRight;
timestampLabel.font = labelFont;
// timestampLabel.text = [self stringForDisplayFromDate:media.createdDate];
// add to view
[headerView addSubview:profilePhoto];
[headerView addSubview:usernameLabel];
[headerView addSubview:timestampLabel];
return headerView;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return mediaArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
InstagramCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[InstagramCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// clear photo
[cell.igPhoto setImage:nil];
if (mediaArray.count >= indexPath.section+1)
{
InstagramMedia *media = mediaArray[indexPath.section];
cell.title.text = media.caption.text;
[cell.igPhoto loadImageFromURL:[media.standardResolutionImageURL absoluteString]];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
InstagramMedia *media = mediaArray[indexPath.section];
CGSize maximumLabelSize = CGSizeMake(304.0f, 20000.0f);
CGSize expectedLabelSize = [media.caption.text sizeWithFont:[UIFont systemFontOfSize:13.0f] constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping];
return (320.0f + expectedLabelSize.height + 20.0f);
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
CGFloat currentOffset = scrollView.contentOffset.y;
CGFloat maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
if (maximumOffset - currentOffset < 10.0)
{
[self loadMedia];
}
}
#end
The first thing you should do is to add an exception breakpoint in your project, so you will know why and where it crashes.
The reason why your app is crashing is that you try to read in an empty array. In the method reloadMedia, you do this :
self.currentPaginationInfo = nil;
[mediaArray removeAllObjects];
So at this point, your array is empty, but your UITableView is not aware of that. By scrolling before your data is reloaded, the methods cellForRowAtIndexPath will get called and try to access an index in your empty array.
To fix this, you can call [self.tableView reloadData]; after [mediaArray removeAllObjects];. This way, the UITableView will makes its call to know how many rows and sections it should have and will be aware there is no more rows and sections.
Or, if you want the old information to still be in your UITableView during the loading, just don't nil the currentPaginationInfo or empty mediaArray in reloadMedia,
This question already has answers here:
UITableView cells strangely disappearing
(2 answers)
Closed 9 years ago.
Very strange problem here.
Essentially what is happening is that our Tableview cells are becoming hidden in some cases when we simply put the app to sleep and then re-unlock. Our normal tableview looks like this:
And then when we re-open the app it will look like this:
All the rows and sections are set correctly, yet the cells are hidden.:
When this happens, our cellForRowAtIndexPath no longer gets called. This surely has to be the problem. Has anyone ever seen behavior like this? Here is how we set up the tableview. (sorry it is long)
//
// SPHomeViewController.m
// Spek
#interface SPHomeViewController () <UITableViewDataSource, UITableViewDelegate, MKMapViewDelegate, SPCreationViewDelegate, UIAlertViewDelegate, CLLocationManagerDelegate>
#property (nonatomic, strong) UITableView* tableView;
#property (nonatomic, strong) NSMutableArray* tableDatasource;
#property (nonatomic, strong) NSMutableArray* datasource;
#property (nonatomic, strong) NSMutableArray* friendsDatasource;
#property (nonatomic, strong) UISegmentedControl* userFilterSegment;
#property (nonatomic) BOOL isLoadingData;
#end
#implementation SPHomeViewController
#synthesize datasource = _datasource;
#synthesize friendsDatasource = _friendsDatasource;
#synthesize tableDatasource = _tableDatasource;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
//[[SPLocationManager locationManager] startUpdatingLocationForSig];
[self setNeedsStatusBarAppearanceUpdate];
self.view.backgroundColor = [UIColor colorWithRed:230.0f/255.0f green:230.0f/255.0f blue:230.0f/255.0f alpha:1.0];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - kTopBarHeight)];
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
if (self.creationView.center.y > self.view.frame.size.height) {
self.creationView = nil;
}
NSLog(#"Mem warning");
}
//****************************************
//****************************************
#pragma mark - UITableViewDelegate/DataSource
//****************************************
//****************************************
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"INDEX PATH ROW: %d AND SECTION: %d", indexPath.row, indexPath.section);
if (indexPath.section == 0) {
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SPMapCellSpace"];
cell.backgroundColor = [UIColor clearColor];
cell.backgroundView = [[UIView alloc] init];
cell.selectedBackgroundView = [[UIView alloc] init];
return cell;
} else if (indexPath.section == self.tableDatasource.count + 1) {
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SPBottomCellSpace"];
cell.backgroundColor = [UIColor clearColor];
cell.backgroundView = [[UIView alloc] init];
cell.selectedBackgroundView = [[UIView alloc] init];
return cell;
}
SPMark* mark = self.tableDatasource[indexPath.section - 1];
NSString* reuseId = [SPHomeViewController cellIdentifierFromData:mark];
SPTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseId];
if (cell == nil) {
cell = [SPTableViewCell cellFromMark:mark reuseID:reuseId];
[cell updateView:YES];
}
[cell addDataToCell:mark];
if (indexPath.section >= self.tableDatasource.count - 2 && !self.isLoadingData && self.pageNumber != -1) {
self.fetchNextPage = YES; // When the scrollview stops it will load more data if available.
}
return cell;
}
- (unsigned int)getPageNumber {
return (self.userFilterSegment.selectedSegmentIndex == 0) ? self.pageNumber : self.friendsPageNumber;
}
- (void)setCurrentPageNumber:(unsigned int)page {
if (self.userFilterSegment.selectedSegmentIndex == 0) {
self.pageNumber = page;
} else {
self.friendsPageNumber = page;
}
}
- (void)incrementCurrentPageNumber {
if (self.userFilterSegment.selectedSegmentIndex == 0) {
self.pageNumber++;
} else {
self.friendsPageNumber++;
}
}
// Every cell has a section header so this should be equal to the number of speks returned from the server
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"section count is: %d",self.tableDatasource.count + 2 );
return self.tableDatasource.count + 2; // Add two because the mapview needs to go on the top and extra spacing at the bottom.
}
// There is a section for every cell, so there is only one cell per section
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
return kMapHeight+2;
} else if (indexPath.section == self.tableDatasource.count + 1) {
return kExtraSpaceBelowHomeView;
}
SPMark* mark = self.tableDatasource[indexPath.section - 1];
return [SPTableViewCell cellHeightForMark:mark];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 || indexPath.section == self.tableDatasource.count + 1) {
cell.backgroundColor = [UIColor clearColor];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 || indexPath.section == self.tableDatasource.count + 1)
return;
SPMark* mark = self.datasource[indexPath.section - 1 ];
SPMarkViewController* markVC = [SPMarkViewController withMark:mark];
[markVC displayData];
[self.navigationController pushViewController:markVC animated:YES];
}
-(void)reloadTableview {
[self.tableView setDelegate:self];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[self.tableView setNeedsDisplay];
});
}
- (void)showNoItems {
if (self.tableDatasource.count == 0 && self.accuracyBad == NO) {
self.opaqueIcon.hidden = NO;
self.noItems.hidden = NO;
self.beTheFirst.hidden = NO;
self.downArrow.hidden = NO;
self.noItemsBackround.hidden = NO;
[self.view bringSubviewToFront:self.noItemsBackround];
[self.view bringSubviewToFront:self.downArrow];
[self.view bringSubviewToFront:self.beTheFirst];
[self.view bringSubviewToFront:self.noItems];
[self.view bringSubviewToFront:self.opaqueIcon];
}
}
- (void)showTableView {
if (self.tableDatasource.count != 0) {
self.noItems.hidden = YES;
self.beTheFirst.hidden = YES;
self.downArrow.hidden = YES;
self.noItemsBackround.hidden = YES;
self.opaqueIcon.hidden = YES;
[self.view sendSubviewToBack:self.noItemsBackround];
[self.view sendSubviewToBack:self.downArrow];
[self.view sendSubviewToBack:self.beTheFirst];
[self.view sendSubviewToBack:self.noItems];
[self.view sendSubviewToBack:self.opaqueIcon];
}
}
//****************************************
//****************************************
#pragma mark - Setters/Getters
//****************************************
//****************************************
- (NSMutableArray*)datasource {
if (!_datasource) {
_datasource = [NSMutableArray array];
if (!self.firstLoad) {
[self loadDataForPagination:NO];
}
}
return _datasource;
}
- (NSMutableArray*)friendsDatasource {
if (!_friendsDatasource) {
_friendsDatasource = [NSMutableArray array];
if (!self.firstLoad) {
[self loadDataForPagination:NO];
}
}
return _friendsDatasource;
}
- (NSMutableArray*)tableDatasource {
if (!_tableDatasource) {
_tableDatasource = (self.userFilterSegment.selectedSegmentIndex == 0) ? self.datasource : self.friendsDatasource;
}
return _tableDatasource;
}
- (SPCreationView*)creationView {
if (!_creationView) {
UIView* window = [SPUtils getAppDelegate].window;
CGSize viewSize = window.frame.size;
CGRect startFrame = CGRectMake(0, viewSize.height, [SPUtils screenWidth], [SPUtils screenHeight]);
_creationView = [SPCreationView creationView:startFrame delegate:self];
[window insertSubview:_creationView belowSubview:self.creationButton];
_creationView.frame = startFrame;
}
return _creationView;
}
- (void)setTableDatasource:(NSMutableArray *)tableDatasource {
_tableDatasource = tableDatasource;
[self preFetchImages];
dispatch_async(dispatch_get_main_queue(), ^{
if(_tableDatasource == nil || _tableDatasource.count == 0) {
[self showNoItems];
} else {
[self showTableView];
}
[self reloadTableview];
});
}
- (void)setDatasource:(NSMutableArray *)datasource {
_datasource = datasource;
}
- (void)setFriendsDatasource:(NSMutableArray *)friendsDatasource {
_friendsDatasource = friendsDatasource;
}
#end
If you think it's a AppDelegate problem, we don't do anything with this controller in there, so I don't see how it could be.
I've only seen this occur previously when I was reloading data (incorrectly) from a background thread. I see you're trying to push the reloads onto the main thread already.
It looks like you're flailing a bit trying to be sure updates are occurring on the main thread. You should probably just verify that your actions are occurring on main by checking [NSThread isMainThread] rather than making your code async to the main thread, making lots of async flow changes can lead to unexpected behavior.
That said, since this only happens on wake from sleep maybe you have some background mode on and you aren't updating the UI from the correct thread there?
Here's a run down of what I want to accomplish:
Main UIViewController is a UITableViewController
Tapping on a cell takes user to a new UIViewController where they can input text and save it
User can preview all the text saved on another UIViewController
When user re-arranges the table in the Main UIViewController, user can see the changes in the Preview
How can I change/move the text on the Preview UIViewController when the UITableViewController is re-arranged?
Any general approach, tips, tutorials, examples is much appreciated!
Thanks!
EDIT, Here's my code:
Singleton .h
#import <Foundation/Foundation.h>
#interface MyInformation : NSObject
{
NSMutableArray * informationArray;
NSMutableString * nameString;
NSMutableString * jobString;
}
#property (nonatomic, retain) NSMutableArray * informationArray;
#property (nonatomic, retain) NSMutableString * nameString;
#property (nonatomic, retain) NSMutableString * jobString;
+ (id)sharedInformation;
#end
Singleton .m
#import "MyInformation.h"
#implementation MyInformation
static MyInformation * _sharedMyInformation = nil;
#synthesize informationArray = _informationArray;
#synthesize nameString = _nameString;
#synthesize jobString = _jobString;
#pragma mark Singleton Methods
+ (id)sharedInformation
{
#synchronized(self)
{
if (_sharedMyInformation == nil)
{
_sharedMyInformation = [[self alloc] init];
}
}
return _sharedMyInformation;
}
- (id)init
{
if (self = [super init])
{
_nameString = [[NSMutableString alloc] init];
_jobString = [[NSMutableString alloc] init];
_informationArray = [[NSMutableArray alloc] initWithObjects:_nameString, _jobString, nil];
}
return self;
}
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
if ([[UIScreen mainScreen] bounds].size.height == 568)
{
self.aTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 1136) style:UITableViewStyleGrouped];
self.aTableView.delegate = self;
self.aTableView.dataSource = self;
[self.view addSubview:self.aTableView];
self.editBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(editButtonTapped)];
self.navigationItem.rightBarButtonItem = self.editBarButtonItem;
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.aTableView reloadData];
}
- (void)editButtonTapped
{
if (self.editing)
{
[super setEditing:NO animated:NO];
[self.aTableView setEditing:NO animated:NO];
[self.aTableView reloadData];
[self.editBarButtonItem setTitle:#"Edit"];
[self.navigationItem.rightBarButtonItem setStyle:UIBarButtonItemStylePlain];
}
else
{
[super setEditing:YES animated:YES];
[self.aTableView setEditing:YES animated:YES];
[self.aTableView reloadData];
[self.editBarButtonItem setTitle:#"Done"];
[self.editBarButtonItem setStyle:UIBarButtonItemStyleDone];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
MyInformation * myInformation = [MyInformation sharedInformation];
int count = [myInformation.informationArray count];
if (section == 0)
{
return count;
}
else if (section == 1)
{
return 1;
}
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * CellIdentifier = #"CellIdentifier";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
MyInformation * myInformation = [MyInformation sharedInformation];
if (indexPath.section == 0 && indexPath.row == 0)
{
cell.textLabel.text = [NSString stringWithFormat:#"%#", myInformation.nameString];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.section == 0 && indexPath.row == 1)
{
cell.textLabel.text = [NSString stringWithFormat:#"%#", myInformation.jobString];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.section == 1 && indexPath.row == 0)
{
cell.textLabel.text = #"Preview";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (indexPath.section == 0 && indexPath.row == 0)
{
NameViewController * name = [[NameViewController alloc] initWithNibName:#"NameViewController" bundle:nil];
[self.navigationController pushViewController:name animated:YES];
}
if (indexPath.section == 0 && indexPath.row == 1)
{
JobViewController * job = [[JobViewController alloc] initWithNibName:#"JobViewController" bundle:nil];
[self.navigationController pushViewController:job animated:YES];
}
if (indexPath.section == 1 && indexPath.row == 0)
{
PreviewViewController * preview = [[PreviewViewController alloc] initWithNibName:#"PreviewViewController" bundle:nil];
[self.navigationController pushViewController:preview animated:YES];
}
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
MyInformation * myInformation = [MyInformation sharedInformation];
NSString * item = [myInformation.informationArray objectAtIndex:sourceIndexPath.row];
[myInformation.informationArray removeObjectAtIndex:sourceIndexPath.row];
[myInformation.informationArray insertObject:item atIndex:destinationIndexPath.row];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 )
{
return YES;
}
else
{
return NO;
}
}
#end
EDIT 2:
I do not believe my array is getting updated.
Here's an example of my save code:
- (IBAction)saveButtonTapped
{
MyInformation * myInformation = [MyInformation sharedInformation];
if (_nameTextField.text == nil)
{
myInformation.nameString = #"";
}
else
{
[myInformation.nameString setString:#""];
[myInformation.nameString appendFormat:#"%#", _nameTextField.text];
}
[self.navigationController popToRootViewControllerAnimated:YES];
}
In this log, the nameString does update to whatever text I type in and save.
But my informationArray always returns as ( "", "" )
EDIT 3 & 4:
Hard coding the strings in the singleton with set characters.
Now I can rearrange my table which is good.
Below is the updated code. The labels on the preview page will rearrange when I rearrange the table.
Here's that code:
- (void)viewDidLoad
{
[super viewDidLoad];
MyInformation * myInformation = [MyInformation sharedInformation];
_nameLabel = [[UILabel alloc] init];
_nameLabel.frame = CGRectMake(20, 20, 300, 44);
_nameLabel.text = [NSString stringWithFormat:#"%#", [myInformation.informationArray objectAtIndex:0]];
_jobLabel = [[UILabel alloc] init];
_jobLabel.frame = CGRectMake(50, 50, 300, 44);
_jobLabel.text = [NSString stringWithFormat:#"%#", [myInformation.informationArray objectAtIndex:1]];
[self.view addSubview:_nameLabel];
[self.view addSubview:_jobLabel];
}
EDIT 5:
The only thing left to accomplish is how do I update the text in the strings in the singleton and in the UITableViewCells?
EDIT 6:
I solved the issue. I had to change the strings in the Singleton to NSMutableStrings. I modified my save button code to set the string to an empty value and the append it with the textfield text. After this it now works as expected!
Thank you for the help and suggestions!
I am assuming you have a backing NSMutableArray, but the answer should generalize to any data storage scheme.
Use tableView:moveRowAtIndexPath:toIndexPath: to detect when the user reorders the first table and update the backing array by removing the object at fromIndexPath.row and inserting it at toIndexPath.row. This makes sure that your backing models accurately reflect the changes the user just made in the UI.
When the user moves to the preview view, that view either needs to pull from the same shared data source (the one we modified in #1) or be given a copy of the just rearranged array. The latter case is simpler and can be done by adding an NSArray property on the preview controller: #property(nonatomic, copy) NSArray *itemsToPreview. Then ensure that the preview controller uses that array instead of the original one.
Apple's documentation on reordering table views is a good resource.
In iOS for the iPhone I want to make a control with similar appearance and behavior to the android spinner control when configured to behave like a drop down list box. Specifically when pressed a modal list of text options with radio buttons comes up and when one of them is pressed the list disappears and the control updates to that choice. Example:
So far I have seen a full-screen option using [self presentViewController...] with a custom ViewController but I want a partial screen (like pictured above) solution. Does anyone know how to do this or could point in the right direction.
The native solution to this will be a UIActionSheet which on iPhone will appear from the bottom and be partial screen or on iPad be very similar to the android version.
You can find the documentation here: UIActionSheet
if you didnt want to use the UIActionSheet and you wanted to make it reusable rather than adding a whole bund of UIViews to your current XIB, you could create a custom UIView with whatever interface you would need to populate it and use the interface builder to help make it look ok.
that view could have a message handler that posts the response that you would need to listen for.
then just init and load the view into your subviews and populate it
then post a message from the custom view to the handler you registered
so for your custom view you would have something like this.
#implementation SomeCustomView
+(SomeCustomView*)viewFromNibNamed:(NSString *)nibName{
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
SomeCustomView *customView = nil;
NSObject* nibItem = nil;
while ((nibItem = [nibEnumerator nextObject]) != nil) {
if ([nibItem isKindOfClass:[AADropDown class]]) {
customView = (SomeCustomView*)nibItem;
break;
}
}
return customView;
}
-(void)someInitializationWith:(NSArray*)repeatableData andNotificationId:(NSString*)noteId{
//set your stuff up for the view here and save the notification id
}
...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[[NSNotificationCenter defaultCenter] postNotificationName:Your_Notification_Id object:somevalue];
}
#end
and include other things, like in this case the tableview stuff or any other logic.
then in your viewcontroller you could call it like
__block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:#"customViewAction" object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
//deal with notification here
[[NSNotificationCenter defaultCenter] removeObserver: observer];
}];
SomeCustomView *cv =(SomeCustomView*) [SomeCustomView viewFromNibNamed:#"SomeCustomView"];
[cv someInitializationWith:arrayOptions andNotificationId:#"customViewAction"];
[self.view addSubview:cv];
and in your interface builder you will just need to make sure that the class of the view is set to your class type.
then you can easily reuse this code again whenever a user needs to select something else in the same manner.
Here is a variation on the solution suggested by AtomRiot.
On your view (xib or storyboard) make a button and assign this graphic to it. Don't worry if it appears stretched out in the editor. The code will make it a realizable graphic.
2X version
Then include the following files in your project (copied below):
DDLBHelper.h
DDLBHelper.m
Then in your ViewController's .h file make links to the button:
#property (weak, nonatomic) IBOutlet UIButton *ddlbB;
- (IBAction)ddlbBClick:(id)sender;
In you ViewController's .m file make the following calls:
#synthesize ddlbB, choiceLabel;
DDLBHelper *mDDLBH;
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *strings = [[NSArray alloc] initWithObjects:#"Item 1", #"Item 2", #"Item 3", nil];
mDDLBH = [[DDLBHelper alloc] initWithWithViewController:self button:ddlbB stringArray:strings currentValue:1];
}
- (IBAction)ddlbBClick:(id)sender {
[mDDLBH popupList];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[mDDLBH adjustToRotation];
}
Works just like android.
Here are the files:
DDLBHelper.h
// DDLBHelper.h
// Created by MindSpiker on 9/27/12.
#import <Foundation/Foundation.h>
#protocol DDLBHelperDelegate <NSObject>
#required
- (void) itemSelected: (int)value;
#end
#interface DDLBHelper : UIViewController <UITableViewDelegate, UITableViewDataSource>{
id <DDLBHelperDelegate> delegate;
}
#property (retain) id delegate;
// external interface
- (id) init;
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue;
- (void) popupList;
- (BOOL) isShown;
- (void) adjustToRotation;
- (int) getValue;
- (NSString *)getValueText;
#end
DDLBHelper.m
// DDLBHelper.m
// Created by MindSpiker on 9/27/12.
#import "DDLBHelper.h"
#import <QuartzCore/QuartzCore.h>
#interface DDLBHelper () {
#private
UIViewController *mVC;
UIButton *mButton;
NSArray *mValues;
int mValue;
UITableView *mTV;
UIView *mBackgroundV;
}
#end
#implementation DDLBHelper
#synthesize delegate;
- (id) init {
self = [super init];
mVC = nil;
mButton = nil;
mValues = nil;
mValue = -1;
return self;
}
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue {
self = [super init];
// save pointers
mVC = viewController;
mButton = button;
mValues = values;
mValue = currentValue;
[self setupButton];
return self;
}
- (void) popupList{
if (mBackgroundV == nil){
mBackgroundV = [self setupBackgroundView];
[mVC.view addSubview:mBackgroundV];
}
if (mTV == nil){
mTV = [self setupTableView];
[mVC.view addSubview:mTV];
}
[mTV reloadData];
[mBackgroundV setHidden:NO];
[mTV setHidden:NO];
}
- (BOOL) isShown{
return !mTV.isHidden;
}
- (void) adjustToRotation{
BOOL isShown = [self isShown];
// remove the controls
if (mBackgroundV != nil){
[mBackgroundV removeFromSuperview];
mBackgroundV = nil;
}
if (mTV != nil){
[mTV removeFromSuperview];
mTV = nil;
}
if (isShown){
[self popupList];
}
}
- (int) getValue{
return mValue;
}
- (NSString *) getValueText{
if (mValues != nil && mValue > -1) {
if (mValues.count > mValue){
return [mValues objectAtIndex:mValue];
}
}
return nil;
}
- (void) updateButtonTitle{
NSString *title = [NSString stringWithFormat:#" %#", [self getValueText]];
[mButton setTitle:title forState:UIControlStateNormal];
}
- (void) setupButton {
UIImage *buttonBG = [UIImage imageNamed:#"sis_proceeds_ddlb.png"];
UIEdgeInsets insets = UIEdgeInsetsMake(8, 8, 8, 45);
UIImage *sizableImg = [buttonBG resizableImageWithCapInsets:insets];
[mButton setBackgroundImage:sizableImg forState:UIControlStateNormal];
[mButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[self updateButtonTitle];
}
- (UIView *) setupBackgroundView{
UIView *v = [[UIView alloc] initWithFrame:mVC.view.bounds];
[[v layer] setOpaque:NO];
[[v layer] setOpacity:0.7f];
[[v layer] setBackgroundColor:[UIColor blackColor].CGColor];
return v;
}
- (UITableView *) setupTableView {
CGRect rect = [self makeTableViewRect];
UITableView *tv = [[UITableView alloc] initWithFrame:rect style:UITableViewStylePlain];
[tv setDelegate:self];
[tv setDataSource:self];
[tv setBackgroundColor:[UIColor whiteColor]];
[[tv layer] setBorderWidth:2];
[[tv layer] setBorderColor:[UIColor lightGrayColor].CGColor];
[[tv layer] setCornerRadius:10];
[mVC.view addSubview:tv];
return tv;
}
- (CGRect) makeTableViewRect {
float l=0.0, t=0.0, w=0.0, h=0.0, maxH=0.0, cellH=0.0, cellsH=0.0;
// get
l = mButton.frame.origin.x;
w = mButton.frame.size.width;
t = mVC.view.bounds.origin.y + 50;
maxH = mVC.view.bounds.size.height - 100;
// get cell height
UITableViewCell *c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cellH = c.bounds.size.height;
// see if list will overlow maxH(eight)
cellsH = cellH * mValues.count;
if (cellsH > maxH) {
h = maxH;
} else {
h = cellsH;
}
return CGRectMake(l, t, w, h);
}
#pragma mark - TableView Delegate functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1; // this is a one section table
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return mValues.count; // should be called for only one section
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// try to resuse a cell if possible
static NSString *RESUSE_IDENTIFIER = #"myResuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RESUSE_IDENTIFIER];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RESUSE_IDENTIFIER];
}
cell.textLabel.text = [mValues objectAtIndex:indexPath.row];
if (mValue == indexPath.row){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// save value and hide view
mValue = indexPath.row;
[self updateButtonTitle];
[mBackgroundV setHidden:YES];
[mTV setHidden:YES];
[delegate itemSelected:mValue];
}
#end