I am doing some custom view controller transitions and I want my transition to start from the center of the button that was pressed.
For UIButton I can do:
myCustomTransition.startingPoint = buttonPressed.center
But if I want to use an UIBarButtonItem, how to actually tell my transition to start from the center of the button, because I don't see any center property on the UIBarButtonItem.
Any suggestions ?
If you just use UIBarButtonItem as navigationItem.leftBarButtonItem or navigationItem.rightBarButtonItem, you can't directly get there geometry property, because UIBarButtonItem doesn't inherit UIView, but you eventually can get geometry property by using tricky method.
This is the hierachy of a simple ViewController that has left and right UIBarButtonItem:
UINavigationButton is your target, get its rect and you can get the center what you need.
- (void)handleItemPressed {
UIView *targetView = nil;
for (UIView *subView in self.navigationController.navigationBar.subviews) {
if ([subView isKindOfClass:NSClassFromString(#"UINavigationButton")]) {
for (UILabel *label in subView.subviews) {
if ([label isKindOfClass:[UILabel class]]) {
if ([label.text isEqualToString:"right"]) {
targetView = subView;
break;
}
}
}
}
}
CGRect rect = [targetView convertRect:targetView.frame toView:self.view];
CGPoint center_you_need = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
}
If you use customeView,just convert customeView's frame to the point.
Related
I have UIBUtton in UICollectionViewCell as show in image. I had set touchUpInside Action in xib. I had set background image of button is pink and lable as yellow. UIButton comes at top of the label. Now the problem is that UIButton in not getting touch event in pink area it only get touch events on orange area. why it is so.
- (IBAction)checkButtonTap:(id)sender event:(id)event
{
DLog(#"%s",__func__);
}
O a hidden view is overlapping the button due to which it is touch event was not reaching to the button.
Just to be sure I understand your issue, you have your UICollectionView in yellow and your UIbutton in pink, correct ?
If so, it seems you want to intercept the touchUpInside event outside your button's superview in yellow. You can look at this answer which deal with kind of problem.
Even if you finally find the solution to your problem, to clarify my answer, if you want to interact with an UIButton which is not inside its superview's frame, you may need to need to implement the method - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event of the superview (here the UICollectionViewCell):
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {
for (UIView *subview in self.subviews.reverseObjectEnumerator) {
CGPoint subPoint = [subview convertPoint:point fromView:self];
UIView *result = [subview hitTest:subPoint withEvent:event];
if (result != nil) {
return result;
}
}
}
return nil;
}
(thanks Noam!)
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTapped:)];
[buttonname addGestureRecognizer:tapGesture];
buttonname.userInteractionEnabled = YES;
(IBAction)imageTapped:(UITapGestureRecognizer *)gestureRecognizer {
if(gestureRecognizer.state == UIGestureRecognizerStateRecognized) {
[buttonname becomeFirstResponder];
}
}
O sorry, there was hidden view that is overlapping the button due to which touch event was not reaching to the button.
I am using the following to try to access all the UIButtons located inside of a UIScrollView within a UIView. The problem is that the code doesn't seem to locate the buttons and set the border property.
UIView -> UIScrollView -> UIButtons.
I basically want to loop through the buttons and set the border property.
for(UIView *v in [self.viewLightLeakChoices subviews]) {
if([v isKindOfClass:[UIButton class]]) {
v.layer.borderWidth = 0;
}
}
Try this one instead
for (id obj in scrollView.subviews) {
NSString *classStr = NSStringFromClass([obj class]);
if ([classStr isEqualToString:#"UIButton"]) {
UIButton *button = (UIButton*)obj;
button.layer.borderWidth = 2.0;
button.layer.borderColor = [UIColor greenColor].CGColor;
}
}
output
Thanks for the help guys. I ended up doing a bunch of for loops to get down to the UIButtons.
for(UIView *v in [self.viewLightLeakChoices subviews]) {
if([v isKindOfClass:[UIScrollView class]]) {
for(UIView *subView in [v subviews]) {
for(UIButton *btn in [subView subviews]) {
btn.layer.borderWidth = 0;
}
}
}
}
first make sure you are getting subviews of UIScrollView because your structure is
UIView > UIScrollView> UIButton
if you have only 1 scroll view in self.viewLightLeakChoices then set your scrollview tag = 1000 and direct access your scrollview so now you dont need to use loop. and execution will be fast.
UIScrollView *scrlV = [self.viewLightLeakChoices viewWithTag:1000];
for (UIButton *btn in scrlV.subviews)
{
if ([btn isKindOfClass:[UIButton Class]]) {
btn.layer.borderWidth = 1.0;
btn.layer.borderColor = [UIColor whiteColor].CGColor;
}
}
i am unable to get i am expecting you are having scrollview -> uiview ->button
for(UIView *myview in Scrollview.subviews)
{
for ( id mybutton in myview.subviews)
{
if ([mybutton isKindOfClass:[UIButton class]])
{
UIButton *mybtn=(UIButton *)mybutton;
mybtn.layer.borderWidth=0;
}
}
}
You should have create Button class say MyButton extents UIButton, if you do this there is no need to loop through scrollview's subviews.
implement awakeFromNib method and apply border, to apply border refer this SO Post How to create border in UIButton?
I'm dynamically creating buttons on UIView.
I can move them by dragging using this code
- (IBAction)draggedOut: (id)sender withEvent: (UIEvent *) event: (NSSet *)touches {
UIButton *selected = (UIButton *)sender;
selected.center = [[[event allTouches] anyObject] locationInView:hallView];
}
I can have more then one button. When I'm dragging some button, I need to check are there any intersections with other buttons?
How can I do this?
You should cycle through the other buttons in the view and, for each of them, check whether in intersect the dragged one via:
CGRectIntersectsRect (draggedButton.frame, anotherButton.frame);
You could use a function like:
- (BOOL)isThereButtonsIntersectionInView:(UIView *)containerView
forButton:(UIButton *)draggedButton
{
for(UIView *view in containerView.subviews){
if([view isKindOfClass:[UIButton class]] &&
view != draggedButton &&
CGRectIntersectsRect (view.frame, draggedButton.frame)){
return YES;
}
}
}
return NO;
}
Call this method passing as a parameter the view containing the buttons and the dragged button.
You can get frames of buttons and check using this
if(CGRectIntersectsRect(firstButton.frame, secondButton.frame)) {
return YES;
}
You simply need to compare the frame of this button with the frame of all the other buttons.
Here is a bit of sample code, which should probably go in your view controller because it requires knowledge of the other buttons.
- (BOOL) button:(UIButton*)button intersectsWithButtons:(NSArray*)moreButtons
{
CGRect buttonFrame = button.frame;
for (UIButton *checkButton in moreButtons) {
if (button != checkButton && CGRectIntersectsRect(buttonFrame, checkButton.frame))
return YES;
}
return NO;
}
I have a UIScrollview in a tab, i added some UIView (NIB) to the UIScrollview. Each UIView has some UISwictch, labels, buttons, etc. How can i get the the label.text inside of the view added to the UIScrollview.
I tried a lot of things but i can access to the content of the UIView added to the UIScrollview.
Check with this,
for (UIView *addedView in [self.scrollView subviews])
{
for (UIView *sub in [addedView subviews])
{
if([sub isKindOfClass:[UILabel class]])
{
UILabel *myLabel = (UILabel *)sub;
NSLog(#"My label :%#",myLabel .text);
}
}
}
Here scrollView is your scroll view. It will print all label's text.
If you need to print any particular label's text. Then add a tag to it and check the tag before printing it, like if(myLabel.tag == 7)
set a unique tag for your label.
eg: label.tag = 10345 (some random number, which is a unique tag)
and you can search for the label in the parentView like this
UILabel *theLabel = (UILabel *)[parentView viewWithTag: 10345];
and then you can do what ever you want with the Label.
Step 1: Add this code in your scrollview
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTap:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
singleTapGestureRecognizer.enabled = YES;
singleTapGestureRecognizer.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:singleTapGestureRecognizer];
Step 2: Implement this method
-(void)singleTap:(UITapGestureRecognizer *)gesture
{
// Convert gesture into view for getting subviews
CGPoint point = [gesture locationInView:mainScrollView];
UIView *tappedView = [mainScrollView hitTest:point withEvent:nil];
// Get the subviews of the view
NSArray *subviews = [view tappedView];
// Return if there are no subviews
if ([subviews count] == 0) return;
for (UIView *subview in subviews) {
NSLog(#"%#", subview);
// List the subviews of subview
[self your_method:subview];
}
}
What's the easiest way to determine the x,y location of a UIBarButtonItem in a UIToolbar?
The only answer I found is in any way to know where uibarbuttonitem has been drawn.
All proposed answers seem too complicated. There ought to be a simpler way to get the position of the damn UIBarButtonItem isn't there?
I used this which seems to be the most elegant way
- (CGRect)frameForBarButtonItem:(UIBarButtonItem *)buttonItem
{
UIView *view = [buttonItem valueForKey:#"view"];
return view ? view.frame : CGRectZero;
}
Unfortunately, there is no easy way of determining the position of a UIBarButtonItem. A UIBarButtonItem is essentially a NSObject that does just two things: describe the look and feel of a toolbar button, and forward events to the designated target/action selector.
Now, given that all buttons are subviews of UIToolbar, and all button events are routed through their respective UIBarButtonItems, it's quite trivial to loop through all subviews of your UIToolbar and when you find a button whose target is that of your UIBarButtonItem, just get the frame of that button. Some code:
UIToolbar *toolbar = <your toolbar>;
UIBarButtonItem *barButtonItem = <your item>;
UIButton *button = nil;
for (UIView *subview in toolbar.subviews) {
if ([subview isKindOfClass:[UIButton class]]) {
for (id target in [(UIButton *)subview allTargets]) {
if (target == barButtonItem) {
button = (UIButton *)subview;
break;
}
}
if (button != nil) break;
}
}
CGRect frame = button.frame;
This works for me when using popovers from UIBarButtonItems.
- (void)buttonClicked:(id)sender{
{
CGRect buttonRect = [[sender view] frame];
}
For iOS 11 (and maybe above) the call:
if let view = barButtonItemView.value(forKey: "view") as? UIView {
let viewFrame = view.frame
}
will return a zero point origin for the view. To counter this, ask for the window coordinates of the view, by using:
let actualPointOnWindow = view.convert(view.frame.origin, to: nil)
If your toolbar has any translations subtract them from the calculated point to find its position on the toolbar.
Complete Code:
if let view = barButtonItemView.value(forKey: "view") as? UIView {
let viewFrame = view.frame
let actualPointOnWindow = view.convert(view.frame.origin, to: nil)
}
A more 'swifty' SWIFT way:
func userAction(sender: AnyObject) {
if let originView = sender.valueForKey("view") {
let frame = originView.frame //it's a UIBarButtonItem
} else {
let frame = sender.frame //it's a regular UIButton
}
}
UIBarButtonItem is NOT a subclass of UIView even though it's essentially a button. Go figure.
I used johosher's approach to get the position of a UIBarButtonItem using Swift.
Since I needed the position as sourceRect for a popoverPresentationController I had to convert it to self.view. I am not sure, whether this is a good solution but it works very well and the popover shows off right of the UIBarButtonItem.
let senderRect = sender.view!!.convertRect(sender.view!!.bounds, toView: self.view)
// additional code for the popover controller
alertController.modalPresentationStyle = UIModalPresentationStyle.Popover
alertController.popoverPresentationController?.sourceRect = senderRect
alertController.popoverPresentationController?.sourceView = self.view
UIToolbar *toolbar;
for (UIView *v in [toolbar items])
{
if ([v isKindOfClass:[UIBarButtonItem class]])
{
UIBarButtonItem *b = (UIBarButtonItem*)v;
//do something with b..
}
}