I am fairly new to objective-c and I have ran into an issue that I have had a hard time solving..
I am using ShinobiDataGrid and using their prepareCellForDisplay.
To get text to display I would do this:
if([cell.coordinate.column.title isEqualToString:#"Task"]){
textCell.textField.textAlignment = NSTextAlignmentLeft;
textCell.textField.text = cellDataObj.task;
}
but for a particular cell, I am trying to add a custom button:
if([cell.coordinate.column.title isEqualToString:#"selected"]){
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 10 , 32, 32);
if(cellDataObj.selected){
[button setImage:[UIImage imageNamed:#"checked-box.png"] forState:UIControlStateNormal];
}else{
[button setImage:[UIImage imageNamed:#"unchecked-box.png"] forState:UIControlStateNormal];
}
button.tag = cell.coordinate.row.rowIndex;
[button addTarget:self action:#selector(CheckBoxPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:button];
[button removeFromSuperview];
}
and I first run the app, the checkbox appears. but when I reload my ShinobiDataGrid the checkbox appears again. I tried removing the button from the superview, but that didn't work...any suggestions ? When I reload my ShinobiDataGrid a 3rd time, the checkbox does not appear for a 3rd time, just adds another when I reload the ShinobiDataGrid the 2nd time. Here is the whole method:
- (void)shinobiDataGrid:(ShinobiDataGrid *)grid prepareCellForDisplay:(SDataGridCell *)cell
{
SDataGridTextCell* textCell = (SDataGridTextCell*)cell;
CellData *cellDataObj = [cellHolderDisplay objectAtIndex:cell.coordinate.row.rowIndex];
textCell.textField.textAlignment = NSTextAlignmentCenter;
if([cell.coordinate.column.title isEqualToString:#"selected"]){
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 10 , 32, 32);
if(cellDataObj.selected){
[button setImage:[UIImage imageNamed:#"checked-box.png"] forState:UIControlStateNormal];
}else{
[button setImage:[UIImage imageNamed:#"unchecked-box.png"] forState:UIControlStateNormal];
}
button.tag = cell.coordinate.row.rowIndex;
[button addTarget:self action:#selector(CheckBoxPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:button];
[button removeFromSuperview];
}
if([cell.coordinate.column.title isEqualToString:#"Task"]){
textCell.textField.textAlignment = NSTextAlignmentLeft;
textCell.textField.text = cellDataObj.task;
}
if([cell.coordinate.column.title isEqualToString:#"BLine. Start"]){
textCell.textField.text = cellDataObj.baselineDate;
}
}
Any suggestions ?
Here is the CheckBoxPressed method:
- (void)CheckBoxPressed:(UIButton *)sender
{
CellData *cell = [cellHolder objectAtIndex:sender.tag];
if([cell selected] == YES)
{
[[cell actualDate]setString:#""];
[[cell finishedDate] setString:#""];
[cell setSelected:NO];
}
else
{
if(([[cell actualDate] isEqualToString:#""]) && ([[cell finishedDate] isEqualToString:#""]))
{
[[cell actualDate]setString:[NSString stringWithFormat:#"%# 8:00:00 AM",[self SetSpecialDateFormat:[NSDate date]]]];
[[cell finishedDate]setString:[NSString stringWithFormat:#"%# 4:00:00 PM",[self SetSpecialDateFormat:[NSDate date]]]];
}
//actual date not populated but finish date populated
else if(([[cell actualDate]isEqualToString:#""]) && !([[cell finishedDate] isEqualToString:#""]))
{
[[cell actualDate]setString:[cell finishedDate]];
}
//finish date not populated but actual date populated
else if(!([[cell actualDate] isEqualToString:#""]) && ([[cell finishedDate] isEqualToString:#""]))
{
[[cell finishedDate]setString:[cell actualDate]];
}
[cell setSelected:YES];
}
[self UpdateEdittedCells:cell];
[self SetDisplayHolder];
//refresh grid
[gridReference reload];
}
(It's not entirely clear what effect you're after here, so I'm assuming that you would like to have a column filled with checkboxes, which are either checked or un-checked according to your data model)
The problem you are encountering is that the shinobi data grid re-uses cells, in order to optimise the memory usage. Therefore adding a button to a cell will mean that the button will be there as the cell is reused (when the grid is reloaded or scrolled).
You could remove the contents of the cell at the beginning of prepareCellForDisplay:, and then you'd have an empty cell to which you can add your button:
- (void)shinobiDataGrid:(ShinobiDataGrid *)grid prepareCellForDisplay:(SDataGridCell *)cell
{
if([cell.coordinate.column.title isEqualToString:#"selected"]){
NSArray *cellSubviews = [cell.subviews copy];
for (UIView *subview in subviews) {
[subview removeFromSuperview];
}
// Now safe to add the button
}
}
However, this isn't the best approach.
You'd be much better creating a custom cell subclass for the selected column. This cell would always have a button, and would therefore make much better use of the cell reuse mechanism.
To do this, create a subclass of SDataGridCell, and register is with the grid, in the same way as you normally would. Then, when you get a callback in prepareCellForDisplay:, you know that the type will be your custom one.
You can find specific instructions on achieving this in the ShinobiDataGrid userguide:
https://www.shinobicontrols.com/docs/ShinobiControls/ShinobiGrids/2.8.0/Standard/Normal/docs/markdown_files/DataGridUserGuide.html#How to: Creating custom cells
The example you're looking for is called "Creating custom cells", and is the last of the "How-tos", right at the bottom of the page.
This example is accompanied with a complete working sample, provided in the samples folder in the dmg that you downloaded. The difference with the sample is that it is using the datasource helper. Your code isn't, but it is fairly simple to translate the populateCell method of the data source helper into the prepareCell method you are used to using.
Related
I want to design a dynamic radio button in my app
for (int f = 0; f<arr.count; f++) {
UILabel *lbl = [[UILabel alloc]init];
lbl.frame = CGRectMake(radio_x+10,radio_y+5 , radio_w, radio_h);
lbl.text = arr[f];
lbl.textColor = [UIColor blackColor];
[self.sub_View addSubview:lbl];
self.yourButton = [[UIButton alloc] initWithFrame:CGRectMake(xPosOfTxt,radio_y , 20, 20)];
[self.yourButton setImage: [UIImage imageNamed:#"RadioButton-Selected.png"]forState:UIControlStateNormal];
[self.yourButton setImage: [UIImage imageNamed:#"RadioButton-Unselected.png"]forState: UIControlStateSelected];
[self.yourButton setTag:baseRadioTag+f];
[self.sub_View addSubview:self.yourButton];
[self.yourButton addTarget:self action:#selector(radioSelected:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)radioSelected:(UIButton*)sender {
self.yourButton.selected = false;
sender.selected = !sender.selected;
self.yourButton = sender; }
I did like this , this is working like , selecting all the options , i want to select only one option at once , if I selected option 1 -> option 2 should be unselected . If I selected option 2 -> option 1 should be deselected.Please help me to do this .
First of all to make things easier
create a array which can hold reference of all the buttons
#interface ViewController ()
{
NSMutableArray *btnArray;
}
Create an object of Array
- (void)viewDidLoad {
[super viewDidLoad];
btnArray = [NSMutableArray new];
/// Here is your code for creating buttons
}
Now add all created buttons to this array
// this is last line from your code where you create your UI
[self.yourButton addTarget:self action:#selector(radioSelected:) forControlEvents:UIControlEventTouchUpInside];
// add this line to add your button to array
[btnArray addObject:self.yourButton];
}
Now when you click button radioSelected method is called
NOTE -: Here can be two cases according to me, but i don't know which one you require so i am explaining both of them
CASE FIRST :-When you select or deselect buttons final output can be that there can be no button selected(all can be deselected)
-(void)radioSelected:(UIButton*)sender{
// here if button is selected, deselect it otherwise select it
[sender setSelected:!sender.isSelected];
for (UIButton* btn in btnArray) {
// here we mark all other button as deselected except the current button
if(btn.tag != sender.tag){
// here when you deselect all button you can add a if statement to check that we have to deselect button only if it is selected
if(btn.isSelected){
[btn setSelected:NO];
}
}
}
}
CASE SECOND:-When atleast one button will be selected
-(void)radioSelected:(UIButton*)sender{
// here if current button is already selected we will not allow to deselect it and return
if(sender.isSelected){
return;
}
// here working is as same as described above
[sender setSelected:!sender.isSelected];
for (UIButton* btn in btnArray) {
if(btn.tag != sender.tag){
[btn setSelected:NO];
}
}
}
You can test both cases and use according to your requirement.
Hope this works for you.
And let me know if you face any issues :)
I have a button in a single cell and set tag for the button.
button uparrow creation:
UIButton *btn_uparrow=[[UIButton alloc]initWithFrame:CGRectMake(500, 20, 50, 50)];
[btn_uparrow setTitle:#"up" forState:UIControlStateNormal];
btn_uparrow.backgroundColor =[UIColor blackColor];
[btn_uparrow addTarget:self action:#selector(btn_up_arrow:) forControlEvents:UIControlEventTouchUpInside];
[btn_uparrow setTag:indexPath.row];
[cell addSubview:btn_uparrow];
uparrow button action method
-(void)btn_up_arrow:(UIButton*)click
{
i++;
NSLog(#"increment %d",i);
if(i>=5)
{
NSLog(#"button increment %d",i);
i--;
}
}
When I click the button in separate cell the increment will continue on the previous data.
Please use following code.
NSInteger tagVal = (UIButton*)click.tag;
and check tagVal variable value.
For tag in tableview
[btn_uparrow setTag:((indexPath.section & 0xFFFF) << 16) |(indexPath.row & 0xFFFF);
In button action
NSUInteger section = ((sender.tag >> 16) & 0xFFFF);
NSUInteger row = (sender.tag & 0xFFFF);
(int)i;
Try this:
-(void)btn_up_arrow:(UIButton*)click{
// get value stored in tag of the button
NSInteger tagVal = click.tag;
tagVal++;
NSLog(#"increment %d",tagVal);
if(tagVal>=5)
{
NSLog(#"button increment %d",tagVal);
tagVal--;
}
// save the value when you are done working with it
click.tag = tagVal;
}
Create a subclass of UITableViewCell
In .h file
#interface CustomTableViewCell : UITableViewCell
{
UIButton *button;
int i;//globally declaring variable i
}
#end
In .m file
// initialize the button in 'init' or any initializing function that you use,
button = [[UIButton alloc]initWithFrame:CGRectMake(10, 10, 100, 30)];
[button setTitle:#"ds" forState:UIControlStateNormal];
[button addTarget:self action:#selector(onButtonAction) forControlEvents:UIControlEventTouchUpInside];
NSLog(#"button instance created");//MAKE SURE THIS IS PRINTED
[self addSubview:button];
-(void)onButtonAction
{
i++;
NSLog(#"increment %d",i);
if(i>=5)
{
NSLog(#"button increment %d",i);
i--;
}
}
I have a UIViewController with a tableView in it with CustomCells, the CustomCell load a PLAY Button for some of the cells, this button are generated within the CustomCell.m
- (UIButton *)videoButton {
if (!videoButton) {
videoButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
videoButton.frame = CGRectMake(120, 319, 50, 30);
[videoButton setTitle:#"Play" forState:UIControlStateNormal];
[videoButton addTarget:self action:#selector(PlayClicked:) forControlEvents:UIControlEventTouchUpInside];
videoButton.backgroundColor= [UIColor clearColor];
[self.contentView addSubview:videoButton];
}
playIMG.hidden = false;
return videoButton;
}
- (IBAction)PlayClicked:(id)sender {
TableView *tvvc = [[TableView alloc] init];
[tvvc PlayBtnClicked:[NSString stringWithFormat:#"%d", [sender tag]]];
}
in my TableView.m
- (IBAction)PlayBtnClicked:(id)sender {
NSString *tag = [NSString stringWithFormat:#"%#", sender]; //OK
int tagNumber = [tag intValue]; //OK
NSString *Media = [arrayID objectAtIndex:tagNumber]; //Not Getting Result !
NSLog(#"%#", arrayID); //Array is empty when logging it from this action
}
arrayID is NSMutableArray
arrayID = [[NSMutableArray alloc] init];
[arrayID addObject#"123"];
[arrayID addObject#"321"];
[arrayID addObject#"231"];
soo i checked the array by adding an action button in my TableView to log the array and its not empty.
how can i fix the empty array which is actually not empty ?
I solved the problem in much easier way than the delegate thing
removed
[videoButton addTarget:self action:#selector(PlayClicked:) forControlEvents:UIControlEventTouchUpInside];
and the action in the custom cell .m file
- (IBAction)PlayClicked:(id)sender {
TableView *tvvc = [[TableView alloc] init];
[tvvc PlayBtnClicked:[NSString stringWithFormat:#"%d", [sender tag]]];
}
in the tableView.m i added edited the action i want to link to this
- (IBAction)PlayBtnClicked:(UIButton*)button {
NSLog(#"Button Clicked Tag: %d", button.tag);
}
and in the cellForRowAtIndexPath method i added the action to the button in the custom cell
if ([MediaType isEqualToString:#"video"]) {
cell.videoButton.hidden = NO;
cell.videoButton.tag = indexPath.row;
[cell.videoButton addTarget:self action:#selector(PlayBtnClicked:) forControlEvents:UIControlEventTouchUpInside];//here linking the action to the button
cell.playIMG.hidden = NO;
}
now everything is working very well :)
The array isn't your problem - you're breaking the model-view-controller nature of the table view controller and its cells. If you want a control in the cell to call a method in the table view controller, make the table view controller the delegate of the cell, and call the delegate method from the cell's button.
If the code you've posted is correct, then you're creating a new table view instance in the PlayClicked method, which is definitely not the way to do it.
As a minor stylistic point, the Cocoa convention of method naming is camelCase, with a lower-case initial letter.
i have a table view and i places button on a tableview as a checkbox ,now i want to maintain state of checkbox's .my problem is when i am navigate from one view controller to another OR terminating my application all checkbox's are unchecked which was previously checked. any suggestion appreciable.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *str=[NSString stringWithFormat:#"identfier%d",indexPath.row];
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:str];
UILabel *lblValue;
if (cell==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:str];
lblValue=[[UILabel alloc]init ];
lblValue.tag=indexPath.row+20000;
btnValue=[UIButton buttonWithType:UIButtonTypeRoundedRect];
btnValue.tag=indexPath.row+100;
}else{
lblValue=(UILabel*)[cell.contentView viewWithTag:indexPath.row+20000];
btnValue=(UIButton*)[cell.contentView viewWithTag:indexPath.row+100];
}
lblValue.backgroundColor=[UIColor clearColor];
lblValue.text=[[sortedArray objectAtIndex:indexPath.row]valueForKey:#"CategoryName"];
//lblValue.text=#"some value";
UIImage *buttonImage = [UIImage imageNamed:#"radiou.png"];
UIImage *buttonImage1=[UIImage imageNamed:#"radioc.png"];
[btnValue setBackgroundImage:buttonImage forState:UIControlStateNormal];
[btnValue setBackgroundImage:buttonImage1 forState:UIControlStateSelected];
[btnValue addTarget:self action:#selector(checkedButton:) forControlEvents:UIControlEventTouchUpInside];
btnValue.frame=CGRectMake(10, 15, 25, 25);
if([self.navigationItem.rightBarButtonItem.title isEqual:#"Done"]){
[UITableView animateWithDuration:0.3f delay:0.1f options:UIViewAnimationOptionCurveEaseInOut animations:^{
lblValue.frame=CGRectMake(35+25, 17, 200, 20);
btnValue.hidden=NO;
} completion:nil];
}
else
{
[UITableView animateWithDuration:0.3f delay:0.1f options:UIViewAnimationOptionCurveEaseInOut animations:^{
lblValue.frame=CGRectMake(35, 17, 200, 20);
btnValue.hidden=YES;
} completion:nil];
}
[cell.contentView addSubview:btnValue];
[cell.contentView addSubview:lblValue];
return cell;
}
For this, you can make a NSArray containing check box's values. Now when viewWillDissappear is called, you can save this array in NSUserDefaults and on viewWillAppear, you can retrieve the array and from NSUserDefaults and set values in checkboxes accordingly.
Suppose you have 10 rows in your table, then you can make an array with count as 10. Now if 4th and 5th row's checkbox is selected, then you can put 1 at index 3 and 4 and rest of the indexes should be 0.
int arrayCount = 10;//enter number of rows you have
NSMutableArray *checkStatusArray = [[NSMutableArray alloc]init];
for (int i=0; i<arrayCount; i++)
{
if([[checkBoxStatusArray objectAtIndex: i]integerValue] == 1)
// Above mentioned array should be made prior to this method from which checkbox will be loaded or you can make 0 entries here for every indexInitially
{
[checkStatusArray addObject:[NSString stringWithFormat:#"1"]];
}
else
{
[checkStatusArray addObject:[NSString stringWithFormat:#"0"]];
}
}
// To put value
[[NSUserDefaults standardUserDefaults]setObject:checkStatusArray forKey:#"statusArray"];
// Now to fetch value
NSArray *valuesArray = [[NSUserDefaults standardUserDefaults]objectForKey: #"statusArray"];
If you want to keep state in your viewControllers without saving and loading state to persistent storage, you should make your viewControllers properties of their parentViewControllers.
That way they won't be deallocated when you navigate away from them.
You must also remember to only alloc and init them once.
I have a button in my tableview that is supposed to change after it is tapped.
In my cellforrowatindexpath, I have
[cell.graphicButton addTarget:self action:#selector(changeGraphic:)forControlEvents:UIControlEventTouchUpInside];
which is supposed to call changeGraphic (which changes the graphic). The call is successful, but in changeGraphic the image doesn't change.
- (IBAction)changeGraphic:sender
{
buttonState++;
// button state is an int, im not using BOOl because I have more than 2 images to change from, but for this question i only included 2
if(buttonState == 2){
buttonState = 0;
}
// 1 = travel time 2 =activity time 3 = total time
if (buttonState == 0) {
[cell.vicinitimeGraphicButton setBackgroundImage:[UIImage imageNamed:#"travelDistanceGraphicGreen.png"] forState:UIControlStateNormal];
}
if (buttonState == 1) {
[cell.vicinitimeGraphicButton setBackgroundImage:[UIImage imageNamed:#"activityTimeGraphicGreen.png" ] forState:UIControlStateNormal];
}
[self.tableView beginUpdates];
[self.tableView reloadData];
[self.tableView endUpdates];
}
When I log stuff inside the changeGraphic method, it returns fine. Am I updating the images of the UIButton correctly?
it should be
[cell.vicinitimeGraphicButton setImage:[UIImage imageNamed:#"travelDistanceGraphicGreen.png"] forState:UIControlStateNormal];
instead of
[cell.vicinitimeGraphicButton setBackgroundImage:[UIImage imageNamed:#"travelDistanceGraphicGreen.png"] forState:UIControlStateNormal];
in my case, the image was being created as background