Adding a button (UIButton) to a custom tableview cell drawn with drawRect: - objective-c

I am currently working a on project where I have lots of custom table view cells. Part of the requirements is that the cells be able to expand if their default size can not hold all of the content. If they need to be able to expand I have to add a UIButton to the cell and when it is tapped redraw it in a bigger view where all the data fits. Currently in draw rect I essentially do this:
if([self needsExpansion]) {
[self addExpansionButton];
}
-(void)addExpansionButton {
self.accessoryButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.accessoryButton setShowsTouchWhenHighlighted:YES];
UIImage *buttonImage = [UIImage imageNamed:#"blue_arrow_collaps_icon.png"];
[self.accessoryButton setFrame:CGRectMake(280, 82, buttonImage.size.width, buttonImage.size.height)];
[self.accessoryButton setImage:buttonImage forState:UIControlStateNormal];
[self.accessoryButton addTarget:self action:#selector(toggleExpanded) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.accessoryButton];
}
This works fine, except for when I click anywhere else in the cell the button flickers and disappears. Anyone know how to propertly do this?

From the UITableViewCell Class Reference:
You have two ways of extending the
standard UITableViewCell object beyond
the given styles. To create cells with
multiple, variously formatted and
sized strings and images for content,
you can get the cell's content view
(through its contentView property) and
add subviews to it.
Instead of adding the accessory button as a subview of the UITableViewCell, you should add it as a subview of the contentView:
[[self contentView] addSubview:self.accessoryButton];
Have you worked out the following problem in your design approach?: Let's say one of your cells (let's call it A) determines it needs expansion, so you add a button to it. What happens when the user scrolls through the UITableView? For performance reasons, your UITableView delegate should be using dequeueReusableCellWithIdentifier in tableView:cellForRowAtIndexPath:. So you'll be reusing A to display a different row of the table. Do you really want A to have an accessory button? Probably not, since it's now representing a different object.
You're probably better off doing the cell customization at the UITextViewDelegate. In tableView:cellForRowAtIndexPath:, you can determine if the object being displayed at the row specified needs a button, and if it does add it as a subview to the contentView.
Then again, if your table size is always relatively small (say < 50), you can use this approach Jeremy Hunt Schoenherr suggests.

Related

How to add an image in UITableView's content view while we reodering cells?

