How to pass target parameter for UIButton? - ios

I write one category method in UIView+Extensions.m:
#interface UIView (Extensions)
+ (UIView*)configureMoreViewWithBtns:(NSArray*)btnsConf;
#end
+ (UIView*)configureMoreViewWithBtns:(NSArray*)btnsConf
{
UIView* moreView = [[self alloc] initWithFrame:CGRectMake(195, 180, 120, 100)];
[moreView setBackgroundColor:[UIColor lightGrayColor]];
for (int i = 0; i < btns.count; i++) {
NSDictionary* confDict = btnsConf[i];
UIButton* btn = [[UIButton alloc] initWithFrame:CGRectMake(0, i*30 + 10, 120, 20)];
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[btn setTitle:confDict[#"title"] forState:UIControlStateNormal];
[btn addTarget:self
action:NSSelectorFromString(confDict[#"selector"]
forControlEvents:UIControlEventTouchUpInside];
[moreView addSubView:btn];
}
return moreView;
}
But this implement is wrong, because i don't know how pass target parameter from my ViewController?
In my viewController, i called this method like this:
- (void)handleMoreImageTapped:(UITapGestureRecognizer*)gestureRecognizer
{
NSLog(#"%s", __FUNCTION__);
UITableViewCell* tappedCell = [UIView tableViewCellFromTapGestture:gestureRecognizer];
NSArray* btnsConf = #[
#{#"title": #"分享", #"selector": NSStringFromSelector(#selector(handleShare:))},
#{#"title": #"私信", #"selector": NSStringFromSelector(#selector(handleSiXin:))},
#{#"title": #"举报或屏蔽", #"selector": NSStringFromSelector(#selector(handleJuBao:))}
];
UIView* moreView = [UIView configureMoreViewWithBtns:btnsConf];
}

You need to also pass the target (the object the selector would be called on, in this case the viewcontroller from which you call the configuremoreviewwithbtns method) in the dictionairies.
So a dictionairy you add to the array would become
#{#"title": #"thetitle", #"selector": NSStringFromSelector(#selector(theselector:)), #"target": self},
and you'd have to change the UIView extension to this:
[btn addTarget:confDict[#"target"]
action:NSSelectorFromString(confDict[#"selector"]
forControlEvents:UIControlEventTouchUpInside];

Related

Creating UIButtons Programmatically - unrecognized selector sent to instance

Relevant code:
- (void) createButtons {
NSMutableArray *buttonTitleArray = [[NSMutableArray alloc] init];
[buttonTitleArray addObject:#"Website"];
[buttonTitleArray addObject:#"Blah"];
[buttonTitleArray addObject:#"Blah"];
int xPosition = 20;
for (int i = 0; i <= buttonTitleArray.count-1; i++) {
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(xPosition, 25, 90, 40)];
button.userInteractionEnabled = TRUE;
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:[buttonTitleArray objectAtIndex:i] forState:UIControlStateNormal];
button.backgroundColor = [UIColor colorWithRed:1 green:200.0/255.0 blue:0 alpha:1];
button.titleLabel.font = [UIFont systemFontOfSize:17];
[self.buttonArray addObject:button];
xPosition += 91;
}
for (UIButton *button in self.buttonArray) {
[button addTarget:self action:#selector(showWebsite:) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:button];
}
}
- (void)showWebsite:(UIButton *)sender {
NSLog(#"Website");
}
In init:
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.buttonArray = tempArray;
For testing purposes I made all the buttons have the same target.
When I click the button, I get unrecognized selector sent to instance.
Any thoughts here?
For some reason your self in your posted code gets released and the pointer location gets re-used by the OS as a UIGestureDelayedTouch.
Make sure the object that you are creating these buttons in does not get released by the OS before you want to use the showWebsite function.
Sometimes people use code like:
-(void)function
{
UIViewController *controller = [[UIViewController alloc] init];
[someOtherView addSubview:controller.view];
}
In this case at the end of the function the controller gets released (as there are no further references to it) and anything that could point to it in the future will point to an invalid (deallocated and possibly re-used) object.
UIButton does not retain objects set as targets, so the OS thinks the objects are valid for release if they are not retained by anything else in the program.

Button #selector not working if button defined in NSObject

I have the following problem: I am trying to define a button in an NSObject (in a separate file) and add it to my ViewController:
NSObject method:
in obj.h:
+(void)NewButtonInView:(UIView *)view withAction:(SEL)actionbutton;
in obj.m
+(void)NewButtonInView:(UIView *)view withAction:(SEL)actionbutton {
UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(0, 0, 50, 50);
[button addTarget:self action:actionbutton forControlEvents:UIControlEventTouchUpInside];
}
in my ViewCotroller I import the obj.h and:
[obj NewButtonInView:[self view] withAction:#selector(actionB:)];
and:
-(void)actionB:(UIButton *)button {
//some code
}
The button looks fine but when I click it I get the following error:
"[obj actionB:]: unrecognized selector sent to class"
Any help is appreciated.
Thank you.
the problem is this line
[button addTarget:self action:actionbutton forControlEvents:UIControlEventTouchUpInside];
specifically, the use of self. You put the actionB: method in the viewController, but because the NewButtonInView:withAction: method is in a class method of obj self refers to the class obj. To fix it pass in the view controller as a parameter to the method like this
+(void)NewButtonInView:(UIView *)view withAction:(SEL)actionbutton target: (id) target {
UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(0, 0, 50, 50);
[button addTarget: target action:actionbutton forControlEvents:UIControlEventTouchUpInside];
}
Try defining it with a return value, as follows:
+(UIButton *)NewButtonInView:(UIView *)view withAction:(SEL)actionbutton withTarget:(id)target{
UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(0, 0, 50, 50);
[button addTarget:target action:actionbutton forControlEvents:UIControlEventTouchUpInside];
return button;
}
Then when you call it:
UIButton *button = [obj NewButtonInView:[self view] withAction:#selector(actionB:) withTarget:self];
Not sure why you're doing it in an NSObject instead of in your view controller, but that's the way to go about it if you do.

How to get index of uiimage subview of uiscrollview

I need to detect selected image of uiimage which is placed inside scrollview.
My code is here:
int newscrollviewY = 40;
for(int i = 0; i<1; i++)
{
scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(5, newscrollviewY, 310, 100)];
scrollView.showsVerticalScrollIndicator = YES;
scrollView.scrollEnabled = YES;
scrollView.userInteractionEnabled = YES;
scrollView.backgroundColor = [UIColor clearColor];
scrollView.delegate=self;
int imgx = 1;
for(int img=0; img<[images count]; img++)
{
UIImageView *imageView1 = [[UIImageView alloc]initWithFrame:CGRectMake(imgx,0,100,100)];
imageView1.backgroundColor = [UIColor whiteColor];
imageView1.image = [images objectAtIndex:img];
imageView1.contentMode = UIViewContentModeScaleAspectFit;
[imageView1 setNeedsDisplay];
[imageView1 setUserInteractionEnabled:YES];
[imageView1 setMultipleTouchEnabled:YES];
[scrollView addSubview:imageView1];
imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
imageButton.frame = CGRectMake(imgx,0,100,100);
[imageButton addTarget:self action:#selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
imageButton.tag = img;
[scrollView addSubview:imageButton];
imgx = imgx + 103;
}
Please help to detect selected image using imageButton or something else.
Replace your selector with buttonClicked:
be Sure that you are adding ":" after selector method. follow or replace the code below:
[imageButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
then Add the selector definantion in .m file
- (void) buttonClicked: (id) sender
{
// here you can get the tag of button.
NSInteger tag = ((UIButton *)sender).tag;
// do your implementation after this
}
Hope this will solve your issue. Enjoy Coding..!!
They way you have set it up the tag of the 'button' is already the number of the image in your array of images. So all you need to do is get the tag from the 'button'.
Make sure the button clicked function retrieves the tag from the sender(id) that you receive.
For example a bit like this:
- (IBAction)buttonClicked:(id)sender {
UIButton *button = (UIButton *)sender;
UIImage selectedImages = [images objectForKey: [button tag]];
}
As par you question if you are using UIImageview you have to use UITapGestureRecognizer that same like Button. you just need to add UITapGestureRecognizer like:-
for(int img=0; img<[images count]; img++)
{
UIImageView *imageView1 = [[UIImageView alloc]initWithFrame:CGRectMake(imgx,0,100,100)];
imageView1.backgroundColor = [UIColor whiteColor];
UITapGestureRecognizer *frameTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(frameTapGesture:)];
frameTapGesture.numberOfTapsRequired=1;
imageView1.image = [images objectAtIndex:img];
imageView1.contentMode = UIViewContentModeScaleAspectFit;
[imageView1 setNeedsDisplay];
[imageView1 setUserInteractionEnabled:YES];
[imageView1 setMultipleTouchEnabled:YES];
imageView1.tag=img;
[_imgView addGestureRecognizer:frameTapGesture];
[scrollView addSubview:imageView1];
}.
- (void)frameTapGesture:(UITapGestureRecognizer*)sender
{
UIView *view = sender.view; //cast pointer to the derived class if needed
NSLog(#"%d", view.tag);
}
Reduce your code There are No need to add Button with same Frame of ImageView For getting Click Event or you can also set Image of UIButton for you want to like use UIBUtton then remove UIImageview Code else you simply use UITapGestureRecognizer with getting click event using - (void)frameTapGesture:(UITapGestureRecognizer*)sender
Please try this code
for(int img=0; img<[images count]; img++)
{
imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
[imageButton setImage:[UIImage imageNamed:[images objectAtIndex:i]] forState:UIControlStateNormal];
imageButton.frame = CGRectMake(imgx,0,100,100);
[imageButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
imageButton.tag = img;
[scrollView addSubview:imageButton];
imgx = imgx + 103;
}
- (void) buttonClicked: (id) sender
{
UIButton *button = (UIButton *)sender;
UIImage selectedImage = button.currentImage;
}
set button target
[button addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
// get Button Action
-(void) buttonAction:(UIButton *)sender
{
NSLog(#"%dl",sender.tag);
// do your implementation after this
}

Can't pass UIButton image with viewWithTag

I don't understand why I'm getting "[UIScrollView imageView]: unrecognized selector sent to instance"
for (int i=0;i<[imagesForGame count];i++)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(i*310, 0, 310, 200);
[button setImageWithURL:[NSURL URLWithString:[imagesForGame objectAtIndex:i]] forState:UIControlStateNormal];
[button addTarget:self action:#selector(openFullPic:) forControlEvents:UIControlEventTouchUpInside];
[_myScroller addSubview:button];
}
-(void)openFullPic:(UIButton *)sender
{
UIButton *random = (UIButton *)[_myScroller viewWithTag:sender.tag];
UIImageView *test = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
test.image = random.imageView.image; // <-- Error
...
}
The sender will be a button anyway, so use it instead.
-(void)openFullPic:(UIButton *)sender
{
UIButton *random = (UIButton *)sender;
UIImageView *test = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
test.image = random.imageView.image; // <-- No more error.
...
}
Because you never set the tag for the button.
Do in the first loop, button.tag = i;
You have UIButtons instance in sender variable so you don't need to use viewWithTag at all ;-)

UIScrollView with a large number of UIButtons

What I want is a UIView with lots of UIButtons in it. They get placed and arranged according to data stored in an NSArray. Because there are quite a lot of buttons they don't fit on the screen all at once. The user should be able to zoom out to see all the buttons or to zoom in to see details (the label on them) and to easily select them.
I tried two different approaches:
1) I constructed a UIView subclass, put the buttons in it and an instance of this View inside a UIScrollview.
Effect: I can access all Buttons via their tag and scrolling and zooming works fine. BUT I can't get the buttons to handle any events (press on them)...
2) I wrote a UIViewController with exactly the same functionality and added an instance of it to the UIScrollView.
Effect: I can press the buttons now, but scrolling and zooming have stopped to work.
Here the relevant Code of the View:
- (UIView *)initWithArray:(NSArray *)nArray{
self = [super init];
if (self) {
int count = [nArray count];
for (int i=0; i<count; i++) {
UIButton *button = [[UIButton alloc]
initWithFrame:(__some Code to place the Button__);
button.tag = i+1;
NSString *title = [[NSString alloc] initWithFormat:__code for generating Title__];
[button setTitle:title forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:14];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
[self addSubview:button];
}
}
return self;
}
And the Code for the matrixController:
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *nArray = [[NSMutableArray alloc] __some code___];
int count = [nArray count];
for (int i=0; i<count; i++) {
UIButton *button = [[UIButton alloc]
initWithFrame:CGRectMake(__some Code to place the Button__];
button.tag = i+1;
NSString *title = [[NSString alloc] initWithFormat:__code for generating Title__];
[button setTitle:title forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:14];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:button];
}
}
And the code for the ScrollViewController:
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 768, 970)];
[self.view addSubview:scrollView];
[scrollView setBackgroundColor:[UIColor blackColor]];
//Zooming
[scrollView setMinimumZoomScale:0.25];
[scrollView setMaximumZoomScale:4.0];
[scrollView setDelegate:self];
// constructing the view
[scrollView addSubview:chartView];
[scrollView bringSubviewToFront:chartView];
OR
[scrollView addSubview:[matrixController view]];
How can I get this to work??
I'm able to get a scroll view containing multiple buttons to pan and zoom just fine, with the buttons still handling touch events:
- (void)didTapButton:(UIButton *)button
{
NSLog(#"Button %ld", (long)button.tag);
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
scrollView.delegate = self;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * 3.0f, scrollView.frame.size.height * 3.0f);
scrollView.maximumZoomScale = 3.0f;
UIView *zoomView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, scrollView.contentSize.width, scrollView.contentSize.height)];
zoomView.backgroundColor = [UIColor whiteColor];
for (NSInteger index = 0; index < 100; index++)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake((scrollView.frame.size.width / 2.0f) - 50.0f, 10.0f + (50.0f * (CGFloat)index), 100.0f, 30.0f);
button.tag = index;
[button setTitle:[NSString stringWithFormat:#"Button %ld", ((long)index + 1)] forState:UIControlStateNormal];
[button addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
[zoomView addSubview:button];
}
[scrollView addSubview:zoomView];
[self.view addSubview:scrollView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return [scrollView.subviews objectAtIndex:0];
}
EDIT: I said not to rely on tag in my comment below, yet I'm doing in here. :) It's merely so I could log the button number, so that part should be ignored.
for (int i=0; i<10; i++)
{
UIButton *scrollingbutton_outlet = [[UIButton alloc] init];
scrollingbutton_outlet = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *img = [UIImage imageNamed:#"box_normal.png"];
scrollingbutton_outlet.frame = CGRectMake(0, 100, img.size.width, img.size.height);
[scrollingbutton_outlet setTitle:[NSString stringWithFormat:#"%d",i+1] forState: UIControlStateNormal];
scrollingbutton_outlet.tag=i+1;
[buttonArray addObject:[NSString stringWithFormat:#"%d",i+1]];
buttonArray = [[NSMutableArray alloc] init];
[scrollingbutton_outlet setBackgroundImage:img forState:UIControlStateNormal];
[scrollingbutton_outlet addTarget:self
action:#selector(scrollbuttonpress:)
forControlEvents:UIControlEventTouchUpInside];
scrollingbutton_outlet.frame = CGRectMake(img.size.width*i,0, img.size.width, scrollviewoutlet.frame.size.height);
[scrollviewoutlet addSubview:scrollingbutton_outlet];
width = scrollingbutton_outlet.frame.size.width;
height = scrollingbutton_outlet.frame.size.height;
scrollviewoutlet.contentSize = CGSizeMake(width*i+scrollingbutton_outlet.bounds.size.width+5, height);
}

Resources