Is there any way to know which image is currently being displayed in the built in animation within a UIImageView?
I have 5 images which I need to animate through. The UIImageView provides a simple method to do this through the
animationImageView.animationImages = [NSArray ...];
animationImageView.animationDuration = 5;
animationImageView.animationRepeatCount = 0;
[animationImageView startAnimating];
But I would like to have some visual representation of which image is currently being shown. I was thinking of using the UIPageControl and having the dot highlighted represent the current image.
Is there any way to link these two, so the animation within the UIImageView can update the UIPageControl? Or do I need to write my own transitions between UIImageViews? If so can you point me in the right direction of writing a simple animation between images?
thanks
Off the top of my head, you could subclass NSArray and override objectAtIndex: to post a notification of the index whenever the the method was called. Then provide that array subclass to the animation. As the animation requests each image in sequence, the subclass would send a notification (or call a method in somewhere etc).
Not an elegant solution but it would work.
Related
I'm creating a NSCell subclass that draws some objects directly onto the view (using drawInRect:fromRect:operation:fraction:respectFlipped:hints:) and also draws an NSButton instance simply using NSView's addSubview: selector.
While objects drawn using the first method all draw correclty, I'm having problems with drawing the NSButton correctly. The issue is that my NSButton instances will draw in the right places, but multiple times over.
I've researched this on the internet for a while and some people suggested using a cache, but I'm not sure if this is efficient. (going an array containing buttons using a for loop will definately cause slow scrolling since I display a lot of data...)
How would you do this? Am I barking up the wrong tree?
This is the relevant code:
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
NSRect _controlRect = cellFrame;
float _Y = cellFrame.origin.y;
NSRect _accessoryRect = NSMakeRect(_controlRect.size.width - 70.0f, _Y + 9.0f, 50.0f, 23.0f);
_switch = [self _choiceSwitch];
[_switch setFrame:_accessoryRect];
[controlView addSubview:_switch];
}
Long story short: Friends don't let friends addSubview, while drawing.
This a fundamental, and not particularly well-explained aspect of managing control interfaces, but is important to come to grips with.
Let your controllers dictate the "order" of subviews, and you can sleep tight knowing that that button shouldn't get overtly mucked about (which is NOT the case if it's getting jostled around inside your custom drawing routines).
It's easy to get trapped in this alley, cause, like, hey, I added an NSImageView in my initWithFrame and everything seems to be okay… But it's just sort of not how you're supposed to do it, I guess… and when you start subclassing NSControl, etc. is when you start to realize why.
Updated: Here's a really good write up on designing custom controls with an equally as great sample project attached - which embodies the kind of code organization that can help avoid this type of issue. For example.. you'll notice in the controller class how he's keeping each button seperate, unique, and independent of other views' business…
for (int butts = 0; butts < 3; butts++) {
NSRect buttFrame = NSMakeRect(0, butts * 10, 69, 10);
ExampleButt *butt = [[ExampleButt alloc]initWithFrame:buttFrame];
[mainView addSubview:butt];
}
“Drawing” NSButton by adding its instance into the view hierarchy each time you draw the cell itself is definitely a bad idea. Instead, create an NSButtonCell and configure it up to your taste. Then, in your -[NSCell drawInteriorWithFrame:inView:] use a cell ivar to draw its appearance.
If you want to have a clickable NSButton instance in each cell of the table view, try to avoid a call to addSubview: when possible. Each time you do this, the control view may invalidate its layout and re-draw everything from scratch making some kind of a recursion in your case.
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.
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.
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.
I have the need to draw a background image or set a tint color on a navigation bar, but I also need the option to have the navigation bar appear as it normally would. I'm currently using a category to support If my app does not specify a background image, what can I do instead to ensure the drawRect method does it normally would do?
I.E. -
#implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
if(hasImage){
UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://myimageurl.com/img.jpg"]]];
[img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}else{
??????
}
}
#end
I actually ended up doing something entirely different and I'm wondering why nobody hasn't discovered this before. One of the approaches I've seen in the course of my Googling on the subject was simply adding an image as a subview to the UINavigationBar. The only problem was this made the buttons in the bar not clickable. The fix was to disable user interaction on the image.
myUIImageView.userInteractionEnabled = NO;
[myNavController.navigationBar addSubview:myUIImageView];
[myNavController.navigationBar sendSubviewToBack:myUIImageView];
With that, everything looks/works great and I don't have to override the drawRect method with a category, swizzle methods or any of that funky stuff. Simple and clean.
Theoretically you could do this by subclassing UINavigationBar overriding only the drawRect: method, and then calling [super drawRect:rect] when you want to use the default behavior.
But I don't believe you can in practice because you don't instantiate the UINavigationBar directly.
Solving this is possible but nontrivial, since the category method "replaces" the original method rather than subclassing it from the runtime's standpoint. This is why just using, say, super, won't work.
You should check out this post on "supersequent" implementation: http://cocoawithlove.com/2008/03/supersequent-implementation.html
(That link and some other related ideas are in the answer to this question: Using Super in an Objective C Category? )