I have a tableview where I provide the option to reoder the cells. But, I don't want to show the delete icon when the user doing rearranging cells. So I did like this to remove the delete button.
In normal mode..
After edit mode (That is, non deletable but rearrangable mode)..
Here, two things are happening. One is the accessoryview of each cell has a image(that represents rearrangement). Second thing is, all strings are moved some points from the left screen. This gap is actually for the deletion symbol. Since I hide the delete button, an empty space appears.
Ok, here is the problem comes. I now want to add some custom button with an image in each cell's content view.
So, I added the following code in my tableView: cellForRowAtIndexPath:
if (isEditable)
{
selectionButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *img = [UIImage imageNamed:#"blue_button.png"];
selectionButton.frame = CGRectMake(-25, 10, img.size.width, img.size.height);
[selectionButton setBackgroundImage:img forState:UIControlStateNormal];
[selectionButton addTarget:self action:#selector(buttonClickAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:selectionButton];
}
The blue button was 24*24 pixels.
The reason why I used -25 as "x" value:
If I give a positive value or zero, the button will overlapped with cell text. Below image represents when the x value is 0.
But for x=-25,
What I need:
Since I added the button with negative x value, the whole image width (24 pixels) will be hiden in the x value (25 pixels). So the button action buttonClickAction: was not called. I want to change the image when the user tapping on it(switching between selected/unselected mode).
Is there any way to call the button's action method? Or should I create a custom cell?
Just confused..
Add this to your Table View Controller
- (BOOL) tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
It will remove empty space.

Accessory View Is Showing Up Half Off of the Cell

I cant figure out how to get my accessory view to fit into my cell. Also, When I add a subview it adds it to the right of the first subview added. I want the sub views to be added from right to left.
I have this for my accessory view
UIView *myAccessoryView = [[UIView alloc] initWithFrame:cell.accessoryView.frame];
And anytime I add a sub view I just write this
[myAccessoryView addSubview:greenCircle];
And as soon as it adds another subview it is placed to the right of the previous sub view which is even further off my cell. How do I reverse the way it adds subview? How can I format the accessory view to stay on the cell?
You are trying to init myAccessoryView with the frame of accessoryView that doesn't yet exist. It will be created after cell creation (and adding to tableView) if you specify cell.accessoryType property, or if you create and set accessoryView yourself like:
[cell setAccessoryView:myAccessoryView];
So if You do this:
UIView *myAccessoryView = [[UIView alloc] initWithFrame:cell.accessoryView.frame];
[cell setAccessoryView:myAccessoryView];
You will have accessoryView with zero size and coordinates. After the cell is set to tableView, accessoryView will get standart origin point in the right side of the cell. But it still have zero size. And all subviews You add to accessoryView will be set to that origin point.
Method "addSubview" cant change subviews frame, it just places one view to another view.
Have no ideas why new subviews are placed to the rigtht of the previous.
To put your subviews to the right place, You have to set their frames manually. For example:
UIView *greenCircle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[myAccessoryView addSubview:greenCircle];
Hope that helps.

making buttons change size along when zoom

I have a UIScrollView, with a UIImageView and UIButton inside of it.
I was reading in the answers here that if I have a single view that contains all of my zoomable content, then I should be fine. The problem is that the button doesn't zoom when the image does.
I thought that what I have would work, since the Scroll View is the zoomable view.
Do I need to create another UIView and put everything in there (and keep the same hierarchy?) ?
Have you checked your Springs and Struts? Look in the size inspector under "autosizing". Those little red lines.. if that doesn't make sense, search for 'auto layout'.
I ended up fixing this by declaring the button in code, and added a UView into the hiearchy. The uiview is a subview of the scroll view, and the imageview is a subview of the uiview. I then added the buttons to the uiview.
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
...
[view addSubview:button];

How to dynamically reposition UIButton as subview of UIImageView when rotating

I'm working on an iPad app that lets you control different things in a prototype of an intelligent house. For example it lets you turn lights on and off. For this, I have made a UIImageView that shows the floor plan of the house and added UIButtons as subviews for each lamp that can be toggled.
As you can see the buttons are placed perfectly on the floor plan using the setFrame method of each UIButton. However, when I rotate the iPad to portrait orientation, the following happens:
The buttons obviously still have the same origin, however it is not relative to the repositioning of the image.
The floor plan image has the following settings for struts and springs:
and has its content mode set to Aspect Fit.
My question is
how do I dynamically reposition each UIButton, such that it has the same relative position. I figure I have to handle this in the {did/should}AutorotateToInterfaceOrientation delegate method.
It should be noted that the UIImageView is zoomable and to handle this I have implemented the scrollViewDidZoom delegate method as follows:
for (UIView *button in _floorPlanImage.subviews) {
CGRect oldFrame = button.frame;
[button.layer setAnchorPoint:CGPointMake(0.5, 1)];
button.frame = oldFrame;
button.transform = CGAffineTransformMakeScale(1.0/scrollView.zoomScale, 1.0/scrollView.zoomScale);
}
Thank you in advance!
I find the best way to layout subviews is in the - (void) layoutSubviews method. You will have to subclass your UIImageView and override the method.
This method will automatically get called whenever your frame changes and also gets called the first time your view gets presented.
If you put all your layout code in this method, it prevents layout fragmentation and repetition, keeps your view code in your views, and most things just work by default.

How to fade picture loading process with an UIActivityIndicatorView?

I have created a custom UITableViewCell. My custom cell contents an ImageView for picture of current article. On creation of the cell image will be loaded from Internet and displayed in the UIImageView. How can I fade then downloading process with an ActivityIndicatorView?
I'm sorry for this bad English :-) I use an online translator.
If I'm understanding you correctly, it seems like you want your UIImageView's (that are lazily downloaded in realtime) to fade in once they have fully downloaded. And while they are downloading, display the spinning UIActivityIndicatorView wheel.
Here is what I suggest:
1) Instead of defining the custom view in your table cell as a UIImageView specifically, just use the more generic UIView. This is because both classes (UIImageView and UIActivityIndicatorView) are subclasses and can be set as such.
2) Initially, for any and all cells, set the UIView to the UIActivityIndicatorView (don't forget to use "startAnimating" to get it to spin) and then on the callback function for the download completion, go to the appropriate cell and set that custom UIView to the downloaded UIImageView.
3) To achieve the fade in effect, look at the following code:
// Sets the image completely transparent
imageView.alpha = 0.0f;
// Animates the image to fade in fully over 1.0 second
[UIView animationWithDuration:1.0f animations:^{
imageView.alpha = 1.0f;
}];
4) You might need to call "setNeedsDisplay" on the table cell to refresh it's subviews after setting the new image view, and before animating it.