Can't able to click a UICollectionViewCell in a UICollectionView - ios

Let's say I have a view controller OptionsToCreateViewController which inherits UICollectionViewController and I have used that View Controller in another view controller like this.. I can able to see the view but can't able to click the cell
self.optionsToCreateViewController = [[OptionsToCreateViewController alloc] init];
self.optionsToCreateViewController.view.translatesAutoresizingMaskIntoConstraints = FALSE;
[self.optionsToCreateViewController didMoveToParentViewController:self];
[self addChildViewController:self.optionsToCreateViewController];
[self.view addSubview:self.optionsToCreateViewController.view];
OrganizerBottomBar *orgBB = [OrganizerBottomBar new];
CGRect applicationFrame = [[UIScreen mainScreen] bounds];
CGFloat viewWidth = applicationFrame.size.width / 2;
if(![MyUIResources isPhone]){
viewWidth = applicationFrame.size.width / 4;
}
[self.view addConstraints:#[
[NSLayoutConstraint constraintWithItem:self.optionsToCreateViewController.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:-(orgBB.frame.size.height + 75)],
[NSLayoutConstraint constraintWithItem:self.optionsToCreateViewController.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:-viewWidth]
]];
is this the right implementation of a view controller in another view controller
In Collection view cell:
[button addTarget:self action:#selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
self.contentView.userInteractionEnabled = FALSE;
self.userInteractionEnabled = TRUE;
I also put a break point to buttonPressed function, it's not hitting. i also used
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [self->button hitTest:[self->button convertPoint:point fromView:self] withEvent:event];
if (view == nil) {
view = [super hitTest:point withEvent:event];
}
return view;
}
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if ([super pointInside:point withEvent:event]) {
return YES;
}
return !self->button.hidden && [self->button pointInside:[self->button convertPoint:point fromView:self] withEvent:event];
}
but no use. Could anyone please help me here, I'm stuck here badly
CGRect applicationFrame = [[UIScreen mainScreen] bounds];
self.view = [UIView new];
self.view.translatesAutoresizingMaskIntoConstraints = NO;
self.view.backgroundColor = [UIColor colorWhite];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collection = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
self.collection.translatesAutoresizingMaskIntoConstraints = NO;
self.collection.backgroundColor = [UIColor colorWhite];
self.collection.contentInset = UIEdgeInsetsMake(0, 7.0, 0, 16.0);
[self.collection registerClass:[OptionsToCreateCollectionViewCell class] forCellWithReuseIdentifier: [OptionsToCreateCollectionViewCell cellIdentifier]];
[self.collection setDataSource:self]; // UICollectionViewDataSource
[self.collection setDelegate:self]; // UICollectionViewDelegate
[self.view addSubview:self.collection];
CGFloat viewWidth = applicationFrame.size.width;
CGFloat frameWidth = viewWidth;
if(![MyUIResources isPhone]){
frameWidth = viewWidth/2;
}
[self.view addConstraints:
#[
[NSLayoutConstraint constraintWithItem:self.collection attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:10],
[NSLayoutConstraint constraintWithItem:self.collection attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:20],
[NSLayoutConstraint constraintWithItem:self.collection attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:frameWidth],
[NSLayoutConstraint constraintWithItem:self.collection attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1.0 constant:114*2.5]
]
];

What is the button's superview? Add the button on the cell.contentView, not cell self.

1.check that button frame(if outside cell not working, then any view overlapping that button not working ) and user interaction enabled or not
Otherwise
2.check that cell frame and height(check if there inside of collection view)
Otherwise
3.collection view supper frame set correctly (collection view frame need inside of superview)
If Frame working correct so assign that clipsToBounds = YES
self.yourview.clipsToBounds = YES;
notes:past that button Action in collection didselecteditem . then check working or not because easily identified issue only that button or that class based.

Related

Change Frame of Subview in Superview

