Changing UIButton frame disconnects it from IBAction selector - ios

I have a xib file which contains a UIButton. I control + dragged the button to create an action. The position of the button has to be set dynamically. The method below is called from drawRect: method which updates the button position.
-(void)updateButtonPosition {
CGFloat xPos = self.label.frame.origin.x + self.label.frame.size.width;
CGFloat yPos = self.label.frame.origin.y + self.label.frame.size.height - 25;
CGRect frame = CGRectMake(xPos, yPos, self.button.frame.size.width, self.button.frame.size.height);
self.button.frame = frame;
}
But I noticed that calling this function disconnects the UIButton from the action I created by control + dragging (i.e. nothing happens when I click the button when the app is running). I commented the part where this function was called. And now the button started working and the action method was called. So changing the frame disconnected the UIButton from its action method.
EDIT: User Interaction is enabled for all its superview. I'm not using auto layout. The project is like that.
How can I change the frame of the button so that the action is also called when I click the button?

Check the button's frame with it's superview frame. The button receives touch events only when it resides inside it's superview frame.

Can't reproduce your problem, I dragged an action named "btnAction" and a outlet named "btnTest".
This is ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (IBAction)btnAction:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *btnTest;
#end
And this is ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
// [super viewDidLoad];
// // Do any additional setup after loading the view, typically from a nib.
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(grHandler)]];
}
-(void)grHandler{
NSLog(#"grHandler actived.");
[self updateButtonPosition];
}
- (IBAction)btnAction:(id)sender {
NSLog(#"btn actived.");
}
-(void)updateButtonPosition {
CGFloat xPos = 20;
CGFloat yPos = 30;
CGRect frame = CGRectMake(xPos, yPos, self.btnTest.frame.size.width, self.btnTest.frame.size.height);
self.btnTest.frame = frame;
}
#end
Try to use my code and tell me where is the problem?
Then I can help you.

My button's frame was outside the frame of its parent view. Hence it was not tap able.
For more info refer UIButton not responding after set frame within UIScrollview

Related

Move an uiview when a button is moving

I'm writing a custom UIButton that can draggable around the screen. When I press this button, a uiview will bee added into superview. I've adding pan gesture for this view so it's can draggable too.
And now I wanna make both uiview and button can draggable at the same time. How can I do that?For example:
If I drag the uiview or the button to a point, the other will move too. You can see the picture below for more information.
I would encapsulate the button and the view in a parent transparent UIView. Add the pan gesture to it and move it around... both will then move.
I tried the sample code for your application.It works perfectly.When you drag button,the view also moves simultaneously.
First I created button and UIView.I hooked up that.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIButton *btnDragg;
- (IBAction)actionDragg:(id)sender;
#property (strong, nonatomic) IBOutlet UIView *viewDrag;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize btnDragg,viewDrag;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIPanGestureRecognizer *panRecognizer;
panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(wasDragged:)];
panRecognizer.cancelsTouchesInView = YES;
[btnDragg addGestureRecognizer:panRecognizer];
}
- (void)wasDragged:(UIPanGestureRecognizer *)recognizer
{
UIButton *button = (UIButton *)recognizer.view;
CGPoint translation = [recognizer translationInView:button];
CGPoint translationView = [recognizer translationInView:viewDrag];
button.center = CGPointMake(button.center.x + translation.x, button.center.y + translation.y);
viewDrag.center = CGPointMake(viewDrag.center.x + translationView.x, viewDrag.center.y + translationView.y);
[recognizer setTranslation:CGPointZero inView:button];
[recognizer setTranslation:CGPointZero inView:viewDrag];
}
Before I drag the button,it is in original position
Then When I drag the button,the view also moves with button.Now it changes the position after the I drag the button.

UIScrollView won't scroll, delegate methods never called

