Scroll a view with 20 text boxes horizontally using UIScrollView - ios

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!

Related

Objective-C: add subview only work for one view

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)];

Layout in UIScrollView

I am new to UIScrollView, and they are driving me crazy.
I am trying to create a screen that has a title and some descriptive text at the top, and then a scroll view (with paging enabled) in the bottom two thirds of the screen. This scroll view will contain 1-3 images. Ideally, I'd like the first image to appear centered in the initial scroll view window, and then enable the user to view the other images by scrolling/paging horizontally, again ideally with each image centered in its 'page'.
The code below loads the images for 'item' from the Internet, creates a UIImageView for each, and inserts them into the scroll view. According to the frame calculations, I would expect the first image to be up against the left side of the scrollview, and then the other images to the right, with no space between them. But instead, the first image is shifted to the right, about half-way across the screen, and there are equally large spaces between each image.
I have turned off paging to simplify matters, and I have tried experimenting with tweaking the image frame values, trying to understand what's happening, but nothing works as I expect it to.
I am guessing that autolayout is messing with me. Can someone confirm that, and maybe give me some hints on how to get this scrollview under control?
Thanks in advance.
self.imageScrollView.contentSize = CGSizeMake(self.imageScrollView.frame.size.width * (imageFieldNames.count),
self.imageScrollView.frame.size.height);
self.imageScrollView.pagingEnabled = NO;
CGFloat xPos = 0.0;
for (NSString *field in imageFieldNames) {
NSString *name = [self.item valueForKey:field];
if (name.length > 0) {
UIImageView *iv = [[UIImageView alloc] init];
iv.contentMode = UIViewContentModeScaleAspectFit;
[self loadImage:iv withFile:name];
iv.frame = CGRectMake(xPos, 0.0,
self.imageScrollView.frame.size.width,
self.imageScrollView.frame.size.height);
[self.imageScrollView addSubview:iv];
xPos += self.imageScrollView.frame.size.width;
}
}

Adding Images By incrementing label count

Here,when button taps label count is increments & decrements.While label count increments images will be added by respective count.here my code for incrementing label count
if (counter >= 9 )
return;
[_count setText:[NSString stringWithFormat:#"%d",++counter]];
but i need to display while incrementing the label count then automatically increments images one by one.like this
Can you please help me how can i implement,thank you.
Add a UIScrollView in place of where you want to show images. When click on '+' button, call following method by passing the 'counter' value.
-(void)addImage:(int) count {
UIScrollView * scView = [[UIScrollView alloc] init];
scView.frame = CGRectMake(30, 60, self.view.frame.size.width, 60);
UIButton * btn;
UIImageView * imgV;
float imgWidth = 44;
for(int i=0;i<count;i++) {
imgV = [[UIImageView alloc] init];
imgV.frame = CGRectMake(i*imgWidth, 0, imgWidth, 44);
imgV.image = [UIImage imageNamed:#"gitar"];
[scView addSubview:imgV];
}
[scView setContentSize:CGSizeMake(imgWidth*count, 50)];
[scView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:scView];
}
- (IBAction)descrese:(id)sender {
counter -= 1;
[self addImage:counter];
}
- (IBAction)btnTap:(id)sender {
counter += 1;
[self addImage:counter];
}
This adds as many images as you want in horizontal scroll view.
use a uiscrollview with cells of images, that simple.
Use UIScrollView.
As number of elements is increasing/decreasing:
1) increse/deacrease UIScrollView size respectively
2) add/remove elements
I guess, the screenshot was taken from MMT app. They're using this feature in their app. I believe, they might have developed a separate control to handle this thing, where they can only pass few arguments like image to show (people), count etc.
You can also develop such kind of UI with following way:
Create a custom view, take a UICollectionView inside it, take argument of image to show and number of rows count, fixed the cell size in layouts. Add a method which will reloads UI (inside logic: reloading UICollectionView) to refresh content when user taps on [ + ] or [ - ] button. Why, we're not taking UIScrollView, with it we can't reuse contents. I believe this step will need you to create everything programmatically.
When user taps on [ + ], you should increase width of our custom view, inside
you should override layoutSubview method to update frame of UICollectionView as well. You may require to refresh(reload) cells inside UICollectionView.
Do reverse when user taps [ - ].
You may require to set some logic so user can't add more/less numbers when selection.
This is just an idea, you may require to check each cases which the reference app has having.

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

Applying transform to UITextView - prevent content resizing

When I apply a rotation transform to a UITextView and then click inside to begin editing, it appears that the content size is automatically being made wider. The new width of the content view is the width of the rotated view's bounding box. For example, given a text box of width 500 and height 400, and rotated by 30 degrees, the new content width would be:
(500 * cos(30)) + (400 * sin(30)) = 633
Or graphically:
Interestingly, if you are already editing the text view and THEN apply the transform, then it appears that no modification is made to the content size. So it appears that sometime around the start of text editing, the text view looks at its frame property and adjusts the content size based on the frame width. I imagine the solution to this is to tell it to use the bounds property instead, however I don't know where to do this, as I'm not sure exactly where the text view is deciding to modify the content size.
I have googled but can't seem to find any references to using transformed UITextViews. Does anybody have any ideas about this?
EDIT (button action from test project):
- (IBAction)rotateButtonTapped:(id)sender {
if (CGAffineTransformIsIdentity(self.textView.transform)) {
self.textView.transform = CGAffineTransformMakeRotation(30.0 * M_PI / 180.0);
}
else {
self.textView.transform = CGAffineTransformIdentity;
}
NSLog(#"contentsize: %.0f, %.0f", textView.contentSize.width, textView.contentSize.height);
}
I was also stuck with this problem.
The only solution which I found was to create an instance of UIView and add the UITextView as a subview. Then you can rotate the instance of UIView and UITextView will work just fine.
UITextView *myTextView = [[UITextView alloc] init];
[myTextView setFrame:CGRectMake(0, 0, 100, 100)];
UIView *myRotateView = [[UIView alloc] init];
[myRotateView setFrame:CGRectMake(20, 20, 100, 100)];
[myRotateView setBackgroundColor:[UIColor clearColor]];
[myRotateView addSubview:myTextView];
myRotateView.transform = CGAffineTransformMakeRotation(0.8);
[[self view] addSubview:myRotateView];
Have you tried applying the rotation by doing a layer transform rather than a transform on the view?
#import <QuartzCore/QuartzCore.h>
mytextField.layer.transform = CATransform3DMakeRotation (angle, 0, 0, 1);
This might be enough to trick whatever broken logic exists inside the core text field code.

Resources