I have a ViewController that adds an UIView, SpeciesImageView as a subview in viewDidLoad and set constraints in viewWillLayoutSubviews.
SpeciesImageView does not have a nib file. When we create speciesImageView in viewDidLoad, it calls initWithFrame in SpeciesImageView class.
This works fine (in both landscape and portrait) until the phone rotates. I tried setting the constraints as speciesImageView.frame.size.width, but that doesn't work because initWithFrame isn't called when the orientation changes, so the height/width of the speciesImageView remains unchanged.
On the other hand, using screenRect doesn't change the actual size of the UIView, it changes its size within the superview. So in other words, I haven't found a way to change the size of the actual speciesImageView on orientation change.
And for reasons lost to me, it gets completely messed up when you rotate it back to the original position.
- (void)viewDidLoad
{
self.tabBarController.tabBar.hidden=YES;
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
self.navigationController.navigationBar.hidden = NO;
//self.navigationController.navigationBar.translucent = YES;
UIImage *plantinfo;
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
plantinfo = [UIImage imageNamed:#"plantinfo_frame.png"];
} else {
plantinfo = [UIImage imageNamed:#"plantinfo.png"];
}
UIBarButtonItem *tempButton = [[UIBarButtonItem alloc] initWithImage:plantinfo
style:UIBarButtonItemStylePlain
target:self
action:#selector(toggleText:)];
self.navigationItem.rightBarButtonItem = tempButton;
[tempButton release];
self.title = theSpecies.scientificName;
//[self.navigationItem.backBarButtonItem setTitle:#""];
self.navigationItem.backBarButtonItem.title = #"";
infoViewSegmentedControl.backgroundColor = [UIColor blackColor];
webView.backgroundColor = [UIColor blackColor];
_activityIndicator.hidden = YES;
[webView setOpaque:YES];
webView.delegate = self;
// Do double justification
[webView loadHTMLString:[self formatHTML:theSpecies] baseURL:nil];
showingInfoView = NO;
//
// Resize containerView, infoview according to iphone 5 screen size.
//
infoView.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
CGPoint screenOrigin = [[UIScreen mainScreen] bounds].origin;
CGSize viewSize = [[UIScreen mainScreen] bounds].size;
CGPoint origin = infoView.frame.origin;
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
infoView.frame = CGRectMake(screenOrigin.x,
screenOrigin.y + statusBarFrame.size.height,
viewSize.width,
viewSize.height - origin.y - statusBarFrame.size.height);
speciesImageView = [[SpeciesImageView alloc]
initWithFrame:CGRectMake(screenOrigin.x,
screenOrigin.y,
viewSize.width,
viewSize.height)];
} else {
infoView.frame = CGRectMake(screenOrigin.x,
screenOrigin.y,
viewSize.width,
viewSize.height - origin.y - statusBarFrame.size.height);
speciesImageView = [[SpeciesImageView alloc]
initWithFrame:CGRectMake(screenOrigin.x,
screenOrigin.y,
viewSize.width,
viewSize.height - statusBarFrame.size.height)];
}
speciesImageView.delegate = self;
[containerView addSubview:speciesImageView];
managedObjectContext = [(LeafletAppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
[self parseImageURLArray];
}
-(void)viewWillLayoutSubviews{
if(speciesImageView.window != nil){
CGRect screenRect = [[UIScreen mainScreen] bounds];
speciesImageView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *widthConst = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:screenRect.size.width];
NSLayoutConstraint *heightConst = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:screenRect.size.height];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
[self.view addConstraints:#[widthConst, heightConst, bottomConstraint, rightConstraint]];
}
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
imageScrollView = [[UIScrollView alloc] initWithFrame:frame];
imageScrollView.delegate = self;
imageScrollView.backgroundColor = [UIColor blackColor];
[self addSubview:imageScrollView];
imageScrollView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *widthConst = [NSLayoutConstraint constraintWithItem:imageScrollView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:imageScrollView.frame.size.width];
NSLayoutConstraint *heightConst = [NSLayoutConstraint constraintWithItem:imageScrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:imageScrollView.frame.size.height];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint
constraintWithItem:imageScrollView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint
constraintWithItem:imageScrollView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
[self addConstraints:#[widthConst, heightConst, bottomConstraint, rightConstraint]];
}
return self;
}
If you want your views to adjust to the size of the superview,
then you need something like this (set the margin to whatever you like):
CGFloat margin = 0;
NSString * visualFormatH = [NSString stringWithFormat:#"|-(%f)-[speciesImageView]-(%f)-|", margin, margin];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatH
options:0
metrics:Nil
views:#{#"speciesImageView": speciesImageView}]];
NSString * visualFormatV = [NSString stringWithFormat:#"V:|-(%f)-[speciesImageView]-(%f)-|", margin, margin];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatV
options:0
metrics:Nil
views:#{#"speciesImageView": speciesImageView}]];
Now speciesImageView will adjust its frame whenever the superview frame changes.
Here is a generic example:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView * sampleView = [UIView new];
sampleView.backgroundColor = [UIColor redColor];
sampleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:sampleView];
CGFloat margin = 0;
NSString * visualFormatH = [NSString stringWithFormat:#"|-(%f)-[sampleView]-(%f)-|", margin, margin];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatH
options:0
metrics:Nil
views:#{#"sampleView": sampleView}]];
NSString * visualFormatV = [NSString stringWithFormat:#"V:|-(%f)-[sampleView]-(%f)-|", margin, margin];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatV
options:0
metrics:Nil
views:#{#"sampleView": sampleView}]];
}
Auto Layout Getting Started
Auto Layout Visual Format Documentation

Add subview to UITextView and using autolayout

I have problem with adding subview to UITextView using autoLayout:
in SubTextView : UITextView .m file:
- (instancetype)initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame]) {
_baseline = [[UIView alloc] init];
[self addSubview:_baseline];
[self setBackgroundColor: [UIColor blackColor]];
_baseline.translatesAutoresizingMaskIntoConstraints = NO;
[self setNeedsUpdateConstraints];
}
}
- (void)updateConstraints
{
[super updateConstraints];
NSLayoutConstraint *constraint = nil;
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeading
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
}
But, this do not work... the self.baseline's frame is always (0, 0, 0, 0)...
Anyone can help?
Edited:
I set a break point at layout subviews, at that time, when layoutSubviews the subviews are inited, and the UITextView is :
<InventoryOverviewListingNameTextView: 0x7fd92b2a1800;
baseClass = UITextView;
frame = (234 36; 399 70.2);
text = '11111111';
clipsToBounds = YES;
gestureRecognizers = <NSArray: 0x7fd92cbd8ca0>;
layer = <CALayer: 0x7fd92cb08900>;
contentOffset: {-0, 10};
contentSize: {399, 70.199997425079346}>
But the frame of the baseline is:
<UIView: 0x7fd92cb90710;
frame = (0 -10; 399 0.5);
layer = <CALayer: 0x7fd92cb907e0>>.
Do not know how to make the y = -10 to y = 69.7.
I feel it is a little like scrollView, to which I solve by add a UIView as contentView on UIScrollView, and UIScrollView itself is added on another UIView. Then I set the contentView's top to scrollView's top, contentView's heigh, and !!!(this is important or autoLayout won't work properly)
contentView's left and right to UIView rather than scrollView.
But I do not see it works for UITextView...
Anyone can help?
The frame will always be (0,0,0,0) because that is the default one that comes whit [[UIView alloc] init].
Have you tried defining the view setting a frame?
- (instancetype)initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame]) {
//Add a frame, does not matter the size
_baseline = [[UIView alloc] initWithFrame:CGRectMake(0,0,20,20)];
//Just to make sure it's there let us give it a color
[_baseline setBackgroundColor:[UIColor green]];
[self addSubview:_baseline];
//Don't run this line just yet.
//[self setNeedsUpdateConstraints];
}
}
If that works, then we found the problem, if it does not, maybe the problem is on the - (void)updateConstraints method.
UPDATE:
So, I sat down and ran your code, I got a few crashes but eventually I managed to make the black box apear inside the text view. I found that the box was not instantiated when the view was looking to layout its subviews, so I tinkered around and here goes, this works, it throws a few constraints warnings but I guess you can work those by yourself.
- (instancetype)initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame]) {
}
return self;
}
-(void)layoutSubviews{
[super layoutSubviews];
if (!_baseline) {
_baseline = [[UIView alloc] init];
[self addSubview:_baseline];
[self setBackgroundColor: [UIColor blackColor]];
[self setNeedsUpdateConstraints];
}
}
- (void)updateConstraints {
[super updateConstraints];
if (_baseline) {
NSLayoutConstraint *constraint = nil;
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeading
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
}
}

