Objective-C: add subview only work for one view - ios

For each UIImageView, I want to add the label subview to it.
Here is my class inherited form UIImageView
-(instancetype)initWithFrame:(CGRect)frame
{
if (self=[super initWithFrame:frame]) {
self.categoryLabel=[[UILabel alloc]initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, 50)];
self.categoryLabel.textAlignment=NSTextAlignmentCenter;
self.categoryLabel.font=[UIFont systemFontOfSize:20];
self.categoryLabel.textColor=[UIColor whiteColor];
[self addSubview:self.categoryLabel];
NSLog(#"%#",self.subviews);
}
return self;
}
-(void)setModel:(HorizontalModel *)model
{
_model=model;
self.categoryLabel.text=self.model.category;
[self sd_setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"XXXXX%#",self.model.imgURL]] placeholderImage:[UIImage imageNamed:#"obama"]];
}
Here is my code in the view controller.
-(void)addImage:(NSNotification *)notification
{
self.HArrayLists=notification.userInfo[#"array"];
for (int i=0; i<[self.HArrayLists count]; i++) {
JTImageView *imageView=[[JTImageView alloc] initWithFrame:CGRectMake(i*310, 0, 300, 200)];
imageView.model=[HorizontalModel restaurantsDetailWithDict: self.HArrayLists[i]];
[self.mediaScrollView addSubview:imageView];
}
self.mediaScrollView.contentSize=CGSizeMake(310*[self.HArrayLists count], 0);
}
It turns out that only the first imageView shows a label, while the rest of the imageViews show only images.

I think the core of your problem is the line:
self.categoryLabel=[[UILabel alloc]initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, 50)];
You are offsetting the x and y positions of the label by the x and y values of the image. This will place them outside the area of the image and with the image clipping, make them invisible. I think the line should be
self.categoryLabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, 50)];
to place all the labels at the top left corner of each image.
Having said that there are also a number of recommendations I would like to offer.
Firstly make all variable names start with a lowercase. So self.HArrayLists should be self.hArrayLists.
Secondly try and make variable names match their contents. So again looking at self.HArrayLists, perhaps something like self.imageData.
Next I would have done the composition differently. I would have a UIView to which I add both the UILabel and UIImageView instances. Using a parent view like this to layout two sub views often makes life easier.
I would also look into using a UICollectionView and UICollectionViewController rather than a UIScrollView. It will take you a bit of work to get your heads around how collection views work. But you will gain in terms of performance and better layout management.
Finally, study up on constraints. They're an essential part of building modern apps that can easily adapt to different sized screens, rotation and layouts.

You need to set as categoryLabel's frame properly.
self.categoryLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, frame.origin.y, frame.size.width, 50)];

Related

Setting up a UIScrollView. UIImageView images are distorted if called in viewDidLayoutSubviews. Image included

