What to replace a UIButton to improve frame rate? - iphone

I created a minesweeper clone game and I made a 30 x 30 grid of cells. Now in my initialize design, I planned to use UIButton for each cell so that I can use its touchDown and touchUpInside. But my problem is using UIButton makes the game slow in zooming and especially in loading or adding each cell(900 pcs) in a UIView.
Now I'm planning to use images instead of UIButton and I heard about CALayer for easy animation. Can you suggest how can I use this CALayer for my implementation or replacement of UIButton?
Thanks.

I'd certainly suggest going down the Core Animation route for this. You can use an NSView subclass to recieve and handle the touch events then you could then use the location of the touch to calculate the cell that's been hit and update your model appropriately.
You arrange CALayers in a heirarchy so - whilst the complexity of the tree of views will depend on other UI elements you wish to have - you'll have a CALayer containing the 900 sub layers.
Using Core Animation will also allow you to get wizzy with animations.
It's going to be a bit more complex, but you just need to bite the bullet and get stuck into the Core Animation documentation and/or buy a book.
Good luck.
Edit: Ivan suggests using the hitTest message. This way you can get the layers to tell you which one of them was hit. Using that is obviously quite nice. However if you're looking for speed it might be quicker to avoid that and just work it out. This does make assumptions about how your game works (i.e. the buttons/cells don't move location). If you get the chance try both and let us know how it works out. :o)

On Cocoa desktop, there's NSCell, which is a lightweight alternative to NSButton, but that's an older technology before CALayer and Core Animation (they don't conflicts with each other)
To make custom button, create a custom class either extends to delegates CALayer. Then to know which button is clicked, use [hitTest] method which will return the layer being clicked efficiently.

Related

How To Move Continiously Multiple UIButtons in Specific Directions?

I have five UIButtons in my application.All these UIButtons are stored in Array.As my Code Show below
NSMutableArray *Buttons = [NSMutableArray arrayWithObjects:btn1, btn2, btn3,btn4,btn5, nil];
Now i Want to move all these UIButtons in Specific Direction Continiously.As my image show below
I Already did some animation in CAkeyframeAnimation,but As a iOS beginer its difficult for me to perform these type of Continious Animation on multiple UIButtons using CAKeyframeAnimation.Can some one help me about this.Any help will be appriated.
I don't know what you've done already, but you could use UIView Animations and then make sure you enable set the UIViewAnimationOptionAllowUserInteraction option.
You can then put a gesture recognizer on the buttons.
To get it to animate, just use UIView's block based animations, there are only 4 that need to be done, and have them repeat. It's fiddly, but it's a quick and dirty solution.
If you are trying to move these buttons around in a way that keeps them reactive to user touches, using Core Animation directly is probably not your best bet. My answer below is based on this assumption.
When a Core Animation-based animation is running, the layer you see moving on screen (the "presentation layer" — see here for more info about this) does not register touches at its current position, but only at the final position of the animation, which is invisible for the user. Thus the moving bouton will behave most of the time as if it is disabled. Though it is possible to hack around this, it is not very convenient and not meant to be used that way.
Another drawback is that CAAnimation is not very flexible once created, for example it would be tedious to stop the movement of the buttons at their current position if you ever needed to.
Instead, you should compute and move your UIButtons frames manually. To synchronize the movement with the display refresh rate and have a smooth animation, use CADisplayLink, which is a very easy to use class that you can use to register a method that will be called back each time the display is being refreshed. In this method you should update your views frames based on the desired behavior of your views.

How to create a class to apply motion-related effect to a view?

Relative newcomer here, sorry for sort of newbie question. I've tried searching for the answers.
I've coded up a way to apply a visual animation effect to a UIImageView on a view controller, based on the angle at which the user is holding the iPhone. Basically I'm using a CMMotionManager to provide an angle, then using that angle to shift a UIImageView by changing its bounds.center. Works great when everything is jammed into the view controller but I want it to be cleaner and reusable.
So I subclassed UIImageView, added to it a motion manager, a motion manager block handler and operation queue, plus a couple methods that map the device angle to a number corresponding to the shift in the UIImageView. I created a custom init method that accepted various parameters to control the visual effect. Then it was as simple as adding the instance of this class as a subview (addSubview:) to my controller's view. It was even using background threads and autorelease pools. Slick, I thought.
While it appears to work visually, for a slew of reasons (including that Instruments shows ever-increasing memory consumption), I'm thinking this is not what I should be jamming into a subclass of UIImageView. Is there a better way to architect this? For example, unlike UIViewController, a subclass of UIImageView doesn't have viewDidLoad/viewDidUnload/...appear/etc. which would let me start and stop the motion manager updates; and I should be able to create a single motion manager for the entire app instead of instantiating it in my image-effect class.
I do realize I must have only once instance of CMMotionManager per app, and have implemented Jonathan's method, but then I find myself needing to access appDelegate from my nifty class, when it would be easier to do it from the view controller, and it just spirals downward from there.
Am I asking for too much, or just not understanding a very simple concept?

Cocoa touch view with multiple identical subviews

I'm having my first foray into Cocoa Touch programming (and one of my first into Cocoa in general) and writing a simple game for the iPhone, though this question is about cocoa touch in general.
The main UI consists of a strip of identical acting buttons (only varying in colour) arranged horizontally across the screen. Although they act like buttons they need to have a custom drawn appearance. Each responds to touch events in the same way, triggering other events in the application.
I want to define a custom view, partly to have more control over the behaviour than just having a bunch of standard buttons, and partly to learn more about cocoa programming.
Should I define a main view with an array of subviews each of which draws itself and forwards touch events? Each button should do standard things like show a pressed state when touched and so on. Are there any pre-existing container views for this kind of scenario?
Or should I just define one main view which draws the whole strip and detects where a touch occurs? I feel this is a badly engineered approach - I shouldn't be programming hit test code.
Edited to clarify the question
The more lightweight approach is to add sublayers to your UIView's layer. Use hitTest: to dispatch touches you receive on you UIView to the CALayer instance that needs to receive it.
If you need more of the UIResponder behavior (touchesBegan etc.), you might want to go with subviews instead of sublayers as that would allow you to handle the events directly in the objects rather than having to dispatch them from a central responder (your main UIView).
Consequently, the essential bit may be just how much of the behavior associated with your individual buttons should be known (handled) by the your main UIView. If it makes sense to have everything controlled from a central place, you can put all the logic in the UIView and just use sublayers for lightweight display purposes. If it makes more sense to put the behavior into the buttons themselves, they shoudl be UIResponders and as such subclass UIView and be added as subviews of your main view.
You should use an array of subviews - that way each "button" class knows how to draw itself and its superview (your stated "main view") places the buttons where they need to go.
And second on the NDA: just talk about the iPhone.
If you have a lot of buttons and want to do fancy things with them, I recommend using layers. Your UIView will handle interpreting which layer had the touch (hit testing) and
respond appropriately. If all you're doing is managing a whole bunch of buttons with various effects and animations, this might be an easier route.
As for bad engineering, not at all. If you take a look at the associated guides, you'll see core animation and layers does require hit testing (though that's relatively easy), but it's far cleaner than the UIView doing all the drawing and more efficient than many subviews. It slips right between those two approaches nicely.
Full disclosure: I'm just wrapping my head around how to best leverage this stuff myself, but for more complicated interactive controls.
You can layout your view in Interface Builder. Simply drag a bunch of UIButtons in your view controller's view.
To respond to events, you define an IBAction in your view controller and connect the buttons to it.
This is all very basic. I really suggest that you at least walk through the iPhone programming introduction that Apple has online. It will teach you iPhone and Interface Builder basics.

