Exactly what should happen in a CALayer's display/drawRect methods? - iphone

Which, if either, of these methods would be an appropriate place to:
Change the text of a CATextLayer
Load a different image into a CAImageLayer
Tell sublayers to update themselves

Dude I may be way drunk ... but there is NO drawRect method in CAlayers
I think you can use drawInContext: to actually (gulp) draw in to CALayers, but nobody is man enough to do that since WW2.
Regarding display, you don't need to call it, it basically updates what you set using .contents.
I just use .contents something like this ...
[self.view setLayer:rearLayer];
[self.view setWantsLayer:YES];
rearLayer.frame = CGRectMake(gameBlah,gameBlah, 1024,768);
// note that we are dealing there with the mysteries of rearLayer positioning;
// it is measured by the SUPER layer of the layer in question!
// (indeed much as frame for the view is, if you think about it ..)
rearLayer.contents = (id)loadMacStylePng(#"spaceShip");
Say one had the guts to write one's own drawInContext: ...
In that case, it gets called (or abstracted out ... or recalculated, or something) when you call displayAsNeeded. (I've never needed to call displayAsNeeded:, that's for sure.)

Related

Collision detection with particles in Cocos2d

I am using CCParticleSystemQuad to create a particle effect. Now I would like to test for collisions with a CGRect from my Cocos2d scene. I listed another subject similar to this one and got a little closer however I still do not have the full solution so I have re-listed with a slightly different subject title.
I have half of the solution. I can get the position of each particle and can test for collisions, now I would like to set the positions of each when they collide.
I am currently subclassing the CCParticleSystemQuad and then adding my own getter like so:
-(tCCParticle*)getQuadParticle:(int)quadIndex
{
return &particles[quadIndex];
}
Then in my Cocos2d scene I can get the particle and the position:
tCCParticle *particle = [emitter getQuadParticle:i];
CGPoint pos = particle->pos;
This works but warns that CCParticleSystemQuad may not respond to getQuadParticle. Which is a concern, but what I would like to do now is set the position from the scene in a similar fashion such as:
[emitter setParticlePos:i newPosition:newPos];
However I am not sure how to make a setter that does this that works from my scene. I don't want to do collision detion inside the particle subclass if possible.
I started another topic of similar nature called "How to get particle position in Cocos2d (iphone)" and I was told to overide the "update" method or the "updateQuadWithParticle" method but I am unsure how to go about this exactly.
If someone could show me an example of how to do this I would be most grateful.
This works but warns that CCParticleSystemQuad may not respond to
getQuadParticle.
For the warning, make sure your emitter is made from your subclass (and not a regular CCParticleSystemQuad), and that your getter method is declared in the interface (.h file) and defined in the implementation (.m file).
Looking at the API, I don't see a method for setParticlePos:newPosition: but there is something that looks similar: -(void) updateQuadWithParticle:(tCCParticle*)particle newPosition:(CGPoint)pos;
I have not used it, but a glance at the source suggests it does what you need.
So maybe try
[emitter updateQuadWithParticle:particle newPosition:newPos];
Hope that's helpful.

Rotation - slowing it down using willAnimateSecondHalfOfRotationFromInterfaceOrientation

people, how do you actually slow down the orientation-rotation when using the "willAnimateSecondHalfOfRotationFromInterfaceOrientation:" method?
I currently have this:
-(void) willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
duration:(NSTimeInterval)duration {
[self positionViews];
}
And I understand that this "willAnimate2ndHalf..." method gets called automatically when the rotation does indeed happen - well where do I actually get to change its DURATION value?
If you want to change the overall timing of he app's rotation, it can't be done. willAnimateSecondHalfOfRotationFromInterfaceOrientation is meant for adding custom code, like setting custom coordinates, properties, things like that.

GLPaint Sample: how to create the view programmatically?

I need to draw something on an image, like in the GLPaint sample from Apple, but I need to create the EAGL surface where render the OpenGL programmatically.
In the sample is instatiated in the MainWindow.xib
If I try to create the view programmatically with something like:
self.drawingView = [[PaintingView alloc] initWithCoder:nil];
drawingView.frame = CGRectMake(0, 0, 320, 380);
[self.view addSubview:drawingView];
I got this error:
failed to make complete framebuffer object 8cd6
Maybe something related to the init? Any hints? Thanks.
From a quick glance inside the source, Apple have put all of the significant initialisation stuff for PaintingView inside initWithCoder:, from lines 77 to 168. That's part of the NSCoding protocol, which is used for archiving and unarchiving objects from files. If you call initWithCoder:nil, quite probably the UIView implementation of initWithCoder isn't able to get some relevant value that it needs. At a guess, it probably starts being size zero, which isn't a valid size for a framebuffer object.
I'd suggest you replace initWithCoder:(NSCoder *)coder with initWithFrame:(CGRect)frame, calling the same on super at line 86. For an even better implementation, implement both initWithFrame: and initWithCoder:, having the two call a common section for everything enclosed in the if((self = [super initWithXXX:argument])) block.

iPhone scrollView add elements dynamically with id

I want to populate a scrollView with quite a few different UI elements.
Therefore I thought I would write a method that remembers the current Position in the scrollView and just adds the element to the scrollView at the current Position.
Something like:
- (void)addUIElement:(id)element withWidth:(CGFloat)width andHeight:(CGFloat)height andYGap:(CGFloat)YGap {
element.frame = CGRectMake(currentScrollPos.x, (currentScrollPos.y + YGap), width, height);
[scrolly addSubview:element];
//And then set the current scroll position here
}
Unfortunately when I try to do access element.frame = ..., I get request for member in something not a structure or union. When I try to do [element frame] = ... Lvalue required as left operand of assignment.
Now, first of all I am not sure what's the best way to dynamically add objects to a scrollview. Maybe anyone has a better or easier approach.
Then on the other hand, I don't get why the above does not work?! Would I have to cast my element to the actual class? I thought I would not have to do so... Also then my method would not make that much sense anymore. Or at least would require some more steps...
This should work I think:
[element setFrame:...];
However if you work with different UI elements in your method may be you can make your elements parameter UIView* instead of id? This way your code will work for all UIView subclasses (which is what you actually need I suppose)
The difference is that "id" doesn't have any kind of reference to a frame. It could be anything. You want to instead do (UIView *)element in the method declaration, or alternatively in the call to element.frame, you would do ((UIView *)element).frame.
(And yeah, all things that you put on the screen are inheriting from UIView -- UIButton, UIImageView, etc.)

UITableViewCell doesn't clear context before drawing

I have a subclass of UITableViewCell which contains several elements - UIImageViews, Labels, etc.
Since this cell is intended to be reusable, I want to be able to change it's appearance a bit depending on what data it is currently displaying.
So as an example - I have this view in my custom UITableViewCell:
UIImageView* delimeterView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cellDelimiter.png"]];
Which I want to be able to hide sometimes like this:
- (void) setRecord:(id)record__ {
if (record__.type == NO_DELIMETER_VIEW)
delimeterView.hidden = YES;
else
delimeterView.hidden = NO;
[self setNeedsLayout];
}
But the problem is that delimeterView will always be displayed on the cell, just like if it was drawn once in the init method and then drawing context was never changed or cleared. I've tried setting clearsContextBeforeDrawing property to YES for both cell and its contentView, I've also tried setting opaque for cell and its contentView to NO since I've read there might be some problems with that aswell in case you're using transparent views.
Nothing helps.
It looks like UITableViewCell never clears its graphic context and just paints over old elements.
Any tips on what am I doing wrong?
I know I can probably fix this by doing custom drawing but I'd rather not.
First, are you sure that delimeterView in setRecord: is actually pointing to your delimeterView? In the code example you give, you assign it to a local. Do you later assign this to an ivar? (You should always use accessors to access ivars: self.delimeterView).
Next, calling -setNeedsLayout just schedules a call to -layoutIfNeeded, which walks the hierarchy calling -layoutSubviews. The default implementation of -layoutSubviews does nothing. You probably meant to call -setNeedsDisplay here, or you need to implement -layoutSubviews to do what you want.