How to Use UIGesterRecognizer within Subclass - iphone

I have a subclass:
CustomView : UIScrollView.
Inside of this subclass I have some methods that, say, populate my custom view with some UI elements. I want to add UIGesterRecognizer functionality to these elements but I do not know how to handle setting the delegate and adding selectors:
#implementation CustomView
-populateMe{
UIImageView *iv = [...];
UIGesterRecognizer r = [UIGesterRecognizer alloc]
initWithTarget:self
action:#selector(handleMySwipe:);
//<==where to declare handler
r.delegate = self; //<==COMPILER ERROR self
[iv.addGestureRecognizer r];
}
So my problem is where I commented above: self is not a valid delegate (I tried self.superclass) and where do I need to declare a handler for action, i.e. handleMySwipe.
Please explain so I understand.

CustomView is potentially a delegate, if you implement the UIGestureRecognizerDelegate protocol for it. That is, implement a few methods within your CustomView class that the protocol requires you to.
Once you've done that, you should be able to set the target parameter to self without any errors. Since your target is now self, you need to implement the selector/method handleMySwipe: within your CustomView class because that is where it will look for it (the target).
- (void) handleSwipe:(UIGestureRecognizer *)gr {
}

Related

access a controllers variable or method from within the views subview class

Good Evening,
Here is the problem, [self.view addSubview:pauseView];
before the pauseView is loaded over the current view a BOOL isPaused is turned to false and then the subview appears. i am trying to change the value of the variable to false from withing the pauseview but since it's not on the current class i am unable to do this.
I know that this topic is already covered in stackoverflow but i still cannot solve my problem. If i'm able to solve this problem, it will solve the same kind of problem in 3 others apps of mine.
Sincerely,
Sonic555gr
Define isPaused as a property in the class that defines isPaused (let's call it MasterView):
// inside MasterView.h
#property (nonatomic,assign) BOOL isPaused;
Then make your subview pauseView a custom UIView subclass (let's call it PauseView) and in this subclass define a property called master of type MasterView:
// inside PauseView.h
#property (nonatomic,assign) MasterView *master
Then when you alloc/init your pauseView just set this property:
// somewhere inside MasterView.m
PauseView *pauseView = [[PauseView alloc] initWithFrame:frame];
pauseView.master=self;
Finally in your PauseView class, in the point of your code where you want to change the isPaused property, do this:
// somewhere in PauseView.m
master.isPaused=YES
You really should have a think about your architecture and try to move your application logic from away from UIViews and back to the controller (i.e. delegates might be a good option but impossible to know without seeing more of your code and what you are trying to achieve).
If you insist on manipulating the variable from the UIView, you need to pass a reference of your viewController to the pauseView when you initialise it.
So in your PauseView class, you would create a custom initialiser:
-(id)initWithFrame:(CGRect)frame andViewController:(id)vc {
self = [super initWithFrame:frame];
if (self) {
// Any other custom initialisation here
}
}

Where does the init *really* happen in a UIView placed in Interface builder?

I have a subclass of UIView called SlideOut. I want to capture the IB placement of the view when it loads, so I have this in my implementation:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
IBframe.origin.x = frame.origin.x;
IBframe.origin.y = frame.origin.y;
IBframe.size.height = frame.size.height;
IBframe.size.width = frame.size.width;
// Initialization code.
NSLog(#"init if self x: %f, y: %f", IBframe.origin.x, IBframe.origin.y);
}
NSLog(#"init x: %f, y: %f", IBframe.origin.x, IBframe.origin.y);
return self;
}
... with a matching prototype in the .h file.
Upon starting up the simulator, I get all my other diagnostics, but neither of these log messages get called. So how does the instance actually get initialized? Or am I missing something? The position function works, but then fails because I haven't captured the actual frame of the thing. In any case, that's how I know I made the IB connections correctly.
Take a look here: Subclassing UIView, "Methods to Override", from UIView Class Reference.
In particular:
initWithCoder: - Implement this method
if you load your view from an
Interface Builder nib file and your
view requires custom initialization.
Objects that are loaded from an xib are actually unarchived. Thus, you should be using the initWithCoder: method. Alternatively, you may way to look at awakeFromNib instead.
I believe the function that gets called when the view is loaded from a NIB is initWithCoder not initWithFrame

warning: class 'CardController' does not implement the 'UIGestureRecognizerDelegate' protocol

In my app i am trying to detect swipe gesture to navigate to the next page ...
Please find my below code below
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRightAction:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
swipeRight.delegate = self;
[cardsGridView addGestureRecognizer:swipeRight];
when i run my application, i get the below warning...
warning: class 'MyGesture' does not implement the 'UIGestureRecognizerDelegate' protocol
Kindly help me up that what i am missing here.
UPDATE1 : can anybody pls show me a working code to detect the swipe....
The UIGestureRecognizerDelegate protocol only defines optional methods. There are now two ways to get rid of the warning:
Do not set the delegate at all if you do not need any of those optional delegate methods. Your swipeRightAction method call will work anyway as you specify the target and the selector in the initializer.
If you need to set the delegate, indicate in the header file of your delegate class that the class implements the protocol by specifying it in angle brackets after your superclass name:
#interface YourClass : UIViewController <UIGestureRecognizerDelegate> {
...
}
Edit: Thanks, I forgot to escape the angle brackets.

Subclasses of UIButton loaded from nibs are not initialized properly

I have a very simple subclass of UIButton:
#interface MyButton : UIButton
#end
#implementation MyButton
- (id) initWithCoder:(NSCoder *)decoder
{
if (!(self = [super initWithCoder:decoder]))
return nil;
NSLog(#"-[%# initWithCoder:%#]", self, decoder);
return self;
}
#end
In Interface Builder I add a UIButton, set its button type to Rounded Rect and its class identity to MyButton.
When running, I have the following log:
-[<MyButton: 0x5b23970; baseClass = UIButton; frame = (103 242; 114 37); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x5b23a90>> initWithCoder:<UINibDecoder: 0x6819200>]
but the button is not a round rect button anymore.
Observed on both iOS 3.2 and iOS 4.
Is this a bug or am I missing something obvious?
Create an instance of MyButton programmatically is not an acceptable answer, thanks.
Programmatically, you instantiate a button with +[UIButton buttonWithType:] which is actually a factory that returns a subclass of UIButton. So if you derive from UIButton you actually don't derive from your round rect button class (UIRoundedRectButton) but from a generic button class. But you are not allowed to subclass from UIRoundedRectButton AFAIK since it's an internal class.
It seems to be problematic to derive from UIButton, I've seen a lot of people recommed to derive from UIControl instead and implement the drawing yourself.
But you might find these articles helpful:
How to override -drawrect in UIButton subclass?
http://www.cocoabuilder.com/archive/cocoa/284622-how-to-subclass-uibutton.html
http://www.cimgf.com/2010/01/28/fun-with-uibuttons-and-core-animation-layers/
Also, I don't know why you want to derive from UIButton, but if you want to do some customization that does not involve overwriting any other methods it might be helpful to use the fact that you can do something like this:
- (id)initWithCoder:(NSCoder *)decoder {
// Decode the frame
CGRect decodedFrame = ...;
[self release];
self = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self setFrame:decodedFrame];
// Do the custom setup to the button
return self;
}
I’m not sure if this is acceptable for your needs, but I tend to prefer to override -awakeFromNib instead of -initWithCoder: in these circumstances. Does doing this resolve the issue you’re seeing?

initializing UIView subclass with parameters in iphone sdk?

Iam a newbiew to iPhone development. Version of my SDK is 2.2
In my code, UIViewController is used to change view dynamically once the app is launched, a method in the UIViewController is called to know which view should be initialized along with parameters, which goes to a 'switch-case' and assign a view to current view according to the parameter, like this:
case 1:
currentView = [[View01 alloc] init];
break;
case 2:
currentView = [[View02 alloc] init];
break;
and outside the switch-case:
[self.view addSubview:currentView.view];
I wonder f can pass a parameter along with initialization, like iniWithNibName or so? I need this because have to manipulate in the leaded view, according to the view from which its called.
Thanks.
One way to approach this is to modify your View01 and View02 classes to include an initWithParam: initialiser.
i.e. add
- (id) initWithParam:(NSString *)myParam;
to the #interface section and add
- (id) initWithParam:(NSString *)myParam {
if (self = [self init]) {
// handle or store 'myParam' somewhere for use later
}
return self;
}
to the #implementation section. Notice how the initWithParam: message internally calls the existing init. Obviously you could change the type, or number of parameters passed in as required.
Another approach would be to provide a property on your view class, so you could do something like the following:
currentView = [[View01 alloc] init];
currentView.myParam = #"SomeValue";
Which approach works the best will depend somewhat on your particular application needs.