in which situations does it make sense to create only an lighteight CALayer rather than a fat UIView?

The only thing that comes in my mind is displaying simple images. But that wouldn't make sense if you want to animate them, right? So is it any useful to make a CALayer only instead of an UIView that comes along with a whole bunch of them (all those trees...)?
You use CALayer when you are not getting any benefits from using UIView and when it's not possible to do the thing you want to do with UIView.
Following this line of thought, if your need is not making use of any UI controls and/or you want to create your own custom animation (2D or 2.5D animation), it makes sense to drop down to the CoreAnimation level and create your own CALayer to do your thing there.
If however you are only interested in performing basic animation and it can be done through UIView, the API is usually simpler, so it will make sense to use UIView to save yourself time there.

Architecting a visual grid of 'buttons'

I'm trying to design how to implement a relatively simple application.
I want to create a grid of 'squares' that cover an entire screen. Each square should have the ability to respond to touch events, and then have an on/off state. For example, if I touch an 'off' square, and then drag my finger across 10 other squares, I want them all to turn on. And vice versa.
I'm not sure of the memory overhead of just creating a grid of 150 buttons. Also buttons don't have a settable state, from what I can see. I was also thinking of subclassing UIView and implementing UIResponder methods. It feels like I should be creating an array of array of buttons (or subclass of UIViews), but I'm not sure if that's possible.
I'm assuming that I can tell what square I'm on by getting the location of the touchevent from the UIResponder methods. Do I need to create my own version of a myButton by subclassing UIView, and have a on/off state property, along with UIResponder methods, and then create an array of myButtons?
UISwitch is the only thing that does this at the moment, though some have had good experiences using the UISegmentedControl for this as well.
Beyond that, you'll have to change the style/color of a regular button or image in code, which is what a lot of application developers do so it looks and reacts exactly the way they want it to.
Unless you need more of UIView's event handling stuff, you'll get the best performance if you use a single view and give it a -touchesBegan:withEvent, -touchesMoved, and -touchesEnded methods. Then use a custom drawRect method to draw your individual squares in either on or off states. You could also use layers, but trying to lay out 150 views is asking for trouble.