I have a UITableView with UITableViewCell which holds UIImageView's. Now I want to add a UILongGestureRecognizer to the UIImageView's. But this does not work. The UILongGestureRecognizer works on self.view...
How to implement the UILongGestureRecognizer that it works on the UIImageView's in the UITableViewCell's?
TableViewController.h
#interface MagTableViewController : UITableViewController <UIGestureRecognizerDelegate>
#property (strong, nonatomic) UILongPressGestureRecognizer *longPress;
#property (strong, nonatomic) NSMutableArray *tableContent;
#end
TableViewController.m
- (void)viewDidLoad
{
self.longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressed:)];
self.longPress.minimumPressDuration = 0.2;
self.longPress.numberOfTouchesRequired = 1;
//[self.view addGestureRecognizer:self.longPress]; // This works!
}
// [...]
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UIImageView *imvLeft = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)];
[imvLeft setImageWithURL:[NSURL URLWithString:self.tableContent[#"url"]]];
imvLeft.userInteractionEnabled = YES; // added soryngod's hint, but does not
// solve the problem, as only the last row of 5 is enabled...
[imvLeft addGestureRecognizer:self.longPress]; // does not work...
[cell.contentView addSubview:imvLeft];
return cell;
}
-(void)longPressed:(UILongPressGestureRecognizer *)recognizer {
// do stuff
}
In addition to setting imvLeft.userInteractionEnabled = YES, you also need to make a distinct gesture recognizer for each image view. By design, UIGestureRecognizer must be associated with a single view. The symptoms you are seeing are a result of the recognizer being unattached from the previous cell as each new one calls addGestureRecognizer:.
See related question: Can you attach a UIGestureRecognizer to multiple views?
You need to set imvLeft.userInteractionEnabled = YES;
by default it is NO.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressed:)];
longPress.minimumPressDuration = 0.2;
longPress.numberOfTouchesRequired = 1;
imvLeft.userInteractionEnabled = YES;
[imvLeft addGestureRecognizer:self.longPress];
[longPress release];
[cell.contentView addSubview:imvLeft];
return cell;
}
And if you want to identify the imageview that was pressed
-(void)longPressed:(UILongPressGestureRecognizer *)recognizer
{
UIImageView *img = (UIImageView *)recognizer.view;
//do stuff
}
Related
I've searched for a while but I cannot find the answer to my problem. I have a custom UITableViewCell that has a UITextField.
I use the cellForRowAtIndexPath to create a table with cells. In the UIView that takes the user to the UITableViewController the user specifies how many rows they wish to have. When the user goes back and forth the UITextField text seems to be lost and does not appear in the UITableView
Basically, I cannot get the text that the user inputs to save. Here is my code:
CustomeCell.m
#implementation customCell
#synthesize aTextField;
-(void)layoutSubviews{
aTextField = [[UITextField alloc] initWithFrame:CGRectMake(7, 3, 65, self.contentView.bounds.size.height-6)];
[aTextField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[aTextField setAutocorrectionType:UITextAutocorrectionTypeNo];
[aTextField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[aTextField setBorderStyle:UITextBorderStyleRoundedRect];
aTextField.textAlignment = NSTextAlignmentCenter;
aTextField.keyboardType = UIKeyboardTypeNumberPad;
[self.aTextField addTarget:self action:#selector(aTextFieldEditing:) forControlEvents:UIControlEventEditingChanged];
[aTextField setAutocapitalizationType:UITextAutocapitalizationTypeWords];
[aTextField setPlaceholder:#"begin"];
[self.contentView addSubview:aTextField];
}
-(void)aTextFieldEditing:(UITextField*)textField{
aTextField.text = textField.text;
}
#end
from TableViewController.m
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
customCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[customCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}
Any recommendations? Thank you in advance.
hi everyone i'm new in iOS programming ! I have a custom table view controller with custom table view cell ! one of those cell have a uislider and a label ! I want to change label text when slider change value ! this is my code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *cellInfo = [[self.sections objectAtIndex:currentTab] objectAtIndex:indexPath.row];
HLNotificheCell *cell = [tableView dequeueReusableCellWithIdentifier:[cellInfo objectForKey:#"cell"] forIndexPath:indexPath];
UIImageView *radioIndicator = (UIImageView *)[cell.contentView viewWithTag:200];
radioIndicator.image = (currentBullet != indexPath.row) ? [UIImage imageNamed:#"RadioOff"] : [UIImage imageNamed:#"RadioOn"];
UIImageView *av = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 80)];
av.backgroundColor = [UIColor clearColor];
av.opaque = NO;
av.image = [UIImage imageNamed:#"NewsSeparetor.png"];
cell.backgroundView = av;
cell.slider.maximumValue = 100;
cell.slider.minimumValue = 1;
cell.slider.continuous = TRUE;
//set a method which will get called when a slider in a cell changes value
[cell.slider addTarget:self action:#selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
//Keep a reference to each slider by assigning a tag so that we can determine
//which slider is being changed
cell.slider.tag = indexPath.row;
//Grab the value from the sliderValuesArray and set the slider knob to that position
return cell;
}
-(void)sliderChanged:(UISlider*)sender{
HLNotificheCell *cell = [[HLNotificheCell alloc]init];
if (sender == cell.slider) {
cell.label.text = [NSString stringWithFormat:#"%0.3f", cell.slider.value];
}
}
Actually there is a lot of bad practices in your code. Please let me explain.
Let's begin with your HLNotificheCell class. I think header file should look like this:
#import <UIKit/UIKit.h>
#define HLNotificheCellIdentifier #"HLNotificheCellIdentifier"
#interface HLNotificheCell : UITableViewCell
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;
#property (strong, nonatomic) UISlider *slider;
#property (strong, nonatomic) UIImageView *radioIndicator;
#end
and implementation file:
#import "HLNotificheCell.h"
#implementation HLNotificheCell
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (self) {
_slider = [[UISlider alloc] init];
_slider.maximumValue = 100;
_slider.minimumValue = 1;
_slider.continuous = YES; //YES is more natural in objc rather than TRUE.
[self addSubview: _slider];
_radioIndicator = [[UIImageView alloc] init];
[self addSubview:_radioIndicator];
UIImageView *av = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 80)];
av.backgroundColor = [UIColor clearColor];
av.opaque = NO;
av.image = [UIImage imageNamed:#"NewsSeparetor.png"];
self.backgroundView = av;
//it's better to use built-in textLabel instead of creating your own. Trust me when you will have 20 different customized cells you will get lost with their names.
self.textLabel.textColor = [UIColor redColor];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
// layout your self.slider and self.radioIndicator here or use xib for it.
// e.g. this will layout slider to fit whole cell:
self.slider.frame = self.bounds;
}
#end
Ok, lets go now to cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// try to dequeue cell if exist
HLNotificheCell *cell = (HLNotificheCell *)[tableView dequeueReusableCellWithIdentifier:HLNotificheCellIdentifier];
// if doesn't, create new one.
if (!cell) { // is enough to set slider target only once when cell is created. When reuse is not needed.
cell = [[HLNotificheCell alloc] initWithReuseIdentifier:HLNotificheCellIdentifier];
[cell.slider addTarget:self action:#selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
}
//set image as you wish:
cell.radioIndicator.image = (currentBullet != indexPath.row) ? [UIImage imageNamed:#"RadioOff"] : [UIImage imageNamed:#"RadioOn"];
//Keep a reference to each slider by assigning a tag so that we can determine
//which slider is being changed
cell.slider.tag = indexPath.row;
//Grab the value from the sliderValuesArray and set the slider knob to that position
NSNumber *sliderValue = sliderValuesArray[indexPath.row];
[cell.slider setValue:sliderValue.floatValue animated:NO]
return cell;
}
and sliderChanged: method:
-(void)sliderChanged:(UISlider*)sender{
// You cannot do this:
// HLNotificheCell *cell = [[HLNotificheCell alloc]init];
// because you have to restore reference from sender.tag as you wrote in cellForRowAtIndexPath method:
HLNotificheCell *cell = (HLNotificheCell *)[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:slider.tag inSection:0]] // I assume you have only 1 section
cell.textLabel.text = [NSString stringWithFormat:#"%0.3f", cell.slider.value];
//save new value to the sliderValuesArray
self.sliderValuesArray[indexPath.row] = #(cell.slider.value);
}
Assumptions:
when you will use this part of code please do not use registerClass:forCellReuseIdentifier:
yours sliderValuesArray is kind of NSMutableArray class.
sliderValuesArray has been initialized with size same as number of cells, like:
self.sliderValuesArray = [[NSMutableArray alloc] initWithCapacity:<#numberOfCels#>];
for (int i = 0; i < sliderValuesArray.count; i++) {
sliderValuesArray[i] = #(0);
}
your table view contains only one type of cells (HLNotificheCell)
There could be some typos and/or lack of semicolons because I wrote it without compiler.
I doing this easier. Apple write that you can use IBActions for static rows. (You can read about it here in The Technique for Static Row Content. But I already tested it on iOS 9 with dynamic cells and it's just works :)
At first - Custom cell with IBAction
#interface SliderTableViewCell ()
#property (weak, nonatomic) IBOutlet UILabel *sliderValueLabel;
#property (weak, nonatomic) IBOutlet UISlider *slider;
#end
#implementation SliderTableViewCell
- (void)awakeFromNib {
self.slider.minimumValue = 1;
self.slider.maximumValue = 1000;
}
- (IBAction)sliderValueChanged:(id)sender {
self.sliderValueLabel.text = [NSString stringWithFormat:#"1_%.f", self.slider.value];
}
#end
Second - TableView Delegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SliderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kReuseIdentifierSliderCell];
cell.slider.value = 142;
cell.sliderValueLabel.text = #"1_142";
return cell;
}
Third - Run your app and enjoy yourself ;)
I'm developing an app for iOS7.1 in Xcode 5
And I want to change tableview cell's background color at the final row to look like this
but when I call this UITableViewController inside a UIPopoverController I get this:
Somehow my tableview cell lost it's original background color
this is my code:
//iPad Popover Section
if (!resultBTPopover || !resultBTPopover.popoverVisible)
{
ResultadosBalanceTransferVC *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"ResultadosBalanceTransferVC"];
//controller.delegate = self;
controller.title = #"Resultados";
controller.amountValue = self.amountTextfield.text;
controller.promoRateValue = self.promoRateTextfield.text;
controller.normalRateValue = self.normalRateTextfield.text;
controller.otherBankRateValue = self.otherBankRateTextfield.text;
controller.termValue = self.termTextfield.text;
navController = [[UINavigationController alloc]initWithRootViewController:controller];
navController.toolbarHidden = FALSE;
NSDictionary *textAtributesDictionaryTitle = [NSDictionary dictionaryWithObjectsAndKeys:
UIColorFromRGB(toolbarTintColor), NSForegroundColorAttributeName,
[UIFont fontWithName:#"HelveticaNeue-BoldCond" size:19.0f], NSFontAttributeName,
nil];
[navController.navigationBar setTitleTextAttributes:textAtributesDictionaryTitle];
resultBTPopover = [[UIPopoverController alloc] initWithContentViewController:navController];
[resultBTPopover presentPopoverFromRect:CGRectMake(self.view.center.x - (self.view.center.x * .2734), self.view.center.y - (self.view.center.y * .6510), 300, 400)
inView:self.view permittedArrowDirections:0
animated:YES];
}
else{
[resultBTPopover dismissPopoverAnimated:YES];
resultBTPopover = nil;
}
}
how to get my original tableview cell colors???
thanks in advance for the support
EDIT: I'll put method proposed by Plokstorm
ResultsCell.h:
#import <UIKit/UIKit.h>
#interface ResultsCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *label1;
#property (nonatomic, weak) IBOutlet UILabel *label2;
#property (nonatomic, weak) IBOutlet UILabel *label3;
#property (nonatomic, weak) IBOutlet UILabel *label4;
#property (nonatomic, weak) IBOutlet UILabel *label5;
#end
on STORYBOARD I did this:
all of them changed to ResultsCell custom class
linked all the properties with visual labels of the UITableViewCell
on CODE I did this for testing:
ResultadosBalanceTransferVC.m
#import "ResultsCell.h"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ResultsCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[ResultsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
if (indexPath.row == 2){
cell.backgroundColor = [UIColor redColor];
cell.label1.text = #"Pago Total";
}
return cell;
}
and... still getting same result:
Show us your
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
You can change a cell background with cell.backgroundColor.
Try that:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
if (indexPath.row == 2)
cell.backgroundColor = [UIColor redColor];
return cell;
}
You need to change cell class with it in storyboard.
If you don't create a cell class, you should create an object which extends UITableViewCell. Then you can add its property.
#interface ResultsCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *lYourFirstLabel;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ResultsCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[ResultsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
if (indexPath.row == 2)
cell.backgroundColor = [UIColor redColor];
[cell.lYourFirstLabel setText:#"hello"];
return cell;
}
I have a problem in populating a uitableview created programmatically as a subview of uicollectionview.
here's my code:
.h file
#import <UIKit/UIKit.h>
#interface TheViewController : UICollectionViewController<UITableViewDataSource>
#property (atomic,strong) IBOutlet UIBarButtonItem *plus;
-(IBAction) addTeamPressed:(id)sender;
#end
.m file
- (void)viewDidLoad
{
[super viewDidLoad];
NSError *jsonParsingError = nil;
teamsView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.window.bounds.size.width, self.view.window.bounds.size.height)];
NSData *t = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://..."] options:NSDataReadingMappedIfSafe error:&jsonParsingError];
NSArray *tmp = [NSJSONSerialization JSONObjectWithData:t options:0 error:&jsonParsingError];
UITableViewCell * teamCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
teams = [[NSMutableArray alloc]init];
[teamsView addSubview:teamCell];
teamsView.delegate = self;
teamsView.dataSource = self;
for(int i =0;i<tmp.count;i++){
[teams addObject:[tmp objectAtIndex:i]];
}
plus.title = #"Done";
[self.view addSubview:teamsView];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
// If You have only one(1) section, return 1, otherwise you must handle sections
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [teams count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
TeamsNameCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[SquadreNameCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.name.text = [NSString stringWithFormat:#"%#",[[teams objectAtIndex:indexPath.row] objectForKey:#"name"]];
NSLog(#"%d teams",[teams count]);
return cell;
}
my tableview is displaying correctly, of course thanks to other functions not mentioned here, but no rows in the subview.
the compiler prints out the number of teams, so it calls the delegate methods, but it doesn't populate the subview...
what 's wrong with this?
thanks in advance
Dario
First you should remove this from your viewDidLoad:
UITableViewCell * teamCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
[teamsView addSubview:teamCell];
Then make sure that your teams array is retained, just put this line to the header file:
#property (nonatomic, strong) NSMutableArray* teams;
And then use self.teams instead of just teams
At the end of viewDidLoad method you should call [teamsView reloadData];
Also it would be good to change your table data source method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
TeamsNameCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
// please make sure that you allocate required object here
cell = [[TeamsNameCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// please make sure that you do have `name` property in your `TeamsNameCell` class
cell.name.text = [NSString stringWithFormat:#"%#",[[teams objectAtIndex:indexPath.row] objectForKey:#"name"]];
NSLog(#"%d teams",[teams count]);
return cell;
}
Please make sure that your TeamsNameCell class has name property in the header:
#property(nonatomic, strong) UILabel* name;
And also do not forget to allocate this label in the constructor of TeamsNameCell:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.name = [[UILabel alloc] initWithFrame:CGRectMake(0,0,100,50)];
[self addSubview:self.name];
}
return self;
}
Or Maybe it is better to use default cell's label:
instead of cell.name.text = #"text"; use cell.textLabel.text = #"text";
solution is,
static NSString *CellIdentifier = #"Cell";
TeamsNameCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[SquadreNameCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.labelText.text = [NSString stringWithFormat:#"%#",[[teams objectAtIndex:indexPath.row] objectForKey:#"name"]];
NSLog(#"%d teams",[teams count]);
return cell;
I have a table view, and if a certain row is tapped, the detail view will show up. But how does the detail view know which row was tapped ?
So for instance, I have a MainController which displays names. If I tap "Johnny" The next screen should show a label with the string "Johnny". How would I do that ?
[EDIT - Added code]
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ArticleView *article = [self.storyboard instantiateViewControllerWithIdentifier:#"ArticleView"];
[article.myLabel setText:#"random"];
[self.navigationController pushViewController:article animated:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSDictionary *info = [json objectAtIndex:indexPath.row];
cell.textLabel.text = [info objectForKey:#"username"];
cell.textLabel.backgroundColor = nil;
cell.textLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.backgroundColor = nil;
cell.detailTextLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.text = [info objectForKey:#"user_pic"];
// Configure the cell...
return cell;
}
ArticleView.h
#interface ArticleView : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#end
ArticleView.m
-> Synthesizing properties
You could pass a object (i.e. the String Jonny) to the detail view controller as a property.
#interface ArticleViewController : UIViewController
#property (retain) ArticleView *articleView;
#end
//Don't forget to synthesize name
in the tableview controller
-(void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath)indexPath
{
NSDictionary *info = [json objectAtIndex:indexPath.row];
ArticleViewController *articleViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ArticleViewController"];
articleViewController.articleView = articleView;
[self.navigationController pushViewController: articleViewController animated:YES];
}
the table view delegate has the method tableView:didSelectRowAtIndexPath:, in this method you present your detail view so you know which row was selected from the indexPath parameter and can pass any info you need when you create the new view controller
Assuming you're talking iPhone here, I would have a property name on my detail view:
#propery (nonatomic, retain) NSString * name;
and an init method as follows:
- (id) initWithName: (NSString *) name
{
self = [super initWithNibName: #"<view-controller-nib-name>" bundle: nil];
if (self) {
self.name = name;
}
return self;
}
and then set name label in viewDidLoad
In the tableView:didSelectRowAtIndexPath: method, get the name referenced by the index path, create and init a detail view controller using initWithName:, then push on the nav stack.