I've got a UIImageView as the background of my UITableViewCell subclass. I have put an image in the Image field and a lighter version of that image in the Highlighted field. In my UITableViewCell subclass, I added code to set that ImageView to highlighted, but nothing changes...
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
self.backgroundImageView.highlighted = selected;
NSLog(#"selected: %d", selected);
}
I've verified that self.backgroundImageView is properly connected as an IBOutlet.
Just initialize the UIImageView like this:
[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"gray_arrow"] highlightedImage:[UIImage imageNamed:#"white_arrow"]];
If you need to keep it highlighted, in your tableview's didSelectRowAtIndexPath method, get the subview that represents your UIImageView and make it highlighted. Something like this:
UIImageView* imageView = [[[dataSource objectAtIndex:[indexPath row]] subviews] objectAtIndex:2]
[imageView setHighlighted:YES];
Set the UIImageView's in the other cells to :
[imageView setHighlighted:NO];
Related
I have tableview and I want to show all images from one folder inside directory and I have path to that directory. I am loading image to cell like:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
for (UIView * view in cell.contentView.subviews){
if ([view isKindOfClass:[UIButton class]]) {
[view removeFromSuperview];
}
}
cell.imageView.image = nil;
cell.accessoryType = UITableViewCellAccessoryNone;
NSData *imgData = [NSData dataWithContentsOfFile:absoluteImagePath];
UIImage *thumbNail = [[UIImage alloc] initWithData:imgData];
UIImageView *imageView = [[UIImageView alloc] initWithImage:thumbNail];
[cell insertSubview:imageView atIndex:0];
}
but when I scroll up and down I get image over image inside cell (old image is visible below new, when I scroll on for example first position I see image for index 0 below other image ).
Does anyone know what is a problem, I am new to this iOS programming ?
You should
subclass your cell,
create an outlet for the image, and
design the layout in storyboard.
The benefits:
No need to check for (cell==nil)
You will have to write less code
Cleaner solution without redundant view creation errors
When the cell is reused, [cell insertSubview:imageView atIndex:0]; adds an additional UIImageView to the cell. Suggestion is to create a custom UITableViewCell and in the prepareForReuse method, remove the UIImageView. An easy way to identify UIImageView to remove is to add a tag to it. E.g.,
imageView.tag = 1000;
Then you can find the image view with
UIImageView *imageView = [self.contentView viewWithTag:1000];
if (imageView) {
[imageView removeFromSuperview];
}
Declare the UIImageView where you are initializing the cell.
For example
if (cell==nil)
{
UIImageView *image = [[UIImageView alloc]initWithFrame:yourFrame];
[cell addSubView:image];
}
image.image = yourImage;
Alternatively, you can remove all subviews from the cell before adding new UIImageView as subview.
I have programmatically created a UITableView and I have also programmatically created UIButtons to be included with every cell / row. I have set these buttons so that if they are tapped, their button image changes. So when the user first sees the table view, the buttons are the color grey, but if the user taps one of the buttons, then that button will turn red. If they tap it again, it will turn back to grey.
I need to make it so that if a button has been pressed, and is currently using the red image, then it will pass it's cell's detailTextLabel property value into an NSMutableArray object.
Here is my code that controls the majority of the UITableView. This is where the cell's textLabels and detalTextLabels are set:
userName = [self.potentiaFriendsInParseFirstNamesArray objectAtIndex:indexPath.row];
NSString *firstNameForTableView = [self.potentiaFriendsInParseFirstNamesArray objectAtIndex:indexPath.row];
NSString *userNameForTableView = [self.potentiaFriendsUsernameArray objectAtIndex:indexPath.row];
UIImage *addUserButtonImage = [UIImage imageNamed:#"SliderThumb-Normal-G"];
UIImage *addUserButtonImageHighlighted = [UIImage imageNamed:#"SliderThumb-Normal"];
UIButton *addUserButton = [[UIButton alloc]init];
addUserButton.frame = CGRectMake(237, -10, 64, 64);
[addUserButton setImage:addUserButtonImage forState:UIControlStateNormal];
[addUserButton setImage:addUserButtonImageHighlighted forState:UIControlStateHighlighted];
[addUserButton setImage:addUserButtonImageHighlighted forState:UIControlStateSelected];
[addUserButton addTarget:self action:#selector(handleTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
[cell.textLabel setText:firstNameForTableView];
[cell.detailTextLabel setText:userNameForTableView];
[cell.contentView addSubview:addUserButton];
The most important parts of the above code are these statements:
[addUserButton setImage:addUserButtonImage forState:UIControlStateNormal];
[addUserButton setImage:addUserButtonImageHighlighted forState:UIControlStateHighlighted];
[addUserButton setImage:addUserButtonImageHighlighted forState:UIControlStateSelected];
The above control the settings for the different states of the button, and this helps make the button turn to the grey image or the red image when it is pressed.
The below statement is a method call that handles the "touch" events and makes the button change from the grey image to the red image when it is pressed:
[addUserButton addTarget:self action:#selector(handleTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
And here is the above method's method implementation in my View Controller:
- (void)handleTouchUpInside:(UIButton *)sender {
sender.selected = !sender.selected;
NSLog(#"Has sender state changed?: %u", sender.state);
}
You will notice that I am using NSLog to print out the button's state. The "state" property changes it's value every time one of the button's is pressed. Now I need to figure out a way to make it so that if a specific button's state is changed, we will grab it's cell's "detailTextLabel" property and place it inside an NSMutableArray.
You can use the addUserButton.tag property to keep tableview index row (1), so inside the handleTouchUpInside (2) you can find button row:
1- Set indexPath row inside the cellForRowAtIndexPath function
//Keep indexPath.row on Button.tag
addUserButton.tag = indexPath.row
2- Find button on TableView Rows
- (void)handleTouchUpInside:(UIButton *)sender {
UIButton *cellButton = (UIButton *)sender;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:cellButton.tag inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.detailTextLabel.text = #"teste";
}
I hope it works.
Here's the essence of how you'd subclass UITableViewCell to accomplish this (condensed a bit to save space...) First the .h
#import <UIKit/UIKit.h>
#interface SampleCell : UITableViewCell
#property (nonatomic, assign) id delegate;
#end
#protocol FancyProtocolNameGoesHere
- (void)doSomethingWithThisText:(NSString*)text fromThisCell:(UITableViewCell*)cell;
#end
And the .m
#import "SampleCell.h"
#interface SampleCell ()
#property (strong, nonatomic) UIButton *button;
- (void)handleTouchUpInside;
#end
#implementation SampleCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self configureCell];
}
return self;
}
- (void)configureCell
{
_button = [[UIButton alloc] init];
//Configure all the images etc, for the button
[_button addTarget:self action:#selector(handleTouchUpInside) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_button]; //you'd probably want to set the frame first...
}
- (void)handleTouchUpInside
{
if (_button.selected) {
[self.delegate doSomethingWithThisText:self.textLabel.text fromThisCell:self];
}
_button.selected = !_button.selected;
}
#end
Register this subclass with the TableView (remember to declare conformity to the protocol), and assign the delegate to self within -(UITableViewCell*)cellForRowAtIndexPath:(NSIndexPath*)indexPath
The final magic comes as you implement - (void)doSomethingWithThisText:(NSString*)text fromThisCell:(UITableViewCell*)cell; because you can call [self indexPathForCell:cell] on the cell parameter you passed in to get the index path you probably need so you know where to insert the text in your NSMutableArray data object.
A subclassed UITableViewCell with a delegate protocol pattern is not the only way to do this, but I think it makes some sense for what you described.
This solutions is safe to table sections.
- (void)onButtonPressed:(UIButton *)sender event:(id)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForItemAtPoint:point];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
/* use cell here */
}
In my UITableView, all the cells will be a different height. All of them have a background image, which is a bubble picture. All of the cell's TextLabels need to be different widths as well, so I've subclassed UITableViewCell and have given it two properties:
#property (strong, nonatomic) UILabel* messageTextLabel;
#property (strong, nonatomic) UIImageView* bubbleImageView;
I have my custom UITableViewCell's initWithStyle set up like so:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//stretchable bubble image
UIImage *rawBackground = [UIImage imageNamed:#"text_bubble"];
UIImage *background = [rawBackground stretchableImageWithLeftCapWidth:13 topCapHeight:22];
_bubbleImageView = [[UIImageView alloc] initWithImage:background];
//textlabel
_messageTextLabel = [[UILabel alloc] init];
[_messageTextLabel setFont:[UIFont systemFontOfSize:14.0f]];
[_messageTextLabel setNumberOfLines:0];
[_messageTextLabel setBackgroundColor:[UIColor clearColor]];
[_messageTextLabel setTextColor:[UIColor blackColor]];
[self.contentView addSubview:_bubbleImageView];
[self.contentView addSubview:_messageTextLabel];
}
return self;
}
In my TableView's cellForRowAtIndexPath, I've already tried to just alloc a UIImageView there and set it to the cell's frame, and that works, but when I scroll up and down then the screen gets cluttered with UIImageViews being re-alloced over and over. I've tried the if(cell == nil) technique, but that just makes my entire UITableView blank. So, this is what I have right now:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
Cell *cell = (Cell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//works just fine
[cell.messageTextLabel setFrame:CGRectMake(15, 0, 245, cell.frame.size.height -10)];
//this doesn't work at all
[cell.bubbleImageView setFrame:CGRectMake(10, 0, cell.frame.size.width, cell.frame.size.height)];
[cell.messageTextLabel setText:[self.randomData objectAtIndex:indexPath.item]];
return cell;
}
So my UITableView ends up looking like this when run (cell selected so you can see the frame):
Note that I can set the frame of the bubbleImageView in my UITableViewCell subclass, but I don't know what the cell's height is going to be then. I'm more baffled by the fact that I can set my messageTextLabel's frame and not my bubbleImageViews. I may be doing something that is very elementary wrong, it's a simple problem though for some reason I'm getting tripped up.
Thank you!
I have seen 2 problems here:
I think that you have the auto-layout enabled.
In this case the initial frame and the autoresizingMask are translated to auto-layout constraints automatically.
After this no frame changes will change the view's size and location - only the constraints...
You haven't set the contentMode of the image view to UIViewContentModeScaleToFill (this is the default, but it's better define this kind of properties anyway).
Just add this line: _bubbleImageView.contentMode = UIViewContentModeScaleToFill; right after its initiation.
I think that the solution here is auto-layout - setting constraints properly will solve this issue.
I suggest doing it in the storyboard, with table view controller and dynamic cells...
I am using custom cells where I set two images, an accessoryView image and some custom buttons. The accessoryView image shows up initially. When the user swipes the row, i hide the accessoryView image and unhide the buttons. When the user 'unswipes' (or taps somewhere else), I hide the buttons and show the accessoryView. This all works fine, except when I do the following:
1)Load the screen. accessoryView image is there and buttons are hidden. Good.
2)Swipe a row. accessoryView disappears and buttons appear. Good.
3)Scroll down the table to reveal more cells (I'm using reusable cells). All new cells are shown with accessoryView and no buttons. Good, as expected.
4)Scroll back up to the original cell I swiped. I see both the accessoryView image and the buttons like this:
Here's some code:
In my custom cell object, I have:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if (selected)
{
self.accessoryView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"arrow-right-black.png"]];
UIImage *selectedRowImage = [UIImage imageNamed:#"table-selectedcellbg-red-45px-stretch.png"];
self.selectedBackgroundView = [[UIImageView alloc]initWithImage:[selectedRowImage resizableImageWithCapInsets:UIEdgeInsetsMake(selectedRowImage.size.height, selectedRowImage.size.width/2, selectedRowImage.size.height, selectedRowImage.size.width/2)]];
}
else
{
self.accessoryView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"arrow-right.png"]];
self.selectedBackgroundView = [[UIImageView alloc]initWithImage:[[UIImage alloc]init]];
}
}
- (void)swipeCell
{
[self setSelected:NO animated:NO];
self.accessoryView = nil;
swipeButtons.hidden = NO;
}
- (void)unswipeCell
{
[self setSelected:NO animated:NO];
self.accessoryView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"arrow-right.png"]];
swipeButtons.hidden = YES;
}
In my cellForRowAtIndexPath, I check to see if the cell was swiped:
if (self.indexPathSwipeButton != nil && self.indexPathSwipeButton.row == indexPath.row)
{
[cell swipeCell];
}
else
{
[cell unswipeCell];
}
return cell;
Any ideas?
You use [self setSelected:NO animated:NO]; in method (void)swipeCell and in method - (void)unswipeCell.
But in (void)swipeCell it should be [self setSelected:YES animated:NO];.
Hope it helps
I have UITextView subviews inside a UITableViewCell. When user taps on the cell I select it, i.e. I switch the background image to selected state. The UITextView becomes first responder, but the cursor is hidden. When I disable the cell selection the UITextView shows a cursor without issues.
How to select the cell and start editing the UITextView with a visible cursor? :)
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected && ![textView isFirstResponder]) {
[textView setUserInteractionEnabled:YES];
[textView becomeFirstResponder];
} else {
[textView resignFirstResponder];
[textView setUserInteractionEnabled:NO];
}
}
Cell stopped to hide cursor, when i set.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
But after that, cell also stopped use selectedBackgroundView. So I set my image to highlighted state of backgroundView.
cell.backgroundView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"input_up.png"] highlightedImage:[UIImage imageNamed:#"input_up_act.png"]] autorelease];
And switched image in setSelected:animated:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected && ![textView isFirstResponder]) {
[textView setUserInteractionEnabled:YES];
[textView becomeFirstResponder];
} else {
[textView resignFirstResponder];
[textView setUserInteractionEnabled:NO];
}
[(UIImageView *)self.backgroundView setHighlighted:selected];
}
your cursor non disappeared maybe is't white!
try: [self.tableView setTintColor:[UIColor redColor]];
You could try setting the selected property of UITableViewCell inside the UITextViewDelegate protocol method textViewDidBeginEditing:.
If this does not work, create a UIImageView as a subview of your cell and change the content of that in the method above.
When you select the cell, the textView become the first responder, but the cursor has been hidden, you can deselect the cell, and then the cursor will show.