I have several UILabel inside the child view of a UIScrollView. I believe I've set it up exactly like the functioning UIScrollView I have in another view controller, only this one won't scroll. The contentSize is set to larger than the scrollview frame size and scrollview delegate is set to self. The views are wired up in Interface Builder and the UIScrollview has scrolling enabled, bounces, user interaction and multiple touch enabled. The child UIView also has user interaction enabled. Here is my code:
.h file
#import <UIKit/UIKit.h>
#interface CreditsViewController : UIViewController <UIScrollViewDelegate>
#end
.m file
#import "CreditsViewController.h"
#interface CreditsViewController ()
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
#property (nonatomic, strong) IBOutlet UIView *contentView;
#end
#implementation CreditsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.scrollView.delegate = self;
_scrollView.contentSize = _contentView.frame.size;
NSLog(#"scrollview frame size, contentview frame size: %f x %f, %f x %f", _scrollView.frame.size.width, _scrollView.frame.size.height, _contentView.frame.size.width, _contentView.frame.size.height);
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
NSLog(#"in scrollViewWillBeginDragging");
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(#"in scrollViewDidScroll");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I get scrollview frame size, contentview frame size: 240.000000 x 128.000000, 320.000000 x 568.000000 as the log printout but I never get the statements from the delegate methods. The scrollview is the only child of the view controller so it should be receiving the touch events when I try to scroll. What's going on?
You'll need to implement viewForZoomingInScrollView: and return your _contentView.

Swipe left gestures over UITextField

I have UITextFields in tableviewcells. When you swipe over the cell not part of the textfield, the delete action comes up as expected. If you swipe over the textfield, it stops the delete from popping up.
How do I fix this so that you can swipe over the inputs and the cell will trigger the delete action?
I think the issue here is that the touch on the text field is interfering with your swipe gesture recognizer (presumably attached to the parent view). I had a similar problem with a text field that was placed in a UIScrollView.
I got around this problem by overlaying a clear UIView on top of my UITextField. I then assigned a UITapGestureRecognizer to this clear view to set the text field as the first responder when the user taps on the field. Otherwise, the swiped is sent to the parent view (a scroll view) which recognizes the swipe without any issues. It's kind of lame but it works.
This scenario is a bit different from yours, but I think it's the same problem. Here is what my code looks like, hopefully it helps:
// UIView subclass header
#interface LSAddPageView : UIView
#property (weak, nonatomic) IBOutlet UITextField *textField; // Connected to the UITextField in question
#property (strong, nonatomic) UIView *textFieldMask;
#property (assign, nonatomic) BOOL textFieldMaskEnabled;
#end
// UIView subclass implementation
#implementation LSAddPageView
- (void)awakeFromNib
{
[super awakeFromNib];
_textFieldMask = [UIView new];
_textFieldMask.backgroundColor = [UIColor clearColor];
[self insertSubview:_textFieldMask aboveSubview:self.textField];
}
- (void)layoutSubviews
{
[super layoutSubviews];
_textFieldMask.frame = self.textField.frame;
}
- (BOOL)textFieldMaskEnabled
{
return _textFieldMask.hidden == NO;
}
- (void)setTextFieldMaskEnabled:(BOOL)textFieldMaskEnabled
{
_textFieldMask.hidden = !textFieldMaskEnabled;
}
#end
And then in the controller:
- (void)viewDidLoad
{
[super viewDidLoad];
_addPageView = (LSAddPageView*)self.view;
_maskGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapMask:)];
_maskGestureRecognizer.numberOfTapsRequired = 1;
_maskGestureRecognizer.numberOfTouchesRequired = 1;
[_addPageView.textFieldMask addGestureRecognizer:_maskGestureRecognizer];
self.textField.delegate = self; // Set delegate to be notified when text field resigns first responder
}
- (void)didTapMask:(UIGestureRecognizer*)recognizer
{
_addPageView.textFieldMaskEnabled = NO;
[self.textField becomeFirstResponder];
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
_addPageView.textFieldMaskEnabled = YES;
return YES;
}
Sounds like you need to set the cancelsTouchesInView property
yourGestureRecognizer.cancelsTouchesInView = NO;
from UIButton & UITextField will block UITableViewCell being swipe to delete
self.tableView.panGestureRecognizer.delaysTouchesBegan = YES;
this will make the textfield not stop left swipe guestures

UIScrollVIew only showing first static subview, delegate of UIPageControl

I am a newbie of IOS development, my problem is I am using UIScrollView and UIPageControl to show guide info to users. I created a xib file related to GuideViewController via setting up File's Owner. I setup the content size and statically add subviews in xib files. But I encountered some strange thing, scrollview only shows the first subview on screen, all following display is just white background (when I scrolling).
Following is the code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSInteger numberOfPages = 2;
self.pageControl.numberOfPages = numberOfPages;
self.pageControl.currentPage = 0;
self.pageScroll.delegate = self;
self.pageScroll.contentSize = CGSizeMake(self.view.frame.size.width * numberOfPages,
self.view.frame.size.height);
self.pageControl.currentPageIndicatorTintColor = [UIColor redColor];
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat pageWidth = self.view.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth/2) / pageWidth) + 1;
self.pageControl.currentPage = page;
}
I googled a lot to find the answer but still stuck here.
I am also confused by this sentence "When a user taps a page control to move to the next or previous page, the control sends the UIControlEventValueChanged event for handling by the delegate" in xcode help. It seems UIPageControl has no delegate attribute,so how I can capture the UIControlEventValueChanged event.
Actually I am developing my main UI on storyboard, but I kind of want separate UI design to make more space for storyboard, so i use xib file for some other part UI, I do not know whether this will cause some problems. Thanks
My solution was this:
Add a IBAction in your header:
- (IBAction)changePage;
Dont forget to set the Outlet and the property for the pageControl:
IBOutlet UIPageControl *pageControl;
#property (nonatomic, retain) IBOutlet UIPageControl* pageControl;
Add a BOOLEAN that the pagecontrol updates:
BOOL pageControlBeingUsed;
Here is my full header:
#interface ViewC : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageControl;
BOOL pageControlBeingUsed;
}
#property (nonatomic, retain) IBOutlet UIScrollView* scrollView;
#property (nonatomic, retain) IBOutlet UIPageControl* pageControl;
- (IBAction)changePage;
#end
(Don't forget to synthesize the propertys)
The second step you did already with the viewdidLoad method but you didn't connected the Boolean to the method! Try this:
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (!pageControlBeingUsed) {
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
}
}
Add at the end this code for the IBAction and that when the pageControl was pressed at a button the site changes.
- (IBAction)changePage {
// update the scroll view to the appropriate page
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
[self.scrollView scrollRectToVisible:frame animated:YES];
pageControlBeingUsed = YES;
}
IMPORTANT:
Connect the IBAction with "value changed" option in the xib. and set the delegate of the Controller to itself:
And then it should be like this:
That is all! Hope you fixed your issue. I would be glad if you give my awnser the "tick" if it helped you!
Greetings,
Noah

