How to fade picture loading process with an UIActivityIndicatorView? - objective-c

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.

Related

How to center a cell with the content offset in a UICollectionView with scrollToItemAtIndexPath

I am implementing a UICollectionView which shows only a single line of cells. It is like an image cover flow. This means I have subclassed UICollectionViewFlowLayout. My implementation works fine when I use my finger for scrolling, meaning that the following delegate method is called and I center the cell;
-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
However when the view loads I want the view to automatically scroll to a cell. For this automatic scroll I use the following;
[self.CollectionView scrollToItemAtIndexPath:_selectedIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
The problem is that targetContentOffsetForProposedContentOffset is not called and thus when the automatic scroll is complete the cell is off the centre.
So how can I programmatically scroll my collection view so that it will also centre on the cell being scrolled to?
Solved this issue myself.
According to the book "iOS UICollectionView The Complete Guide" (Listing 6.7) scrollToItemAtIndexPath: cannot be used in this cover flow type layout as it will not centre the cell.
I have posted below the way it is suggested in the book. Based on the indexPath you want to have you need to calculate the offset of the collection view yourself, and then use the targetContentOffsetForProposedContentOffset: to automatically centre it for you.
CGPoint proposedOffset = CGPointMake(0, 0);
proposedOffset.x = _selectedIndexPath.item * (flow.itemSize.width + flow.minimumLineSpacing);
CGPoint contentOffset = [flow targetContentOffsetForProposedContentOffset:proposedOffset withScrollingVelocity:CGPointMake(0, 0)];
[self.statCollectionView setContentOffset:contentOffset animated:YES];

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.

Draw Over Image

I'm working on some drawing code. I have that portion working great.
I want to draw over an image, but I want to still be able to see the detail of the image, the black lines, etc.
What I am working on is making a transparent UIImageView that holds the image.
I'm not sure how to get this set up properly though.
Should this be added above the other UIImageView that I color on or below it?
Here's what I have so far:
- (void)viewDidLoad
{
[super viewDidLoad];
topImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 46, 320, 370)];
[topImageView setImage:[UIImage imageNamed:#"imagesmall.png"]];
topImageView.alpha = 1.0;
topImageView.layer.opacity = 1.0;
topImageView.layer.opaque = NO;
[self.view addSubview:topImageView];
[topImageView release];
}
Thoughts anyone?
Yes, you can draw views over other views. They are drawn in the order that they're added as subviews, unless you reorder them after that.
You may need to set the opaque property for some views (this is distinct from and overrides their layer opacity), and set their backgroundColor to nil. UIImageView seems to be transparent by default, as long as its image is; some other UIView subclasses are not.
So, just what is your overlay going to be? If you just need to display one image over another, what you have here seems to work already. If you need to draw some lines programmatically, you'll need to do this:
Create a subclass of UIView.
Implement its drawRect method to display the content you need.
When you add your custom view on top of the background image, make sure it is not opaque and has no backgroundColor.
A common problem here is to find that your foreground is working, but the background isn't being loaded properly. To make sure the background is there, set the alpha of the foreground view to 0.5. You won't want to do that in production, but it will allow you to verify that both views exist.

How to create a "stretchable" UIView

I have a UIView that contains another UIView. The outer UIView draws a border around the inner UIView via drawRect. (The border is too complicated to be drawn via CALayer properties.)
At present, when I animate the resizing of the outer UIView, its drawRect method is called once at the beginning of the animation and the result is stretched or shrunk. This does not look good.
I am looking for a way to either redraw the content at every step of the animation, or find a way to achieve the same visual effect. (The result should be similar to the resizing of a stretchable UIImage.)
You should change view's content type to:
your_view.contentMode = UIViewContentModeRedraw;
And it will redraw each time its frame changes.
I ended up adding subviews with autoresizing masks that kept them positioned correctly during the animation.
You need to send a [UIView setNeedsToDisplay] to the view for every time the frame size is changed, you could try overriding the setFrame: method like
- (void)setFrame:(CGRect)r
{
[super setFrame:r];
[self setNeedsToDisplay];
}

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

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.