I have a UIScrollView that has UIViews in it, and in those UIViews are UIImageViews. I am trying to access the UIImageViews.
For proof of concept, I have a scrollview with a UIView, which contains a UIImageView in it, both whose tags are set to 0.
Code:
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
UIView *currentView = (UIView *)[scrollView viewWithTag:0];
UIImageView *currentImageView = (UIImageView *)[currentView viewWithTag:0];
[self bobbleView:currentImageView];
}
And then I am trying to bob that UIImageView up and down continuously (which is another matter in of itself, I can only get it to bobble once so I just that left that code in), but what is happening is the entire UIScrollView and its subviews are bobbing.
That code:
-(void)bobbleView:(UIView *)viewIn{
viewIn.transform = CGAffineTransformMakeScale(1.2, 1.2);
[UIView animateWithDuration:1 animations:^{
viewIn.transform = CGAffineTransformMakeScale(1.0, 1.0);
}];
}
Any thoughts?
The viewWithTag doc says:
Discussion
This method searches the _current view_ and all of its subviews for the specified view.
(emphasis mine)
What you are seeing is that:
(UIImageView *)[currentView viewWithTag:0]
returns
currentView
HTH
Yes.. Assign unique tags to the views and different to eachother. I bet that if you set a breakpoint in the call to bobbleView, your UIImageView object will be your UiScrollView and not the imageview nor the UiView... Use simply unique tags, like 100X fir the UIViews and 200X for the imageview
Related
I am currently trying to make a UIView containing some UILabel animate to a new size. But doing so I am having some trouble understanding what is really happening with my view. I read some other post about it but I am still unclear about what is really going on.
In my button I added something that just double the size of the right constraint :
[superView layoutIfNeeded];
rightConst.constant *= 2;
[UIView animateWithDuration:3
animations:^{
[superView layoutIfNeeded];
} completion:nil];
superView Being the view I wanna animate and rightConst the constraint to the right.
But doing so, the animation starts but it is actually coming from left. I don't understand this part. My goal would be to animate just the right side of the view to show the resize and maybe the bottom part of the view but the top left should be fixed.
Thanks.
As described in this document, if you call [aView layoutSubviews], layout of the subviews of aView is forced but layout of aView itself is NOT forced.
You need to call layoutSubviews of the superview of the view you want to animate. In this case, the superview of the superview of the two labels.
Solution is here
UIView *theView;
// theView is the superview of the superview of the two labels.
theView = superView.superview;
[theView layoutIfNeeded];
rightConst.constant *= 2;
[UIView animateWithDuration:3
animations:^{
[theView layoutIfNeeded];
} completion:nil];
I use pure code (not storyboard or xib) to set size of all views, and I don't want to use hard code to set frame , so I use Masonry.
Now I have a scrollView and a set of views as subviews of the scrollview, the code is like this:
[self.scrollview addSubview:[self.imageviews objectAtIndex:0]];
[[self.imageviews objectAtIndex:0] mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(self.scrollview);
make.top.equalTo(#0);
make.left.equalTo(#0);
}];
for (NSInteger i = 1; i < maxcnt ; i++) {
[self.scrollview addSubview:[self.imageviews objectAtIndex:i]];
UIImageView *previous = [self.imageviews objectAtIndex:i-1];
[[self.imageviews objectAtIndex:i] mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(self.scrollview);
make.top.equalTo(#0);
make.left.equalTo(previous.mas_right);
}];
}
But here comes the problem:
1) How I can use Masonry to set the contentsize of the scrollview? The following code not works well because in rotate event, self.view.frame.size.width change.
self.scrollview.contentSize = CGSizeMake(self.imageviews.count * self.view.frame.size.width, self.view.frame.size.height);
2) If I have to use the upper code to set, how to deal with rotate event so the contentsize is update well.
You are almost there. All you have to do is set a right constraint on the last image view. By doing so you create a "connection" between the left side of the contentView and the right side. That way the UIScrollView "knows" how much space the subviews need and adjusts the contentSize accordingly.
There is no need to set the contentSize at all. Auto Layout handles this for you and it also works when rotating the device.
I wrote a blog post about this a little while ago. It uses SnapKit but that is basically just another name for "Masonry with Swift". The syntax is pretty much the same. It describes a vertical scroll view but the idea is the same on a horizontal one.
One more small thing:
Instead of doing this:
make.top.equalTo(self.scrollview.mas_top);
You can do this:
make.top.equalTo(self.scrollview);
I want to create a scrollView having many sub views as shown in image.
All views having a labels & image within it.
Number of views add in scrollView are dynamic.
And data of that views is also dynamic.
So that I can't make a static view in program and use it for display.
I want to make scrollview's subview like TableView with custom cells.
Like make a object of that TableViewCell and use it.
Can I use ViewController for that?
If i understood you question true, you need something like dynamic content of scrollView. So you need an array to control how many cell you will put into scrollView and create label, imageView or whatever you need.
For example like that;
//You will need to clean your scrollView Content in everytime
for(UIView *view in [yourScrollView subviews]){
[view removeFromSuperview];
}
for(int i=0;i!=[yourArray count];i++)
{
labels[i]=[[UILabel alloc]init];
//anyInteger is about your views place.
views[i]=[[UIView alloc]initWithFrame:CGRectMake(21, i*anyInteger, 300, 50)];
views[i].backgroundColor=[UIColor colorWithRed:0.1 green:0.2 blue:1.8 alpha:0.0];
[views[i] addSubview:labels[i]];
[yourScrollView addSubview:views[i]];
}
These codes will help you about insert objects in yourScrollView. I didnt test this yet but i guess it will give you an idea.
I would like to know how to access a UIScrollView using a subview UILabel.
I have tried to access the UIScrollView using .superview; however I am now receiving an error
No visible #interface for 'UIView' declares the selector 'scrollRectToVisible:animated:'
The code I am using looks like this
- (void) SymbolButtonPressed:(NSString *)selectedString {
UILabel *label = (UILabel *)[self.view viewWithTag:currentlySelectedTag];
// perform scrolling here, figure out what view your uilable is in.
float newPosition = label.superview.contentOffset.x+label.frame.size.width;
CGRect toVisible = CGRectMake(newPosition, 0, label.superview.frame.size.width, label.superview.frame.size.height);
[label.superview scrollRectToVisible:toVisible animated:YES];
}
The superview of a UILabel is of type UIView and so does not respond to the method you are trying to call. You can cast the superview as a UIScrollView so that Xcode can see the methods and properties you are trying to access. You should also check if the superview responds to the method.
if([label.superview respondsToSelector:#selector(scrollRectToVisible:animated:)]) {
[(UIScrollView *)label.superview scrollRectToVisible:toVisible animated:YES];
}
Given your sample code you will also need to cast the superview to get contentOffset
float newPosition = ((UIScrollView *)label.superview).contentOffset.x+label.frame.size.width;
I have added a number of labels to a view giving them tags.
What is the correct way to retrieve a label from the view. I am wanting to re-postion the label. Here is what I am using to retrieve the label and re-position it:
UILabel *theLabel = (UILabel *)[self.view viewWithTag:5];
[theLabel.layer setPosition:CGPointMake(100, 200)];
Is this the correct way of doing it?
There's no need to go to the layer level, although it might work fine.
theLabel.center = CGPointMake(100,200);
I guess that does the same thing, without looking at the documentation to verify that a layer's default anchor point is its center.
You can use fast enumeration with a for-loop:
for (UIView *view in [self.view subViews]) {
if([view isKindOfClass:[UILabel class]]) {
// do your stuff here
}
}
Try this, it will surely work.
To retrieve the label, use an IBOutlet if you've created it in Interface Builder, or a raw property or ivar if created in code. There's no need to loop the subviews or use viewWithTag if you've got a direct reference (outlet, property, ivar) to it.
To move the label, directly set its frame or center property without needing to access its layer.