i have made some #properties of uiimage view type in a class and then initialized that class in my rootviewcontroller.
questions.h:
#property(nonatomic,strong)UIImageView *img1;
#property(nonatomic,strong)UIImageView *img2;
#property(nonatomic,strong)UIImageView *img3;
#property(nonatomic,strong)UIImageView *img4;
'viewcontroller.m'
-(void)viewdidload{
questions *q1=[[questions alloc]init];
q1.img1 =[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"red.png"]];
[self.view addSubview:q1.img1];
UITapGestureRecognizer *Tap1 = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(iTap:)];
[q1.img1 addGestureRecognizer:Tap1];
}
-(void)iTap:(UIGestureRecognizer *)gestureRecognizer {
// do something..
}
i know its not a good idea to populate viewdidload with initialization code..
is there any better way to acive this using class methods ?
like :
questions.m:
+(questions * )mymethod{
questions *q1=[[questions alloc]init];
q1.img1 =[[uiimageview alloc]initwithimage [uimage imagenamed#"red.png"]];
[self.view addSubview:q1.img1];
UITapGestureRecognizer *Tap1 = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(iTap:)];
[q1.img1 addGestureRecognizer:Tap1];
return q1;
}
and then calling that method in viewdidload
viewcontroller.m:
-(void)viewdidload{
[questions mymethod];
}
There's nothing really wrong with creating adding views in viewDidLoad. You can however also use - [UIViewController loadView].
Related
I have a UIViewController where I'm adding bunch of UIViews as subviews. Then I attach UIGestureRecognizer to each, so I can be notified when there's a tap. Here's the code inside the UIViewController:
- (void)attachSubview{
UIImageView *childView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"child"]] ;
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[childView addGestureRecognizer:singleFingerTap];
[self.view addSubView childView];
}
- (void)tapped:(UITapGestureRecognizer *)recognizer{
NSLog(#"Tapped view : %#", recognizer.view);
NSLog(#"The root view is : %#", self.view);
}
Now, here's the problem: I actually want to extract these two methods out into a separate class. In this case I can't use the self.view inside the tapped: method, since self wouldn't be the viewcontroller class anymore.
So I would like a simple and efficient way to just take the recognizer object and somehow get the root view to which the image view belongs. What is the best and future proof way to do this?
Could you try this please?
- (void)viewDidLoad {
[super viewDidLoad];
//example of its use. You can replace with [className attachSubview:self.view] for example
self.view = [self attachSubview:self.view];
}
- (UIView *)attachSubview:(UIView *)passedInView{
UIImageView *childView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"child"]] ;
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[childView addGestureRecognizer:singleFingerTap];
[passedInView addSubview:passedInView];
return passedInView;
}
- (void)tapped:(UITapGestureRecognizer *)recognizer{
NSLog(#"Tapped view : %#", recognizer.view);
NSLog(#"The root view is : %#", recognizer.view.superview);
}
I tried to use initWithFrame but I am not able to display the UIView, This kind of code solved many questions as I saw here but not in my case:
- (id)initWithFrame:(CGRect)frame myParams:(NSArray*)params;
.m file
- (id)initWithFrame:(CGRect)frame myParams:(NSArray*)params{
self = [super initWithFrame:frame];
if(self){
UIView *view = [UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
//Trying to send an uiview with gesture include
view.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(test)];
[view addGestureRecognizer:tap];
[self addSubview:view];
}
return self;
}
Here is how I am trying to add the view in UIViewController:
Maybe here I am doing it wrong, right?
Custom *view = [Custom alloc] initWithFrame:self.view.bounds myParams:array];
[self.view addSubview:view];
So, my question is it possible to add UITapGesture in the UIView generated in this class, cause it is not firing:
.h file
+ (UIView *)viewParams:(NSArray*)params;
.m file
+ (UIView *)viewWithParams:(NSArray*)params{
UIView *view = [UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
NSLog(#"read params %#", params);
//Trying to send an uiview with gesture include
view.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(test)];
[view addGestureRecognizer:tap];
return view;
}
- (void)test{
NSLog('it works...');
}
UPDATE : As instance method is working. But as class method I can not make it work. somebody know if possible?
1st Part
If you are using XIB for your customView then you need to use awakeFromNib method. But if you are trying to create through code only then just use initWithFrame: method and add your gesture recognizer in the initializer.
2nd Part
For firing tap gesture recognizer you are adding recognizer target self i.e your customView. So event will fire in your customViewClass class only then to get these events in your controller you need to use protocol and delegate. And set the delegate of customView to whatever controller you want to use in the controller.
View will add after firing the initwithcoder just use this code in init with coder ...
dispatch_after(0.1, dispatch_get_main_queue(), ^(void)
{
UIView *view = [UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
//Trying to send an uiview with gesture include
view.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(test)];
[view addGestureRecognizer:tap];
[self addSubview:view];
});
}
return self;
}
Minimum Time interval 0.1 max time interaval set as per your data load requirement
setting delegate for UITapGesture giving warning
Here is my code :
UITapGestureRecognizer *tapOtherPlayers = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapcollectionViewOtherPlayers:)];
tapOtherPlayers.delegate = self;
[tapOtherPlayers setNumberOfTapsRequired:1];
[collectionViewOtherPlayers addGestureRecognizer:tapOtherPlayers];
You need to add UIGestureRecogniserDelegate in your .h file as following :
Hope it helps..
Make "tapOtherPlayers" Variable as global and set UIGestureRecognizerDelegate delegate as bellow.
#interface ViewController ()<UIGestureRecognizerDelegate>{
UITapGestureRecognizer *tapOtherPlayers;
}
#end
#implementation ViewController
- (void)viewDidLoad {
tapOtherPlayers = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapcollectionViewOtherPlayers:)];
tapOtherPlayers.delegate = self;
[tapOtherPlayers setNumberOfTapsRequired:1];
[collectionViewOtherPlayers addGestureRecognizer:tapOtherPlayers];
}
Hope this will help you...
I'm trying to build a generic class with a couple of Gesture Recognizers, so that I can call one method and have both Recognizers added to the view
Here is my class implementation code
#import "saUIHelper.h"
#implementation saUIHelper
-(void)handlePan:(UIPanGestureRecognizer *)recognizer
{
NSLog(#"pan");
}
-(void)handleLP:(UILongPressGestureRecognizer *)recognizer
{
NSLog(#"Test");
}
-(saUIHelper*)initWithView:(UIView*)view
{
self = [super init];
if(self){
self.myView = view;
self.myView.userInteractionEnabled = YES;
}
return self;
}
-(void)start
{
UIPanGestureRecognizer* panRecognizer =
[[UIPanGestureRecognizer alloc]
initWithTarget:self
action:#selector(handlePan:)];
[self.myView addGestureRecognizer:panRecognizer];
UILongPressGestureRecognizer* lpRecognizer =
[[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleLP:)];
[self.myView addGestureRecognizer:lpRecognizer];
}
#end
And I try to use it like this
UIImage *playImg = [UIImage imageNamed:#"playBtn"];
self.playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
self.playBtn.frame = CGRectMake(0.0f,0.0f, 60.0f, 60.0f);
self.playBtn.center = CGPointMake(viewWidth/2,(viewHeight/2)-35);
[self.playBtn setBackgroundImage:playImg forState:UIControlStateNormal];
[self.playBtn addTarget:self action:#selector(play:) forControlEvents:UIControlEventTouchUpInside];
[self.menu addSubview:self.playBtn];
saUIHelper* helper = [[saUIHelper alloc] initWithView:self.playBtn];
[helper start];
When I run this code and do a Pan or LongPressure gesture on the button I added, I get a crash with BAD_ACCESS_EXEC code
If however instead of calling [helper start]; I type in the same code as implemented in the start method, and add the handlePan: and handleLP: callbacks to the main class, I get no issues and everything runs fine
It's obvious I'm doing something very wrong here, not sure if it's threading issues or something else, can anyone give me some pointers?
Store a strong reference to saUIHelper* helper in your view/viewcontroller so that it doesn't get dealloced. You're probably getting a crash because the target is the helper, which might have been dealloced.
I have created a UIViewController, which contains a UIView object.
I want the UIView object response to a single tap by 1 finger, and also pinch by 2 fingers.
I have clicked the "User Interaction Enabled" and the "Multiple touch" options in the xib.
I create both UITapGestureRecognizer, and UIPinchGestureRecognizer inside the UIView function initWithFrame:, as it is the only entry point for the UIView object. But the object doesn't response to the UIGestureRecognizer objects. Why? Or, where is the best place to put the UIGestureRecognizer objects?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// single tap
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self addGestureRecognizer: singleTap];
// 2 fingers pinch
UIPinchGestureRecognizer* doubleMove = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleMove:)];
[self addGestureRecognizer: doubleMove];
}
return self;
}
Your problem is that when you instantiate your custom view subclass in IB, initWithCoder: is called. If you had done it programmatically using initWithFrame: it would have worked properly.
Two ways you can fix this,
Move the gestures setup to a different method and call them in both initWithFrame: and initWithCoder:. I would recommend doing this if you intend to reuse this component and expose some kind of callbacks on gestures.
If you want to implement this once and have a lot of interacting with the controller element, add them in viewDidLoad.
I tried your code and it works for me.
Where are you setting the view? Maybe it has any other view in front, or its superview has userInteractionEnabled disabled.
I created a UIView subclass and added this code:
-(void) handleSingleTap:(UITapGestureRecognizer *)gr {
NSLog(#"handleSingleTap");
}
-(void) handleDoubleMove:(UIPinchGestureRecognizer *)gr {
NSLog(#"handleDoubleMove");
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// single tap
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self addGestureRecognizer: singleTap];
// 2 fingers pinch
UIPinchGestureRecognizer* doubleMove = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleMove:)];
[self addGestureRecognizer: doubleMove];
}
return self;
}
Then, in my controller:
-(void) viewDidLoad {
[super viewDidLoad];
MyView * myView = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
myView.backgroundColor = [UIColor greenColor];
[self.view addSubview:myView];
[myView release];
}
And it works.
i think if you are working with .xib, initialization can also be done in
-(void)awakeFormNib;
Adding the GestureRecognizers is typically done in the viewDidLoad method of the UIViewController.