iOS5 adding and manipulting a UIView class

I have create a UIVeiw class and a .xib. Within this .xib view I have its set to freeform with the dimensions of 400x200 and I have assigned it to my custom class with the same name:
Storyboard: blogView
Class Files: blogView.h & blogView.m
Within in the .xib i have added a label and a text field and linked them up to variable within the .h files etc (See code below).
blogCont.h
#import <UIKit/UIKit.h>
#interface blogCont : UIView
#property (strong, nonatomic) IBOutlet UILabel *lbBlogDate;
#property (strong, nonatomic) IBOutlet UITextView *txtBlogTitle;
#end
blogCont.m
#import "newsStoryView.h"
#implementation blogCont
#synthesize lbBlogDate;
#synthesize txtBlogTitle;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code place a log to see if it loads
NSLog(#"View Loaded");
}
return self;
}
#end
Now with in my main viewController.m file i have added the following code to init this view class, and I have added a background colour to see if this loads in.
viewController.m
UIView *blogCont = [[blogView alloc] init];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Now when I run this it all works well but as I do not see the purple background it looks as if the view does not load, but within the log I do see the NSLog message I have within this view NSLog(#"View Loaded"); so it seems it initiating this, but I cannot for the life of me get this to display?
Now if I change the code slightly to my main View Controller.m fiel to:
CGRect blogFrame;
blogFrame.origin.x = 20;
blogFrame.origin.y = 20;
blogFrame.size = CGRectMake(400,200);;
newsStoryView *blogCont = [[blogView alloc] blogFrame];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Then I get my view display a nice purple box, so this shows up when I set a frame size and the init the view with it 'blogFrame', bu tI thought that all this would be set within the .xib settings so no need to do this?
SO how can I create this external view class and assign it into another view and then manipulate its data, as accessing the label in the .xib using blogCont.lbBlogDate.text does not seem to work that is it probably does but as I cannot view it i cannot confirm it.
What am i doing wrong?
Thanks
Seems I nearly answered my own question then did:
I was not setting the size within my separate class view I was asking for a size when init it:
- (id)initWithFrame:(CGRect)frame
this is asking for a size
so I could do the following to the above:
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 478, 220)];
.... rest of code
Setting the size within the view load.
But I could also set it when I init it in my main view controller as below:
newsStoryView *blogCont = [[blogView alloc] initWithFrame:CGRectMake(0, 0, 400, 200)];
This is better as I can control the position of each one. Hope this helps anyone

Resources