I am having a strange problem here. I have a UIScrollView that is setup in the interface builder. I add content to it via a method called setupScrollView which is as follows :
-(void)setupScrollView {
UIView *content = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width*[self.stickers count], self.scrollView.frame.size.height)];
for(int i=0; i<[self.stickers count]; i++){
UIImageView *imageView= [[UIImageView alloc] initWithFrame:CGRectMake(i*self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
MySticker *sticker = self.stickers[i];
imageView.image=sticker.image;
[content addSubview:imageView];
NSLog(#"scroll view width is %f",self.scrollView.frame.size.width);
NSLog(#"ImageView width is %f", imageView.frame.size.width);
}
self.scrollView.contentSize=CGSizeMake(content.frame.size.width ,content.frame.size.height);
[self.scrollView addSubview:content];
}
Now I call this method in viewDidLayoutSubviews because I need the views to be repositioned first after using the constraints set in the interface builder. This all works fine but my images in the scroll view are slightly distorted with jagged edges, there are sticker/chat images with black outlines so it's quite noticeable. If however I place the [self setupScrollView] in the viewDidLoad method the images won't be distorted and look perfectly clear. Example image:
Have no idea why it is doing this. Could anyone give me some pointers to what I might be doing wrong?
If it works correctly in viewDidLoad try to call setupScrollView method in viewWillLayoutSubviews method.
Also check situation when setupScrollView will be call more than once to avoid adding duplicates.

CGRectIntersectsRect with 2 UIImageViews does not work

I have a problem.
Briefly: CGRectIntersectsRect(object1.frame, object2.frame) placed in UIViewController does not work for object1 and object2 created in different classes (Class1 and Class2). I only can change their coordinates like object1.center.x, and object1.frame.size.width = 0 (I guess this is why CGRectIntersection function does not work). These objects just came through each other.
As I understand it may be connected with protocol/delegating, but I haven't found any sufficient information how to be in my situation.
Platform.m (my class for creating a platform in the ViewController)
#implementation Platform
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
platformView = [[UIImageView alloc]initWithFrame:frame];
platformView.image = [UIImage imageNamed:#"platform.png"];
[self addSubview:platformView];
}
return self;
}
ViewController.m (in the #interface there are Platform *platform; Kelvin *kelvin;)
-(void)addPlatform
{
platform = [[Platform alloc]initWithFrame:CGRectMake(initialPlatformX, (500 - arc4random()%200), 200, 10)];
[self.view addSubview:platform];
}
**if (!CGRectIntersectsRect(kelvin.frame, platform.frame)) {
NSLog(#"%f", platform.frame.size.width);
}**
Your explanation is confusing and hard to follow.
This sentence, for example, is a total mystery to me:
As I understand it may be connected with protocol/delegating, but i
haven't found any sufficient information how to be in my situation.
Delegation? Huh? Rectangles are not objects. Delegation is a design pattern for objects. How is that relevant here? (Answer: Very likely it isn't relevant at all.)
Moving on, though, here are a few things to consider:
2 views' frames will only use the same coordinate system if they are both subviews of the same view. So are your platform and your "kelvin" view subviews of the same view (It looks like you add platform directly to the view controller's content view, so is your "kelvin" view also a subview of the view controller's content view?)
Also, you make reference to object1.frame.size.width = 0
The CGRectIntersectsRect function checks to see if any pixels of the 2 rectangles overlap. If either of your rectangles has either a height or a width of 0, it's empty, and can't intersect with anything.
In initWithFrame, you are adding a UIImageView subview to Platform using the frame of Platform. That is incorrect. For example, if you add PlatForm at CGRectMake(10, 10, 100, 100), you'll then be adding the image view at CGRectMake(10, 10, 100, 100) within Platform (which is CGRectMake(20, 20, 100, 100) within the original view).
So, instead, I think you want to make a CGRect that starts at 0, 0 (or use the bounds of Platform, not its frame):
#implementation Platform
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
platformView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
platformView.image = [UIImage imageNamed:#"platform.png"];
[self addSubview:platformView];
}
return self;
}
By the way, just to be safe, you might also want to set clipsToBounds to YES, so that if you ever change contentMode to something that doesn't scale to fit, you don't have to worry about the image bleeding over its bounds.

Scroll a view with 20 text boxes horizontally using UIScrollView

I have to implement 20 text boxes horizontally. How can I add a scroll bar to see all text boxes when I scroll to the left.
please try following code:
UIScrollView *scrlView=[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
scrlView.scrollEnabled=YES;
int x=5;
int y=5;
for (int i=0;i<20;i++ ) {
UITextField *txtField=[[UITextField alloc] initWithFrame:CGRectMake(x,y , 100,40 )];
txtField.tag=i;
txtField.delegate=self;
[scrlView addSubview:txtField];
x+=105;
}
scrlView.contentSize=CGSizeMake(x, 50);
[self.view addSubview:scrlView];
i hope this code will help you.
You can find plenty of questions about this topic (i.e., Calculate the contentsize of scrollview), but nonetheless here is my solution:
You want to use the UIScrollView for the task. Using it is rather simple in fact.
First you need to initialise and display the UIScrollView somewhere in your screen. I am going to assume that you are in a UIViewController, and that you want to create a scroll view of 300px width and 200px height. For this, you can do the following:
UIScrollView *aScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
[[self view] addSubview:aScrollView];
[aScrollView setScrollEnabled:YES];
Now its time to place the content inside of it.
The key idea here to take into consideration is the following. While the 'UIScrollView' has a size itself, it also has an internal size for it's content, which is essentially the are that is scrollable.
Let's suppose that you have 20 items, each of which has a size of '40px width', and '200px height'. I am also going to suppose that you will want to leave a space of 10px between each text box. Thus, the total scrollable width for the area that we want to have inside the 'UIScrollView' is the following: (20 (items) * (40 (size of each item) + 10 (distance between each item))) -10. We shall then do the following:
[aScrollView setContentSize:CGSizeMake((20*(40 + 10))-10), 200];
All right, we are almost done. Now all we have to do is add each of the text items to the scroll view. Instead of doing it one by one, I am going to assume that you have them inside a collection such as a NSArray (probably an NSMutableArray).
NSArray *textFields; // the array with the collection of text boxes
int x = 0;
for (UITextField *aTextField in textFields){
[aTextField setFrame:CGRectMake(x, 0, 40, 200)];
[[self view] addSubview:aTextField];
x += 40 + 10; // incrementing the X coordinate to correctly place the next item
}
That's it!

iOS: Autolayout causing UIScrollView to not scroll

I have set up a UIScrollView with which I want to display 12 images (only 8 fit on screen) laid out horizontally. In the following image you can see the problem I'm having (which makes my scroll view not scroll), my constraints and the UIScrollView which I have added on storyboard:
I have called the following method on -(void)viewDidLoad, where I "set up"my scrollview (itemList is my scroll view property and itemNames a array with the images'names):
- (void)setupHorizontalScrollView
{
self.itemList.delegate = self;
[self.itemList setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.itemList setBackgroundColor:[UIColor blackColor]];
[self.itemList setCanCancelContentTouches:NO];
self.itemList.indicatorStyle = UIScrollViewIndicatorStyleWhite;
self.itemList.clipsToBounds = NO;
self.itemList.scrollEnabled = YES;
self.itemList.pagingEnabled = NO;
NSInteger tot=0;
CGFloat cx = 0;
for (; ; tot++) {
if (tot==12) {
break;
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.itemNames objectAtIndex:tot]]];
CGRect rect = imageView.frame;
rect.size.height = 40;
rect.size.width = 40;
rect.origin.x = cx;
rect.origin.y = 0;
imageView.frame = rect;
[self.itemList addSubview:imageView];
cx += imageView.frame.size.width;
}
[self.itemList setContentSize:CGSizeMake(cx, [self.itemList bounds].size.height)];
}
I have added the [self.itemList setTranslatesAutoresizingMaskIntoConstraints:NO]; because I saw this suggestion on other posts, but it doesn't work with or without it. The only way it works is if I uncheck use AutoLayout on the storyboard, but that moves the UIImageViewI use to look as a navigation bar to the bottom of the screen.
I don't know what to do anymore, any help is appreciated :)
Try to set your scrollView's Content size int "viewDidLayoutSubviews" method with keeping the autolayouts set.
-(void)viewDidLayoutSubviews
{
[self.itemList setContentSize:CGSizeMake(required_width, required_height)];
}
Two Solutions:
Create different constraints that can be satisfied simultaneously (you will have to edit). I think the problem is your bottom space and top space constraints are mutually exclusive. please remove one and try again. IF this is difficult for you, try adding another UIView to contain the UIScrollView to help manage your constraints, it might seem odd at first, but sometimes adding another view to contain your view actually makes it simpler at each level.
Turn off Autolayout, and change the autoresize masks of your UIImageView to be what you wish.
Insert: [scrollView setContentSize:CGSizeMake(x,y)]; in the following method:
-(void)viewWillAppear:(BOOL)animated

Constrain UIScrollView panning?

UIScrollView has a built-in behavior "directionLockEnabled".
When enabled, panning will attempt to lock to either the horizontal or vertical directions. But when the user aggressively attempts to scroll diagonally - it still allows diagonal scrolling.
I'd like to remove the ability to diagonally scroll.
Many thanks in advance.
EDIT:
I've tried putting a UIScrollView inside another (each with dimensions so as to constrain the movement) but the pan recognizers seemed to conflict - only one worked.
I've looked at TTScrollView to see if it could be modified for the job - but it does not seem to be working properly out of the box (freezing after first gesture.)
I've tried adding a second action (listener) to UIScrollView.panGestureRecognizer to call setTranslation:inView with a constrained value. This resulted in erratic jumping.
And several other avenues probably not worth mentioning.
EDIT2:
Odrakir's solution works. Code looks like:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImage* image = [UIImage imageNamed:#"Sofia"];
UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, 1024 * 2, 768 * 2);
UIScrollView* scrollView1 = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 1024*2, 768)];
scrollView1.contentSize = CGSizeMake(1024*2, 768*2);
[scrollView1 addSubview:imageView];
UIScrollView* scrollView2 = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
scrollView2.contentSize = CGSizeMake(1024*2, 768);
[scrollView2 addSubview:scrollView1];
[self.view addSubview:scrollView2];
}
I never tried that, but I have an app that has a horizontal ScrollView, and inside it there are multiple views, each of them with their own vertical ScrollView.
It's kind of like a magazine, with different articles and each article has a number of pages.
Both ScrollViews work and the user can't scroll diagonally. You can try that.
The display hierarchy is Horizontal ScrollView-> View ->Vertical ScrollView

Resources