I have an problem that i use custom cell for UITableView, when I tap more than one finger (2 fingers or more) on my tableview it had many problems some of my labels on each cells (to display information) lost texts (it's empty). So that I try to disable multi touch on my table, but it's not affect. I try to add tableView.allowsMultipleSelection = NO; or tableView.multipleTouchEnabled = NO; into cellForRowAtIndexPath or didSelectRowAtIndexPath. But nothing work. Please help me to find out solution.
Thank you!
Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
#synchronized (self) {
if (row == [voicemailItems count]) {
// User selected the blank rows
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Blank out the play button on previous selected row
[self deselect];
return;
}
}
if (selectedRowIndexPath != nil) {
if (row == selectedRowIndexPath.row) {
// Selecting the same row twice will play the voicemail
if (streaming == NO) {
if (calling == NO) {
// Play the voicemail
[NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(playVoicemailAction:) userInfo:indexPath repeats:NO];
}
return;
}
else {
// Streaming VM
if ([self isCallInProgress] == YES) {
[ScreenUtils errorAllert:#"Cannot play voicemail while call is in progress." type:kUINotice delegate:self];
}
else {
if (![self isVoicemailNotification:selectedRowIndexPath.row]) {
// Stream the voicemail
[NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(playVoicemailAction:) userInfo:indexPath repeats:NO];
}
}
}
}
else {
// Selecting a different row
[self shutdownPlayer];
[self cancel];
// Blank out the play button on previous selected row
[self deselect];
}
}
selectedRowIndexPath = indexPath;
// Enable Call Back button
// Don't enable if private, etc.
btnCallBack.enabled = ([self canCallBack:row] &&
!calling &&
([self isCallInProgress] == NO) &&
![self isVoicemailNotification:selectedRowIndexPath.row]);
// Enable and Delete button
btnDelete.enabled = YES;
// Select the cell
VoicemailCell * cell = (VoicemailCell*)[tblView cellForRowAtIndexPath:indexPath];
[cell select:YES playing:[self isPlaying] stream:streaming];
[tblView setNeedsDisplay];
//[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Try this, it helps me!
cell.contentView.exclusiveTouch = YES;
cell.exclusiveTouch = YES;
#try this
[cell setExclusiveTouch:YES]
after many tries, I find out that I need to add the follow code at the end of didSelectRowAtIndexPath:
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Related
I have tried several approaches posted here, but I cannot get my table full of switches to return an index value for the cell of the changed switch. I am creating the view containing the table programmatically (no xib).
TableSandboxAppDelegate.m I instantiate the view controller in didFinishLaunchingWithOptions: with:
...
TableSandboxViewController *sandboxViewController = [[TableSandboxViewController alloc]
init];
[[self window] setRootViewController:sandboxViewController];
...
TableViewController.h file reads:
#interface TableSandboxViewController : UITableViewController
{
NSMutableArray *_questionOrder;
NSMutableArray *switchStates;
}
#end
TableViewController.m cellForRowAtIndexPath: reads:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
UISwitch *theSwitch = nil;
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"MainCell"];
theSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
theSwitch.tag = 100;
[theSwitch addTarget:self action:#selector(switchChanged:)
forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:theSwitch];
} else {
theSwitch = [cell.contentView viewWithTag:100];
}
if ([[switchStates objectAtIndex:indexPath.row] isEqualToString:#"ON"]) {
theSwitch.on = YES;
} else {
theSwitch.on = NO;
}
return cell;
TableViewController.m -(IBAction)switchChanged:(UISwitch *)sender reads:
UITableViewCell *theParentCell = [[sender superview] superview];
NSIndexPath *indexPathOfSwitch = [self.tableView indexPathForCell:theParentCell];
NSLog(#"Switch changed at index: %d", indexPathOfSwitch.row);
My log result is always "Switch changed at index: 0". I feel like the problem is in that CGPoint line where I've tried combinations of replacements for "sender" ([sender superview], [[sender superview]superview], etc). I don't feel like that line is pointing to the view that displays the table.
What am I doing wrong?
Note added 10/9, 9:15 EDT: my goal is to be able to handle about 100 yes/no questions in the table, so reuse is a key. I want to scroll and have the table the state of each switch, as well as be able to retrieve them when leaving the view.
Tags is an okay solution, but a little clumsy because the cells - and therefore their subviews - are continually being reused, changing their rows - and therefore the tags they need.
Instead, I generally keep one of these around:
- (NSIndexPath *)indexPathWithSubview:(UIView *)subview {
while (![subview isKindOfClass:[UITableViewCell self]] && subview) {
subview = subview.superview;
}
return [self.tableView indexPathForCell:(UITableViewCell *)subview];
}
Then when I get an IBAction:
- (IBAction)someSubviewAction:(id)sender {
NSIndexPath *indexPath = [self indexPathWithSubview:(UIView *)sender];
// carry on from here
}
You may set switch view tag to row index. Instead of theSwitch.tag = 100;
do
-(UITableViewCell*)tableView:table cellForRowAtIndexPath:indexPth
{
UISwitch *theSwitch = nil;
if (cell == nil) {
...
// as per your example
[cell.contentView addSubview:theSwitch];
} else {
theSwitch = subviewWithClass(cell.contentView, [UISwitch class]);
}
theSwitch.tag = indexPath.row;
...
}
Add this helper function to replace viewWithTag: call
UIView *subviewWithClass(UIView *contentview, Class klass)
{
for (UIView *view in contentview.subviews)
if ([view isKindOfClass:klass])
return view;
return nil;
}
Then retrieve tag, that is a row index now, in your switchChanged function
-(IBAction)switchChanged:(UISwitch *)sender {
NSLog(#"Selected Switch - %d", sender.tag);
...
}
If you use something block-based (like https://github.com/brightsoftdev/iOS-Block-Based-Bindings/blob/master/UISwitch%2BBindings.m), you don't need to worry about getting the row, because you can reference the indexPath that is passed into tableView:cellForRowAtIndexPath: in your block.
Similar to #danh, I've come up with this solution using an extention which I've used multiple times.
#interface UIView (Find)
- (id)findSuperviewOfClass:(Class)class;
- (NSIndexPath *)findIndexPath;
#end
#implementation UIView (Find)
- (id)findSuperviewOfClass:(Class)class
{
return [self isKindOfClass:class] ? self : [self.superview findSuperviewOfClass:class];
}
- (NSIndexPath *)findIndexPath
{
UITableView *tableView = [self findSuperviewOfClass:[UITableView class]];
return [tableView indexPathForCell:[self findSuperviewOfClass:[UITableViewCell class]]];
}
#end
for iOS6+ you could maintain a NSMutableArray queuedSwitches
in -tableView:cellForrowAtIndexPath: you would take a switch, if not empty and places it on the custom cell and assign it to a property. If empty you create a new one.
in -tableView:didEndDisplayingCell:forRowAtIndexPath: you would add it to quededSwitches and remove it from it cell.
This will just allocate enough switches for visible cells and reuse them.
the switches are all wired up to one action.
-(void)switchAction:(UISwitch *)switch
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:[switch superView]];
//…
}
You could create a subclass of UISwitch and add an indexPath property, then just set the indexPath in cellForRowAtIndexPath:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SwitchCell *returnCell = [tableView dequeueReusableCellWithIdentifier:#"SwitchCell" forIndexPath:indexPath];
returnCell.switch.indexPath = indexPath;
return returnCell;
}
First of all, I'm just starting on iPhone development. I'm trying to get an SBTableAlert working (see https://github.com/blommegard/SBTableAlert )
My initial setup is simple: I have a UIViewController with a button. On the button press, I do the following (as per the SBTableAlert example):
- (IBAction)myBtn_Press
{
SBTableAlert *alert;
alert = [[SBTableAlert alloc] initWithTitle:#"Apple Style" cancelButtonTitle:#"Cancel" messageFormat:nil];
[alert.view setTag:2];
[alert setStyle:SBTableAlertStyleApple];
MySecondViewController *myWGVC = [[MySecondViewController alloc] init];
[alert setDelegate:myWGVC];
[alert setDataSource:myWGVC];
[alert show];
}
MySecondViewController is declared as:
#interface MySecondViewController : NSObject <SBTableAlertDelegate, SBTableAlertDataSource>
which means it will function as a delegate for the table view. I also include the following (pasted from the example):
#implementation MySecondViewController
#pragma mark - SBTableAlertDataSource
- (UITableViewCell *)tableAlert:(SBTableAlert *)tableAlert cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
if (tableAlert.view.tag == 0 || tableAlert.view.tag == 1) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
} else {
// Note: SBTableAlertCell
cell = [[SBTableAlertCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
}
[cell.textLabel setText:[NSString stringWithFormat:#"Cell %d", indexPath.row]];
return cell;
}
- (NSInteger)tableAlert:(SBTableAlert *)tableAlert numberOfRowsInSection:(NSInteger)section {
if (tableAlert.type == SBTableAlertTypeSingleSelect)
return 3;
else
return 10;
}
- (NSInteger)numberOfSectionsInTableAlert:(SBTableAlert *)tableAlert {
if (tableAlert.view.tag == 3)
return 2;
else
return 1;
}
- (NSString *)tableAlert:(SBTableAlert *)tableAlert titleForHeaderInSection:(NSInteger)section {
if (tableAlert.view.tag == 3)
return [NSString stringWithFormat:#"Section Header %d", section];
else
return nil;
}
#pragma mark - SBTableAlertDelegate
- (void)tableAlert:(SBTableAlert *)tableAlert didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableAlert.type == SBTableAlertTypeMultipleSelct) {
UITableViewCell *cell = [tableAlert.tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
[tableAlert.tableView deselectRowAtIndexPath:indexPath animated:NO];
}
}
- (void)tableAlert:(SBTableAlert *)tableAlert didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSLog(#"Dismissed: %i", buttonIndex);
}
The error message I'm getting is:
2013-04-25 00:13:35.389 MyTestProject[3386:c07] *** -[SBTableAlert tableView:cellForRowAtIndexPath:]: message sent to deallocated instance 0x682ed80
however I have no idea how to trace this or debug it. It appears it could have something to do with ARC, since the demo project doesn't use it, but I can't pinpoint how to fix this.
Any help is appreciated!
Try creating properties with strong attribute in your main UIViewController subclass for both alert and myWGVC objects. They seem to be deallocated because of ARC before the alert is presented on screen since there are no strong references to the alert's delegate/datasource and the alert itself.
I have this code
NSString *localStringValue;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
localStringValue = [m_textfield cellForRowAtIndexPath:indexPath].textLabel.text;
localStringValue = [m_textfield cellForRowAtIndexPath:indexPath].detailTextLabel.text;
NSArray* toReload = [NSArray arrayWithObjects: indexPath, self.selectedIndexPath, nil];
self.selectedIndexPath = indexPath;
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark){
UploadView *uploadview = (UploadView *)self.view;
if (uploadview != nil)
{
[m_owner uploadString:localStringValue];
//[self dismissModalViewControllerAnimated:YES];
}
[[m_textfield cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryNone];
}
else {
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
}
}
in this code i am syncing localStringValue to google-doc when i tap the cell if the check mark is there.localStringValue contains the values in the tableview cell.Every thing works fine at this point.But my need is i want to pass this value to a button click,that means if the user select multiple row i want all the values in the localStringValue and pass this through this code
- (IBAction)doUpload:(id)sender
{
UploadView *uploadview = (UploadView *)self.view;
if (uploadview != nil)
{
[m_owner uploadString:#""];
//[self dismissModalViewControllerAnimated:YES];
}
}
i want to pass localstringvalue in [m_owner uploadString:localstringvalue];
How to do this?
thanks in advance.
you can create a NSMutableArray as class variable and you can add your strings to that on didSelectRowAtIndexPath. Later on on button click you can process the NSMutableArray to fetch strings one by one and sending them to google-doc...etc.
You need to update ur
- (void)doUpload:(NSString*)stringValue
{
UploadView *uploadview = (UploadView *)self.view;
if (uploadview != nil)
{
[m_owner uploadString:localstringvalue];
//[self dismissModalViewControllerAnimated:YES];
}
}
And one more thing
localStringValue = [m_textfield cellForRowAtIndexPath:indexPath].textLabel.text // reassigning the string again so this line does not make any sense.
How to use 3 different cells on one uitableview? I have 3 buttons now When i press any button then cell of table view should be changed. Please help
In the button's action method, save which button was tapped & reload the row in which you want to change the cell.
-(void)button1Tapped:(id)sender
{
self.buttonIndex = 1;
NSArray* arr = [[NSArray alloc] initWithObjects:self.indexPathOfConcernedCell, nil];
[self.tableView reloadRowsAtIndexPaths:arr withRowAnimation:UITableViewRowAnimationNone];
[arr release];
}
Then, in cellForRowAtIndexPath: return the cell one the basis of which button was pressed-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath == self.indexPathOfConcernedCell)
{
if(self.buttonIndex == 1)
{
Cell1* cell = (Cell1*) [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier1"];
if(cell == nil)
{
cell = [[[Cell1 alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"CellIdentifier1"] autorelease];
}
}
else if(self.buttonIndex == 2)
{
//do similar stuff
}
//do similar stuff for buttonIndex 3 here
}
}
else
{
//your regular stuff
}
return cell;
}
Here is my code for the UIControlEventValueChanged event for a UISegmentedControl:
- (void)segmentAction:(id)sender{
if([sender selectedSegmentIndex] == 0){
pendingIsShowing = YES;
[freeCutsTable reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
}else if([sender selectedSegmentIndex] == 1){
pendingIsShowing = NO;
[self showAvailableCuts:sender];
[freeCutsTable reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
}
}
My problem is when the value is changed, the [self showAvailableCuts:sender] is called, but the segment control no longer changes its index. If I comment out the method call, it works fine...What I tried to do was pass in the segmented control into [self showAvailableCuts:sender] and change it that way, but to no avail...
- (void)showAvailableCuts:(id)sender{
if(!pendingIsShowing){
NSString *path =#"https://WebserviceURL";
NSString* escapedUrl = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//[sender setSelectedIndex:1];
NSLog(#"%#", escapedUrl);
[self parseXMLFileAtURL:escapedUrl];
}
}
I'm not sure why this is occurring...
Without looking at the code for [self showAvailableCuts:sender]; all I can think of is - why do you need to pass the 'sender' object itself? Just modify the showAvailableCuts method so that you need to pass only the required value(s) like [sender titleForSegmentAtIndex:] , [sender selectedSegmentIndex] etc.
ok, firstly the setter should be [sender setSelectedSegmentIndex:index] not what you have commented out. I have myself successfully used this -
sender.selectedSegmentIndex = index; //in your case index is 1