UIView breaking in iOS7 but not in iOS8

I have created a custom view to show 2 labels inside a circle. It is suppose to look like this:
but in iOS 7 it looks like this:
That happens because the constraints hat are supposed to stick the labels to the top/bottom are breaking for some reason, but only on iOS 7. I get the following error:
(
"<NSLayoutConstraint:0x7f96e500a540 H:|-(-1)-[UILabel:0x7f96e2dd84d0] (Names: '|':UIView:0x7f96e2df6350 )>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7f96e500a540 H:|-(-1)-[UILabel:0x7f96e2dd84d0] (Names: '|':UIView:0x7f96e2df6350 )>
I have confirmed that those are in fact the constraints called (I only gave one error as an example)
self.dayLabelStickButtomConstraint
self.monthLabelStickTopConstraint
Here is the code for the custom view, can anyone maybe understand why is it breaking on iOS 7 but not on 8?
- (instancetype) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self initiateValues];
[self buildHeirarchy];
}
return self;
}
- (instancetype) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initiateValues];
[self buildHeirarchy];
}
return self;
}
-(void)initiateValues{
self.fillColor = [UIColor blackColor];
self.month = #"jan";
self.monthFontSize = 8.0f;
self.monthTextColor = [UIColor blackColor];
self.monthLabelInsetDistance = 1.0f;
self.day = #"01";
self.dayFontSize = 12.0f;
self.dayTextColor = [UIColor blackColor];
self.dayLabelInsetDistance = 1.0f;
}
-(void)buildHeirarchy{
self.innerContainer = [[UIView alloc] initWithFrame:CGRectInset(self.bounds, 5.0, 5.0)];
[self.innerContainer setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.innerContainer];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.innerContainer
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.innerContainer
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.innerContainer
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:0.7
constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.innerContainer
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeHeight
multiplier:0.7
constant:0.0]];
self.monthLabel = [[UILabel alloc] initWithFrame:CGRectInset(self.bounds, 5.0, 5.0)];
[self.monthLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
self.monthLabel.textAlignment = NSTextAlignmentCenter;
[self.innerContainer addSubview:self.monthLabel];
[self.innerContainer addConstraint:[NSLayoutConstraint constraintWithItem:self.monthLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.innerContainer
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
NSLayoutConstraint *monthTopConstraint = [NSLayoutConstraint constraintWithItem:self.monthLabel
attribute:NSLayoutAttributeTopMargin
relatedBy:NSLayoutRelationEqual
toItem:self.innerContainer
attribute:NSLayoutAttributeTopMargin
multiplier:1.0
constant:self.monthLabelInsetDistance];
self.monthLabelStickTopConstraint = monthTopConstraint;
[self.innerContainer addConstraint:self.monthLabelStickTopConstraint];
self.dayLabel = [[UILabel alloc] initWithFrame:CGRectInset(self.bounds, 5.0, 5.0)];
[self.dayLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.innerContainer addSubview:self.dayLabel];
self.dayLabel.textAlignment = NSTextAlignmentCenter;
[self.innerContainer addConstraint:[NSLayoutConstraint constraintWithItem:self.dayLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.innerContainer
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
NSLayoutConstraint *dayButtomConstraint = [NSLayoutConstraint constraintWithItem:self.dayLabel
attribute:NSLayoutAttributeBottomMargin
relatedBy:NSLayoutRelationEqual
toItem:self.innerContainer
attribute:NSLayoutAttributeBottomMargin
multiplier:1.0
constant:self.dayLabelInsetDistance];
self.dayLabelStickButtomConstraint = dayButtomConstraint;
[self.innerContainer addConstraint:self.dayLabelStickButtomConstraint];
}
-(void)layoutSubviews{
// get the graphics context
if (!self.backgroundColorRoundView) {
self.backgroundColorRoundView = [[UIView alloc]initWithFrame:self.bounds];
[self addSubview:self.backgroundColorRoundView];
[self sendSubviewToBack:self.backgroundColorRoundView];
self.backgroundColorRoundLayer = [CAShapeLayer new];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:self.backgroundColorRoundView.bounds];
self.backgroundColorRoundLayer.path = path.CGPath;
//imageMaskLayer.fillColor = self.fillColor.CGColor;
[self.backgroundColorRoundView.layer addSublayer:self.backgroundColorRoundLayer];
}
self.backgroundColorRoundView.frame = self.bounds;
self.backgroundColorRoundLayer.frame = self.bounds;
[self updateViews];
[super layoutSubviews];
}
-(void)updateViews{
self.monthLabel.textColor = self.monthTextColor;
self.dayLabel.textColor = self.dayTextColor;
self.backgroundColorRoundLayer.fillColor = self.fillColor.CGColor;
}
-(void)updateConstraints{
self.dayLabelStickButtomConstraint.constant = self.dayLabelInsetDistance;
self.monthLabelStickTopConstraint.constant = self.monthLabelInsetDistance;
[super updateConstraints];
}
After a lot of messing around the answer lied in the restraints themselves. Once i switched from topMargin,bottomMargin to just top and bottom it worked

iOS Auto layout Rows

I'm trying to understand auto layout better and I created some static methods that can help me out. Now I'm trying to setup an array of views in like a tableview structure (in rows). This works kinda.
See here my problem:
To achieve this I use this code:
//In the update constraints method
UIView *view1 = [self createView];
view1.backgroundColor = [UIColor redColor];
UIView *view2 = [self createView];
view2.backgroundColor = [UIColor yellowColor];
[self addSubview:view1];
[self addSubview:view2];
[self addConstraints:[DXVFL row:#[view1, view2] inView:self]];
//The row method
+ (NSArray *) row:(NSArray const *)views inView:(UIView const *)superview {
NSMutableArray *constraints = [NSMutableArray new];
CGFloat multiplier = 1.f / [views count];
UIView *prev = nil;
for (UIView *view in views) {
if (!view.hidden) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeWidth multiplier:1.f constant:0.f]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeHeight multiplier:multiplier constant:0.f]];
if (prev) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prev attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
}
prev = view;
}
}
return [constraints copy];
}
So this part works (I guess). But when I want to split the yellow view again in rows. The views are always added into the top region?
In the update constraints method I do this:
UIView *view1 = [self createView];
view1.backgroundColor = [UIColor redColor];
UIView *view2 = [self createView];
view2.backgroundColor = [UIColor yellowColor];
[self addSubview:view1];
[self addSubview:view2];
UIView *view3 = [self createView];
UIView *view4 = [self createView];
[view2 addSubview:view3];
[view2 addSubview:view4];
[self addConstraints:[DXVFL row:#[view1, view2] inView:self]];
[view2 addConstraints:[DXVFL row:#[view3, view4] inView:view2]];
But I want those two rows in the bottom? What am I doing wrong?
Off the top of my head:
You need to add a constraint to tell it to align the view to the top of the superview. At the moment, you just set the height and width but you don't tell it where to put its top edge.
Try changing your code to this:
if (!prev) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.f constant:0.f]];
} else {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prev attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
}

Auto Layout for dynamic/draggable UIView

I am trying to have a draggable UIView within my ViewController, eventually this UIView will become a clickable button but for now, I am stuck with updating the constraints of this view when it is dragged on the screen. The code is below.
- (void)viewDidLoad
{
[super viewDidLoad];
self.anotherView = [[UIView alloc]init];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(dragging:)];
[self.anotherView addGestureRecognizer:panRecognizer];
[self.anotherView setBackgroundColor: [UIColor blueColor]];
self.anotherView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview: self.anotherView];
[self.view bringSubviewToFront:self.anotherView];
NSDictionary *views = #{#"subview" : self.anotherView, #"superview" : self.view};
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:Nil
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:20]];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:[subview(40)]"
options:0
metrics:nil
views:views]];
// add horizontal constraints
/*[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[subview(==20)]|" options:0 metrics:nil views:views]];
// set the height of the offscreen subview to be the same as its superview
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[subview(==40)]" options:0 metrics:nil views:views]];
// set the location of the subview to be just off screen below the current view
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.anotherView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1.0 constant:self.view.bounds.size.height];
[self.view addConstraint:constraint];*/
//[self.anotherView pinEdges:JRTViewPinLeftEdge toSameEdgesOfView:self.view];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}
The above code is how I have setup the UIView within the ViewController. It is expected to be of size 20x45. The code for dragging is below:
-(void)dragging:(UIPanGestureRecognizer *)gesture
{
if(gesture.state == UIGestureRecognizerStateBegan)
{
//NSLog(#"Received a pan gesture");
self.panCoord = [gesture locationInView:gesture.view];
[self.tableView setScrollEnabled:NO];
}
CGPoint newCoord = [gesture locationInView:gesture.view];
float dX = newCoord.x-self.panCoord.x;
float dY = newCoord.y-self.panCoord.y;
CGFloat newXPoint;
CGFloat newYPoint;
gesture.view.frame = CGRectMake(gesture.view.frame.origin.x+dX, gesture.view.frame.origin.y+dY, gesture.view.frame.size.width, gesture.view.frame.size.height);
if (gesture.state == UIGestureRecognizerStateEnded) {
newYPoint = gesture.view.frame.origin.y+dY;
if (gesture.view.frame.origin.x+dX<(self.view.frame.size.width/2)) {
newXPoint = 0;
}
else {
newXPoint = self.view.frame.size.width - gesture.view.frame.size.width;
//The below is just an attempt to remove and re-add constraints so the view will stick to the right side of the screen. It is not working :(
[self.view removeConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0]];
}
// self.draggedViewCoordinate = gesture.view.frame.origin;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.70];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.anotherView layoutIfNeeded];
[UIView commitAnimations];
[self.tableView setScrollEnabled:YES];
}
}
I am not getting how to update the constraints so the view will stick to the new dragged location. Can anyone help on this?
The accepted answer is incorrect. It's very expensive operation for UI to add/remove constraints.
Proper solution would be changing
self.yCoordinate.constant
and
self.xCoordinate.constant
properties based on dX and dY.
Okay, I solved it with the below code!
-(void)dragging:(UIPanGestureRecognizer *)gesture
{
if(gesture.state == UIGestureRecognizerStateBegan)
{
//NSLog(#"Received a pan gesture");
self.panCoord = [gesture locationInView:gesture.view];
[self.tableView setScrollEnabled:NO];
}
CGPoint newCoord = [gesture locationInView:gesture.view];
float dX = newCoord.x-self.panCoord.x;
float dY = newCoord.y-self.panCoord.y;
CGFloat newXPoint;
CGFloat newYPoint;
gesture.view.frame = CGRectMake(gesture.view.frame.origin.x+dX, gesture.view.frame.origin.y+dY, gesture.view.frame.size.width, gesture.view.frame.size.height);
if (gesture.state == UIGestureRecognizerStateEnded) {
newYPoint = gesture.view.frame.origin.y+dY;
CGFloat newYPosition = (self.view.frame.size.height/2) - newYPoint - 20;
if (gesture.view.frame.origin.x+dX<(self.view.frame.size.width/2)) {
[self.view removeConstraint:self.xCoordinate];
[self.view removeConstraint:self.yCoordinate];
self.xCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0];
[self.view addConstraint:self.xCoordinate];
self.anotherView.translatesAutoresizingMaskIntoConstraints = NO;
self.yCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:-newYPosition];
[self.view addConstraint:self.yCoordinate];
}
else {
newXPoint = self.view.frame.size.width - gesture.view.frame.size.width;
[self.view removeConstraint:self.xCoordinate];
[self.view removeConstraint:self.yCoordinate];
self.xCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0];
[self.view addConstraint:self.xCoordinate];
self.anotherView.translatesAutoresizingMaskIntoConstraints = NO;
self.yCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:-newYPosition];
[self.view addConstraint:self.yCoordinate];
}
// self.draggedViewCoordinate = gesture.view.frame.origin;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.70];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.anotherView layoutIfNeeded];
// gesture.view.frame = CGRectMake(newXPoint, newYPoint, gesture.view.frame.size.width, gesture.view.frame.size.height);
[UIView commitAnimations];
[self.tableView setScrollEnabled:YES];
}
}
Essentially, I maintained a reference to the constraints. This helped me in removing/re-adding the constraints based on the position of the dragged view.
This simplified version solved for me when dragging down and up:
#implementation SomeController
{
float beginDragPointY;
NSLayoutConstraint someConstraint;
}
- (void) viewDidLoad
{
// Define someConstraint
}
- (void) onDragGesture: (id) sender
{
UIPanGestureRecognizer* recognizer = (UIPanGestureRecognizer*)sender;
UIGestureRecognizerState state = recognizer.state;
CGPoint translation = [sender translationInView:self.view];
switch(state)
{
case UIGestureRecognizerStateBegan:
NSLog(#"Translation began %f %f", translation.x, translation.y);
beginDragPointY = translation.y;
break;
case UIGestureRecognizerStateChanged:
showBasicEventAnnotationConstraint.constant += translation.y - beginDragPointY;
beginDragPointY = translation.y;
[self.view setNeedsLayout];
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed:
case UIGestureRecognizerStatePossible:
default:
break;
}
[self.view layoutIfNeeded];
}

Resources