I have a UIScrollView with multiple components.I need to add UITextfields in such a way that on tap of a button the textfields will get add one below another vertically.for eg if button tapped 100 times.100 uitextfields should get added, also there are components below this uitextfield so the uiscrollview should adjust its height accordingly.
Note: Original answer edited with fill / get example code.
Here is a simple example.
Add a UIStackView
(vertical axis) to the scroll view. With each button tap, create a new UITextField
and add it as an arrangedSubview
of the stack view.
The stack view will automatically expand vertically, and its constraints will automatically handle the scroll view's content size.
ViewController.h
//
// ViewController.h
//
// Created by Don Mag on 12/3/19.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m
//
// ViewController.m
//
// Created by Don Mag on 12/3/19.
//
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) UIButton *theButton;
@property (strong, nonatomic) UIButton *fillButton;
@property (strong, nonatomic) UIButton *getButton;
@property (strong, nonatomic) UIScrollView *theScrollView;
@property (strong, nonatomic) UIStackView *theStackView;
@property (strong, nonatomic) NSMutableArray *theData;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor whiteColor]];
// instantiate buttons, scrollView and stackViews
// adds a new text field
_theButton = [UIButton new];
[_theButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[_theButton setTitle:@"Add Field" forState:UIControlStateNormal];
[_theButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
[_theButton setBackgroundColor:[UIColor redColor]];
// fills the fields with sample data
_fillButton = [UIButton new];
[_fillButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[_fillButton setTitle:@"Fill Fields" forState:UIControlStateNormal];
[_fillButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
[_fillButton setBackgroundColor:[UIColor redColor]];
// logs the text of each field to debug console
_getButton = [UIButton new];
[_getButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[_getButton setTitle:@"Get Text" forState:UIControlStateNormal];
[_getButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
[_getButton setBackgroundColor:[UIColor redColor]];
// scroll view will hold the stack view filled with fields
_theScrollView = [UIScrollView new];
[_theScrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_theScrollView setBackgroundColor:[UIColor cyanColor]];
// stack view to hold the new fields
_theStackView = [UIStackView new];
[_theStackView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_theStackView setAxis:UILayoutConstraintAxisVertical];
[_theStackView setSpacing:8.0];
// stack view for buttons
UIStackView *buttonsStackView = [UIStackView new];
[buttonsStackView setTranslatesAutoresizingMaskIntoConstraints:NO];
[buttonsStackView setAxis:UILayoutConstraintAxisHorizontal];
[buttonsStackView setSpacing:8.0];
// add buttons to the buttons stack view
[buttonsStackView addArrangedSubview:_theButton];
[buttonsStackView addArrangedSubview:_fillButton];
[buttonsStackView addArrangedSubview:_getButton];
// add button stack view and scrollView to view
[self.view addSubview:buttonsStackView];
[self.view addSubview:_theScrollView];
// add stackView to scrollView
[_theScrollView addSubview:_theStackView];
UILayoutGuide *g = self.view.safeAreaLayoutGuide;
UILayoutGuide *sg = _theScrollView.contentLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
// constrain buttons 20-pts from top, centered horizontally
[buttonsStackView.topAnchor constraintEqualToAnchor:g.topAnchor constant:20.0],
[buttonsStackView.centerXAnchor constraintEqualToAnchor:g.centerXAnchor constant:0.0],
// constrai scrollView 20-pts below button, 20-pts on each side and bottom
[_theScrollView.topAnchor constraintEqualToAnchor:_theButton.bottomAnchor constant:20.0],
[_theScrollView.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:-20.0],
[_theScrollView.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
[_theScrollView.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
// constrain stackView 8-pts on each side
[_theStackView.topAnchor constraintEqualToAnchor:sg.topAnchor constant:8.0],
[_theStackView.bottomAnchor constraintEqualToAnchor:sg.bottomAnchor constant:-8.0],
[_theStackView.leadingAnchor constraintEqualToAnchor:sg.leadingAnchor constant:8.0],
[_theStackView.trailingAnchor constraintEqualToAnchor:sg.trailingAnchor constant:-8.0],
// constrain stackView width to scrollView frame width minus 16-pts (for 8-pts on each side)
[_theStackView.widthAnchor constraintEqualToAnchor:_theScrollView.frameLayoutGuide.widthAnchor constant:-16.0],
]
];
[_theButton addTarget:self action:@selector(addTextField:) forControlEvents:UIControlEventTouchUpInside];
[_fillButton addTarget:self action:@selector(fillFields:) forControlEvents:UIControlEventTouchUpInside];
[_getButton addTarget:self action:@selector(getFields:) forControlEvents:UIControlEventTouchUpInside];
// sample data to fill the fields with
NSString *s = @"This is just random text that will be used to fill the text fields when the fill button is tapped";
_theData = [s componentsSeparatedByString:@" "].mutableCopy;
}
- (void)fillFields:(id)sender {
// set the text of each field based on the data array
NSInteger idx = 0;
for (UITextField *f in _theStackView.arrangedSubviews) {
// make sure we don't have more fields than our data array
if (idx < _theData.count) {
f.text = _theData[idx++];
}
}
}
- (void)getFields:(id)sender {
// log the text of each field to debug cosole
for (UITextField *f in _theStackView.arrangedSubviews) {
NSLog(@"%@", f.text);
}
}
- (void)addTextField:(id)sender {
// instantiate a new text field
UITextField *f = [UITextField new];
[f setBorderStyle:UITextBorderStyleRoundedRect];
[f setBackgroundColor:[UIColor whiteColor]];
// add it to the stack view
[_theStackView addArrangedSubview:f];
// set its placeholder text (just to make it easy to see what we're doing)
[f setPlaceholder:[NSString stringWithFormat:@"Text Field %ld", _theStackView.arrangedSubviews.count]];
dispatch_async(dispatch_get_main_queue(), ^{
// auto-scroll to bottom so newly added text field is visible
CGRect r = CGRectMake(0.0, self.theScrollView.contentSize.height - 1.0, 1.0, 1.0);
[self.theScrollView scrollRectToVisible:r animated:YES];
});
}
@end
Result after 3 taps:
after enough taps to need to scroll:
and after tapping the "Fill Fields" button: