I want to pass the movie url from my dynamically generated button to MediaPlayer:
我想将动态生成的影片url传递给MediaPlayer:
[button addTarget:self action:@selector(buttonPressed:) withObject:[speakers_mp4 objectAtIndex:[indexPath row]] forControlEvents:UIControlEventTouchUpInside];
but action:@selector() withObject:
does not work?
但是action:@selector() withObject:不起作用吗?
Is there any other solution?
还有别的办法吗?
Thanks for help!
谢谢你的帮助!
11 个解决方案
#1
59
Edit. Found a neater way!
编辑。发现了一个整洁!
One argument that the button can receive is (id)sender
. This means you can create a new button, inheriting from UIButton, that allows you to store the other intended arguments. Hopefully these two snippets illustrate what to do.
按钮可以接收的一个参数是(id)sender。这意味着您可以创建一个新的按钮,继承自UIButton,它允许您存储其他预期的参数。希望这两个片段能说明该怎么做。
myOwnbutton.argOne = someValue
[myOwnbutton addTarget:self action:@selector(buttonTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
and
和
- (IBAction) buttonTouchUpInside:(id)sender {
MyOwnButton *buttonClicked = (MyOwnButton *)sender;
//do as you please with buttonClicked.argOne
}
This was my original suggestion.
这是我最初的建议。
There is a way to achieve the same result, but it's not pretty. Suppose you want to add a parameter to your navigate
method. The code below will not allow you to pass that parameter to navigate
.
有一种方法可以达到同样的结果,但它并不好看。假设您想向导航方法添加一个参数。下面的代码不允许您传递该参数进行导航。
[button addTarget:self action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];
To get around this you can move the navigate method
to a class of it's own and set the "parameters" as attributes of that class...
要解决这个问题,您可以将导航方法移动到它自己的类中,并将“parameters”设置为该类的属性……
NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];
Of course you can keep the navigate method in the original class and have it called by navAid, as long as it knows where to find it.
当然,您可以在原始类中保留导航方法,并让navAid调用它,只要它知道在哪里找到它。
NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.whereToCallNavigate = self
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];
Like I said, it's not pretty, but it worked for me and I haven't found anyone suggesting any other working solution.
就像我说的,它不漂亮,但它对我起作用了,我还没有发现任何人提出任何其他可行的解决方案。
#2
31
I found solution. The call:
我发现解决方案。电话:
-(void) someMethod{
UIButton * but;
but.tag = 1;//some id button that you choice
[but addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
And here the method called:
这里的方法叫做:
-(void) buttonPressed : (id) sender{
UIButton *clicked = (UIButton *) sender;
NSLog(@"%d",clicked.tag);//Here you know which button has pressed
}
#3
11
You can sub-class a UIButton named MyButton, and pass the parameter by MyButton's properties.
您可以子类化一个名为MyButton的UIButton,并通过MyButton的属性传递参数。
Then, get the parameter back from (id)sender.
然后,从(id)发送方获取参数。
#4
11
I made a solution based in part by the information above. I just set the titleLabel.text to the string I want to pass, and set the titleLabel.hidden = YES
我根据上面的信息做了一个部分的解决方案。我刚刚设置了标题。文本到我想要传递的字符串,并设置titleLabel。隐藏= YES
Like this :
是这样的:
UIButton *imageclick = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
imageclick.frame = photoframe;
imageclick.titleLabel.text = [NSString stringWithFormat:@"%@.%@", ti.mediaImage, ti.mediaExtension];
imageclick.titleLabel.hidden = YES;
This way, there is no need for a inheritance or category and there is no memory leak
这样,就不需要继承或类别,也不需要内存泄漏
#5
3
Add the hidden titleLabel to the parameter is the best solution.
将隐藏的titleLabel添加到参数中是最好的解决方案。
I generated a array arrUrl which store the NSURL of the mov files in my phone album by enumerate assets block.
我生成了一个数组arrUrl,它通过enumerate assets块在我的电话相册中存储mov文件的NSURL。
After that, I grab on Frame, lets say, get the frame at 3:00 second in the movie file, and generated the image file from the frame.
之后,我抓取帧,比方说,在电影文件中3点获取帧,然后从帧中生成图像文件。
Next, loop over the arrUrl, and use program generate the button with image in the button, append the button to subview of the self.view.
接下来,对arrUrl进行循环,并使用程序在按钮中生成带有图像的按钮,将按钮附加到self.view的子视图。
Because I have to pass the movie Url to playMovie function, I have to assign the button.titleLabel.text with one movie url. and the the button events function, retrieve the url from the buttontitleLable.txt.
因为我必须把电影的Url传递给playMovie函数,所以我必须分配按钮。titlelabel。带有一个电影url的文本。和按钮事件函数,从buttontitleLable.txt中检索url。
-(void)listVideos
{
for(index=0;index<[self.arrUrl count];index++{
UIButton *imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
imageButton.frame = CGRectMake(20,50+60*index,50,50);
NSURL *dUrl = [self.arrUrl objectAtIndex:index];
[imageButton setImage:[[UIImage allow] initWithCGImage:*[self getFrameFromeVideo:dUrl]] forState:UIControlStateNormal];
[imageButton addTarget:self action:@selector(playMovie:) forControlEvents:UIControlEventTouchUpInside];
imageButton.titleLabel.text = [NSString strinfWithFormat:@"%@",dUrl];
imageButton.titleLabel.hidden = YES;
[self.view addSubView:imageButton];
}
}
-(void)playMovie:(id) sender{
UIButton *btn = (UIButton *)sender;
NSURL *movUrl = [NSURL URLWithString:btn.titleLabel.text];
moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:movUrl];
[self presentMoviePlayerViewControllerAnimated:moviePlayer];
}
-(CGIImageRef *)getFrameFromVideo:(NSURL *)mUrl{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:mUrl option:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
NSError *error =nil;
CMTime = CMTimeMake(3,1);
CGImageRef imageRef = [generator copyCGImageAtTime:time actualTime:nil error:&error];
if(error !=nil) {
NSLog(@"%@",sekf,error);
}
return @imageRef;
}
#6
1
I think the correct method should be : - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
我认为正确的方法应该是:(void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
UIControl参考
Where do you get your method from?
你的方法是从哪里来的?
I see that your selector has an argument, that argument will be filled by the runtime system. It will send you back the button through that argument.
我看到你的选择器有一个参数,这个参数将由运行时系统填充。它会通过那个参数返回按钮。
Your method should look like:
您的方法应该如下:
- (void)buttonPressed:(id)BUTTON_HERE { }
-(void)buttonPressed:(id)BUTTON_HERE { }
#7
1
You can set tag of the button and access it from sender in action
您可以设置按钮的标签并从发送者的操作中访问它。
[btnHome addTarget:self action:@selector(btnMenuClicked:) forControlEvents:UIControlEventTouchUpInside];
btnHome.userInteractionEnabled = YES;
btnHome.tag = 123;
In the called function
在被调用的函数
-(void)btnMenuClicked:(id)sender
{
[sender tag];
if ([sender tag] == 123) {
// Do Anything
}
}
#8
1
tl;dr: Use Blocks
For Obj-C, for example, there's a CocoaPod SHControlBlocks, whose usage would be:
例如,对于object - c,有一个CocoaPod SHControlBlocks,它的用途是:
[self.btnFirst SH_addControlEvents:UIControlEventTouchDown withBlock:^(UIControl *sender) {
[weakSelf performSegueWithIdentifier:@"second" sender:nil];
NSLog(@"first");
}];
For Swift, I love the pod Actions, which allows blocks for UIControl
s [1]:
对于Swift,我喜欢pod动作,它允许UIControls[1]块:
// UIControl
let button = UIButton()
button.add(event: .touchUpInside) {
print("Button tapped")
playMusic(from: speakers_mp4, withSongAtPosition: indexPath.row)
}
Not that anyone is reading a 3-year old thread. ::crickets::
并不是说所有人都在阅读一个三岁的帖子。::蟋蟀::
[1] And UIView
, UITextField
, UIGestureRecognizer
, UIBarButtonItem
, Timer
(formally NSTimer), and NotificationCenter
(formally NSNotificationCenter).
[1]和UIView, UITextField, UIGestureRecognizer, UIBarButtonItem, Timer(正式的NSTimer), NotificationCenter(正式的NSNotificationCenter)。
#9
0
UIButton responds to addTarget:action:forControlEvents: since it inherits from UIControl. But it does not respond to addTarget:action:withObject:forControlEvents:
UIButton响应addTarget:action:forControlEvents:因为它继承自UIControl。但它对addTarget:action:withObject:forControlEvents:
see reference for the method and for UIButton
方法和UIButton请参阅参考
You could extend UIButton with a category to implement that method, thought.
你可以用类别扩展UIButton来实现那个方法,thought。
#10
0
I have another solution in some cases.
在某些情况下,我有另一个解。
store your parameter in a hidden UILabel. then add this UILabel as subview of UIButton.
将参数存储在隐藏的UILabel中。然后添加这个UILabel作为UIButton的子视图。
when button is clicked, we can have a check on UIButton's all subviews. normally only 2 UILabel in it.
单击按钮时,我们可以检查UIButton的所有子视图。通常只有两个UILabel在里面。
one is UIButton's title, the other is the one you just added. read that UILabel's text property, you will get the parameter.
一个是UIButton的标题,另一个是你刚刚添加的。读取UILabel的文本属性,您将获得参数。
This only apply for text parameter.
这只适用于文本参数。
#11
0
To add to Tristan's answer, the button can also receive (id)event
in addition to (id)sender
:
为了增加Tristan的答案,除了(id)发送方之外,该按钮还可以接收(id)事件:
- (IBAction) buttonTouchUpInside:(id)sender forEvent:(id)event { .... }
This can be useful if, for example, the button is in a cell in a UITableView
and you want to find the indexPath
of the button that was touched (although I suppose this can also be found via the sender
element).
例如,如果按钮位于UITableView中的单元格中,并且您希望找到被触摸的按钮的indexPath(尽管我认为这也可以通过sender元素找到),那么这将非常有用。
#1
59
Edit. Found a neater way!
编辑。发现了一个整洁!
One argument that the button can receive is (id)sender
. This means you can create a new button, inheriting from UIButton, that allows you to store the other intended arguments. Hopefully these two snippets illustrate what to do.
按钮可以接收的一个参数是(id)sender。这意味着您可以创建一个新的按钮,继承自UIButton,它允许您存储其他预期的参数。希望这两个片段能说明该怎么做。
myOwnbutton.argOne = someValue
[myOwnbutton addTarget:self action:@selector(buttonTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
and
和
- (IBAction) buttonTouchUpInside:(id)sender {
MyOwnButton *buttonClicked = (MyOwnButton *)sender;
//do as you please with buttonClicked.argOne
}
This was my original suggestion.
这是我最初的建议。
There is a way to achieve the same result, but it's not pretty. Suppose you want to add a parameter to your navigate
method. The code below will not allow you to pass that parameter to navigate
.
有一种方法可以达到同样的结果,但它并不好看。假设您想向导航方法添加一个参数。下面的代码不允许您传递该参数进行导航。
[button addTarget:self action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];
To get around this you can move the navigate method
to a class of it's own and set the "parameters" as attributes of that class...
要解决这个问题,您可以将导航方法移动到它自己的类中,并将“parameters”设置为该类的属性……
NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];
Of course you can keep the navigate method in the original class and have it called by navAid, as long as it knows where to find it.
当然,您可以在原始类中保留导航方法,并让navAid调用它,只要它知道在哪里找到它。
NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.whereToCallNavigate = self
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];
Like I said, it's not pretty, but it worked for me and I haven't found anyone suggesting any other working solution.
就像我说的,它不漂亮,但它对我起作用了,我还没有发现任何人提出任何其他可行的解决方案。
#2
31
I found solution. The call:
我发现解决方案。电话:
-(void) someMethod{
UIButton * but;
but.tag = 1;//some id button that you choice
[but addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
And here the method called:
这里的方法叫做:
-(void) buttonPressed : (id) sender{
UIButton *clicked = (UIButton *) sender;
NSLog(@"%d",clicked.tag);//Here you know which button has pressed
}
#3
11
You can sub-class a UIButton named MyButton, and pass the parameter by MyButton's properties.
您可以子类化一个名为MyButton的UIButton,并通过MyButton的属性传递参数。
Then, get the parameter back from (id)sender.
然后,从(id)发送方获取参数。
#4
11
I made a solution based in part by the information above. I just set the titleLabel.text to the string I want to pass, and set the titleLabel.hidden = YES
我根据上面的信息做了一个部分的解决方案。我刚刚设置了标题。文本到我想要传递的字符串,并设置titleLabel。隐藏= YES
Like this :
是这样的:
UIButton *imageclick = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
imageclick.frame = photoframe;
imageclick.titleLabel.text = [NSString stringWithFormat:@"%@.%@", ti.mediaImage, ti.mediaExtension];
imageclick.titleLabel.hidden = YES;
This way, there is no need for a inheritance or category and there is no memory leak
这样,就不需要继承或类别,也不需要内存泄漏
#5
3
Add the hidden titleLabel to the parameter is the best solution.
将隐藏的titleLabel添加到参数中是最好的解决方案。
I generated a array arrUrl which store the NSURL of the mov files in my phone album by enumerate assets block.
我生成了一个数组arrUrl,它通过enumerate assets块在我的电话相册中存储mov文件的NSURL。
After that, I grab on Frame, lets say, get the frame at 3:00 second in the movie file, and generated the image file from the frame.
之后,我抓取帧,比方说,在电影文件中3点获取帧,然后从帧中生成图像文件。
Next, loop over the arrUrl, and use program generate the button with image in the button, append the button to subview of the self.view.
接下来,对arrUrl进行循环,并使用程序在按钮中生成带有图像的按钮,将按钮附加到self.view的子视图。
Because I have to pass the movie Url to playMovie function, I have to assign the button.titleLabel.text with one movie url. and the the button events function, retrieve the url from the buttontitleLable.txt.
因为我必须把电影的Url传递给playMovie函数,所以我必须分配按钮。titlelabel。带有一个电影url的文本。和按钮事件函数,从buttontitleLable.txt中检索url。
-(void)listVideos
{
for(index=0;index<[self.arrUrl count];index++{
UIButton *imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
imageButton.frame = CGRectMake(20,50+60*index,50,50);
NSURL *dUrl = [self.arrUrl objectAtIndex:index];
[imageButton setImage:[[UIImage allow] initWithCGImage:*[self getFrameFromeVideo:dUrl]] forState:UIControlStateNormal];
[imageButton addTarget:self action:@selector(playMovie:) forControlEvents:UIControlEventTouchUpInside];
imageButton.titleLabel.text = [NSString strinfWithFormat:@"%@",dUrl];
imageButton.titleLabel.hidden = YES;
[self.view addSubView:imageButton];
}
}
-(void)playMovie:(id) sender{
UIButton *btn = (UIButton *)sender;
NSURL *movUrl = [NSURL URLWithString:btn.titleLabel.text];
moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:movUrl];
[self presentMoviePlayerViewControllerAnimated:moviePlayer];
}
-(CGIImageRef *)getFrameFromVideo:(NSURL *)mUrl{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:mUrl option:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
NSError *error =nil;
CMTime = CMTimeMake(3,1);
CGImageRef imageRef = [generator copyCGImageAtTime:time actualTime:nil error:&error];
if(error !=nil) {
NSLog(@"%@",sekf,error);
}
return @imageRef;
}
#6
1
I think the correct method should be : - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
我认为正确的方法应该是:(void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
UIControl参考
Where do you get your method from?
你的方法是从哪里来的?
I see that your selector has an argument, that argument will be filled by the runtime system. It will send you back the button through that argument.
我看到你的选择器有一个参数,这个参数将由运行时系统填充。它会通过那个参数返回按钮。
Your method should look like:
您的方法应该如下:
- (void)buttonPressed:(id)BUTTON_HERE { }
-(void)buttonPressed:(id)BUTTON_HERE { }
#7
1
You can set tag of the button and access it from sender in action
您可以设置按钮的标签并从发送者的操作中访问它。
[btnHome addTarget:self action:@selector(btnMenuClicked:) forControlEvents:UIControlEventTouchUpInside];
btnHome.userInteractionEnabled = YES;
btnHome.tag = 123;
In the called function
在被调用的函数
-(void)btnMenuClicked:(id)sender
{
[sender tag];
if ([sender tag] == 123) {
// Do Anything
}
}
#8
1
tl;dr: Use Blocks
For Obj-C, for example, there's a CocoaPod SHControlBlocks, whose usage would be:
例如,对于object - c,有一个CocoaPod SHControlBlocks,它的用途是:
[self.btnFirst SH_addControlEvents:UIControlEventTouchDown withBlock:^(UIControl *sender) {
[weakSelf performSegueWithIdentifier:@"second" sender:nil];
NSLog(@"first");
}];
For Swift, I love the pod Actions, which allows blocks for UIControl
s [1]:
对于Swift,我喜欢pod动作,它允许UIControls[1]块:
// UIControl
let button = UIButton()
button.add(event: .touchUpInside) {
print("Button tapped")
playMusic(from: speakers_mp4, withSongAtPosition: indexPath.row)
}
Not that anyone is reading a 3-year old thread. ::crickets::
并不是说所有人都在阅读一个三岁的帖子。::蟋蟀::
[1] And UIView
, UITextField
, UIGestureRecognizer
, UIBarButtonItem
, Timer
(formally NSTimer), and NotificationCenter
(formally NSNotificationCenter).
[1]和UIView, UITextField, UIGestureRecognizer, UIBarButtonItem, Timer(正式的NSTimer), NotificationCenter(正式的NSNotificationCenter)。
#9
0
UIButton responds to addTarget:action:forControlEvents: since it inherits from UIControl. But it does not respond to addTarget:action:withObject:forControlEvents:
UIButton响应addTarget:action:forControlEvents:因为它继承自UIControl。但它对addTarget:action:withObject:forControlEvents:
see reference for the method and for UIButton
方法和UIButton请参阅参考
You could extend UIButton with a category to implement that method, thought.
你可以用类别扩展UIButton来实现那个方法,thought。
#10
0
I have another solution in some cases.
在某些情况下,我有另一个解。
store your parameter in a hidden UILabel. then add this UILabel as subview of UIButton.
将参数存储在隐藏的UILabel中。然后添加这个UILabel作为UIButton的子视图。
when button is clicked, we can have a check on UIButton's all subviews. normally only 2 UILabel in it.
单击按钮时,我们可以检查UIButton的所有子视图。通常只有两个UILabel在里面。
one is UIButton's title, the other is the one you just added. read that UILabel's text property, you will get the parameter.
一个是UIButton的标题,另一个是你刚刚添加的。读取UILabel的文本属性,您将获得参数。
This only apply for text parameter.
这只适用于文本参数。
#11
0
To add to Tristan's answer, the button can also receive (id)event
in addition to (id)sender
:
为了增加Tristan的答案,除了(id)发送方之外,该按钮还可以接收(id)事件:
- (IBAction) buttonTouchUpInside:(id)sender forEvent:(id)event { .... }
This can be useful if, for example, the button is in a cell in a UITableView
and you want to find the indexPath
of the button that was touched (although I suppose this can also be found via the sender
element).
例如,如果按钮位于UITableView中的单元格中,并且您希望找到被触摸的按钮的indexPath(尽管我认为这也可以通过sender元素找到),那么这将非常有用。