I have a UITextView added on my UIView programmatically. The textview added is not editable, it is just to display some data. The data displayed in the textview is getting from array.The no of the textviews are same as texts which I Stored in Array.Textview is displaying from start to end one by one.I need to set the postion of textview one by one means first textview come and set at some postion,second will be set as just before first textview,third will be just before on second and so on.. Note: Something like using Animation. suppose one textview come from top and it stops at Y postion at 250 then next textview will set at just before that..it cant come upto 250 of Y postion. and so on. I have no clue how to do this. Please give me some ideas.
Don't Consider the array and the UITextView data.... its fot temporary..
NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:#"One",#"Two",#"three",#"Four",#"Five",#"Six",#"Seven",#"Eight",#"Nine",#"Ten", nil];
for(int i=0;i<[array count];i++) {
UITextView *textView = [[UITextView alloc]init];
[textView setFrame:CGRectMake(20, 20*i+height, 200, height)];
[textView setBackgroundColor:[UIColor redColor]];
[textView setText:[array objectAtIndex:i]];
[self.view addSubview:textView];
}
you want to add textviews programmatically in your view based on the array,if you are adding textviews to your view then there is a problem(if u are having more number of textviews then you must take scroll view ) that's why better to take scroll view and add scroll view to your view after that you will add textviews to your scroll view ,
now take constant x-coordinate value ,width and height only change y-coordinate value and you must give the content size to scrollview .
for(int i=1;i<[array length];i++){
text_desc = [[UITextView alloc] initWithFrame:CGRectMake(63,64*i,370,60)];
text_desc.font = [UIFont fontWithName:#"Helvetica" size:13.0];
text_desc.editable=NO;
text_desc.tag=1;
}
and then set srollview content size,
scroll.contentSize = CGSizeMake(0,total*87);
//loop over the substrings of type Array to add textfields at run time
for (int i = 0; i < [substrings count]; i++)
{
CGRect frame = CGrectMake(0, i * 40, 100, 30);
UITextField * txtDynamic = [[UITextField alloc] initWithFrame: frame];
txtDynamic.text = [substrings objectAtIndex:i];
//add as subview
[view addSubview:txtDynamic];
//if you are not using ARC release the txtDynamic
}
Note
If number of UITextField more i.e it goes out of screen, then Add UITextField to UIScrollView and you can make its Size and content size dynamic.
Hope this will give you some clue.
hey mate then take one scrollview and in it just set all textview with its ContentSize like bellow
here i give an example ,
Note: this is just example here take one UIScrollView and give name scrview and after add your all this UITextField in it.
you add this code after you add data in textfield
txt1.frame = CGRectMake(txt1.frame.origin.x, txt1.frame.origin.y, txt1.frame.size.width, txt1.contentSize.height);
float txtscreen1 = txt1.frame.origin.y + txt1.contentSize.height + 10;
txt2.frame = CGRectMake(txt2.frame.origin.x, txtscreen1, txt2.frame.size.width, txt2.contentSize.height);
float txtscreen2 = txt2.frame.origin.y + txt2.contentSize.height + 10;
txt3.frame = CGRectMake(txt3.frame.origin.x, txtscreen2, txt3.frame.size.width, txt3.contentSize.height);
//.....and so on to 10
float txtscreen10 = txt3.frame.origin.y + txt3.contentSize.height + 10;
txt10.frame = CGRectMake(txt10.frame.origin.x, txtscreen10, txt10.frame.size.width, txt10.contentSize.height);
float scrollviewscreen = txtscreen10.frame.origin.y + txtscreen10.frame.size.height + 20;
scrview.contentSize=CGSizeMake(320, scrollviewscreen);//take scrollview
i hope this help you....
:)
Related
I've looked through many answers and they all seem very complex! Most recently I was looking at this answer although I'd prefer not to have to put my buttons inside views.
I have 6 UIButtons that are all the same dimensions. I want to space them evenly horizontally across the full width and at the bottom of my root view controller.
| |
| |
| [b1] [b2] [b3] [b4] [b5] [b6] |
________________________________________
What is the simplest way to achieve this programmatically?
I think this is simpler than the link on the accepted answer. Ok, firstly lets create some buttons:
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeSystem];
button1.translatesAutoresizingMaskIntoConstraints = NO;
[button1 setTitle:#"Btn1" forState:UIControlStateNormal];
... do that 6 times for 6 buttons, however you like then add them to the view:
[self.view addSubview:button1];
[self.view addSubview:button2];
[self.view addSubview:button3];
[self.view addSubview:button4];
[self.view addSubview:button5];
[self.view addSubview:button6];
Fix one button to the bottom of your view:
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
Then tell all the buttons to be equal width and spread out equally across the width:
NSDictionary *views = NSDictionaryOfVariableBindings(button1, button2, button3, button4, button5, button6);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[button1][button2(==button1)][button3(==button1)][button4(==button1)][button5(==button1)][button6(==button1)]|" options:NSLayoutFormatAlignAllBottom metrics:nil views:views]];
Result:
UIStackView was introduced in iOS9.
https://developer.apple.com/documentation/uikit/uistackview
I know this question is a bit old, but I've been programming in iOS for a few years now and dislike using autolayout. So I wrote a helper method to evenly space UIButtons horizontally and center them vertically within a UIView. This works great for menu bars.
- (void) evenlySpaceTheseButtonsInThisView : (NSArray *) buttonArray : (UIView *) thisView {
int widthOfAllButtons = 0;
for (int i = 0; i < buttonArray.count; i++) {
UIButton *thisButton = [buttonArray objectAtIndex:i];
[thisButton setCenter:CGPointMake(0, thisView.frame.size.height / 2.0)];
widthOfAllButtons = widthOfAllButtons + thisButton.frame.size.width;
}
int spaceBetweenButtons = (thisView.frame.size.width - widthOfAllButtons) / (buttonArray.count + 1);
UIButton *lastButton = nil;
for (int i = 0; i < buttonArray.count; i++) {
UIButton *thisButton = [buttonArray objectAtIndex:i];
if (lastButton == nil) {
[thisButton setFrame:CGRectMake(spaceBetweenButtons, thisButton.frame.origin.y, thisButton.frame.size.width, thisButton.frame.size.height)];
} else {
[thisButton setFrame:CGRectMake(spaceBetweenButtons + lastButton.frame.origin.x + lastButton.frame.size.width, thisButton.frame.origin.y, thisButton.frame.size.width, thisButton.frame.size.height)];
}
lastButton = thisButton;
}
}
Just copy and paste this method into any view controller. Then to access it, I first created all the buttons I wanted, then called the method with all of the buttons in an array, along with the UIView I wanted it in.
[self evenlySpaceTheseButtonsInThisView:#[menuButton, hierarchyMenuButton, downButton, upButton] :menuView];
The advantage of this method is that you don't need autolayout and it's super easy to implement. The disadvantage is that if your app works in landscape and portrait, you will need to make sure to call this method again after the view has been rotated.
I usually do something like:
int numButtons = 6;
float gap = 10.0f;
float y = 50.0f;
float width = (self.view.frame.size.width - gap * (numButtons + 1)) / numButtons;
float height = 60.0f;
for (int n=0;n<numButtons;n++) {
float x = gap * (n+1) + width * n;
UIButton *button = [self.buttons objectAtIndex:n]; //Or get button some other way/make button.
[button setFrame:CGRectMake(x,y,width,height)];
}
You can set numButtons to however many buttons you want in the row, and if you have an array of buttons, you can set it to the length of that array.
The y is just whatever y coordinate you want and the same goes for the height and gap, which is the space between buttons. The width is just a calculation of how wide each button will be based on the screen width and the gap space you want between each button.
You can send the Label/button/view's as array to this methods and arrange the button frames.
-(void)arrangeViewsXposition:(NSArray*)anyView y:(CGFloat)y width:(CGFloat)width height:(CGFloat)height mainViewWdith:(UIView*)mainview {
int count = (int)anyView.count;
CGFloat widthTemp = mainview.bounds.size.width, temp1 = widthTemp-(width*count),space = temp1/(count+1);
for (int i = 0; i<count; i++) {
UIView *btnTemp = (UIView*)[anyView objectAtIndex:i];
if (btnTemp) {
btnTemp.frame = CGRectMake(space+((space+width)*i), y, width, height);
}
}
}
Call this method like this:
[self arrangeViewsXposition:#[btnSave,btnCancel] y:5 width:80 height:30 mainViewWdith:footerView];
There are a number of decent auto-layout solutions discussed in this question:
Evenly space multiple views within a container view
Basically it can be a lot of manual constraint-definition code, which can be conveniently wrapped in a category extension for encapsulation/reuse.
I just cooked this up in Swift using Cartography.
func disributeEvenlyAcrossWithCartography(views: [UIView], enclosingBox: UIView, spacer: CGFloat = 10.0) {
var priorView = UIView() // never null
for (index, view) in views.enumerate() {
constrain(view, priorView, enclosingBox) { view, prior, enclosingBox in
view.height == enclosingBox.height
view.centerY == enclosingBox.centerY
if index == 0 {
view.width == enclosingBox.width / CGFloat(views.count) - spacer
view.left == enclosingBox.left
} else {
view.left == prior.right + (spacer + spacer / CGFloat(views.count - 1))
view.width == prior.width
}
}
priorView = view
}
}
Result with 5 views and a small spacer:
This is my first post on Stackoverflow. This site has been very helpful in getting me up to speed on Xcode and swift. Anyway, below is my quick-and-dirty fix to the above question.
Pin the left most button and the right most button, respectively.
Create "dummy" labels between each of the buttons. Set all of the "dummy" labels as equal widths. For each of the "dummy" label, add constraints (0 to the nearest neighbor on the left, and 0 to the nearest neighbor on the right). The buttons will then be equally spaced throughout, even when you change from portrait to landscape orientation.
This is what i have tried,
UITextView *_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, 300, 10)];
NSString *str = #"This is a test text view to check the auto increment of height of a text view. This is only a test. The real data is something different.";
_textView.text = str;
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;//Here i am adjusting the textview
[self.view addSubview:_textView];
Basically after fitting the text into textview,scrolling is enable,but i cannot view the content inside the textview without scrolling the textview.I do want to initialize the UITextView frame size based on the text size,font name etc.
Any solution is appreciated.Thanks.
NSString *str = #"This is a test text view to check the auto increment of height of a text view. This is only a test. The real data is something different.";
UIFont * myFont = [UIFont fontWithName:#"your font Name"size:12];//specify your font details here
//then calculate the required height for the above text.
CGSize textviewSize = [str sizeWithFont:myFont constrainedToSize:CGSizeMake(300, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
//initialize your textview based on the height you got from the above
UITextView *_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, textviewSize.width, textviewSize.height)];
_textView.text = str;
[self.view addSubview:_textView];
And also you want to disable the scrolling in textview then refer this.
As William Jockusch states in his answer here:
You can disable almost all scrolling by putting the following method
into your UITextView subclass:
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated {
// do nothing
}
The reason I say "almost" all scrolling is that even with the above,
it still accepts user scrolls. Though you could disable those by
setting self.scrollEnabled to NO.
If you want to only disable some scrolls, then make an ivar, lets call
it acceptScrolls, to determine whether you want to allow scrolling or
not. Then your scrollRectToVisible method can look like this:
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated {
if (self.acceptScrolls)
[super scrollRectToVisible: rect animated: animated];
}
I have scroll view with label and a table view and a button . I just want to scroll the scrollview and the table view must display all the contents but tableview must not scroll. Below the tableview i have a button. How to set the frame of the button so it comes exactly below the table?
Thanks
Maybe you would like to set the YourTableView.userInteractionEnabled = NO?
Yes we can disable the scrolling the tableview.
Goto->xib->select table->Goto 1st tab->unselect the scrolling Enabled.
The answer for your Second Question.
Put the UiView in footer of your table and then place the button in that UIView you want to show in bottom.
It will always show at the bottom.
If you want to place button programmatically use following code in viewDidload method.
///--------Table Footer is Set here
UIView *footer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 260, 44)];
UIButton *adddays = [[UIButton alloc] initWithFrame:CGRectMake(10, 0, 260, 44)];
[adddays setBackgroundImage:[UIImage imageNamed:#"abcd.png"] forState:UIControlStateNormal];
[adddays addTarget:self action:#selector(buttonaction) forControlEvents:UIControlEventTouchDown];
UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(75, 12, 250, 20)];
[text setBackgroundColor:CLEAR_COLOR];
[text setText:#"Title for your button"];
[text setTextColor:XDARK_BLUE];
text.font=[UIFont fontWithName:#"Arial-BoldMT" size:18.0f];
[footer addSubview:adddays];
[footer addSubview:text];
[table setTableFooterView:footer];
This is assuming you have created IBOutlets for your scrollView, tableView and button, and hooked them up appropriately.
I find it useful to remember that we're only messing with the y-values of a CGRect (origin.y & size.height) - The x-values should be set up in the xib.
I've commented this profusely to illustrate my point better, usually I would only comment where appropriate
-(void)viewDidLoad {
[self.tableView setScrollEnabled:NO];
// Get the number of rows in your table, I use the method
// 'tableView:numberOfRowsInSection:' because I only have one section.
int numOfRows = [self.tableView numberOfRowsInSection:0];
// Get the height of your rows. You can use the magic
// number 46 (44 without including the separator
// between rows) for the height of your rows, but because
// I was using a custom cell, I had to declare an instance
// of that cell and exctract the height from
// cell.frame.size.height (adding +2 to compensate for
// the separator). But for the purpose of this demonstration
// I'm going to stick with a magic number
int rowHeight = 46; //Eww, Magic numbers! :/
// Get a reference to the tableViews frame, and set the height
// of this frame to be the sum of all your rows
CGRect frame = self.tableView.frame;
frame.size.height = numOfRows * rowHeight;
// Now we have a frame with the exact size of our table,
// so set the 'tableView.frame' AND the 'tableView.contentSize'
// to that. (Because we want ALL rows visible as you
// disabled scrolling for the 'tableView')
self.tableView.frame = frame;
self.tableView.contentSize = frame.size;
// Now we want to set up the button beneath the table.
// We still have the 'frame' variable, which gives us
// the tableView's Y-origin and height. We just add these
// two together (with +20 for padding) to get the origin of the button
CGRect buttonFrame = self.button.frame;
buttonFrame.origin.y = frame.origin.y + frame.size.height + 20;
self.button.frame = buttonFrame;
// Finally, we want the `scrollView`'s `contentSize` to
// encompass this entire setup (+20 for padding again)
CGRect scrollFrame = self.scrollView.frame;
scrollFrame.size.height = buttonFrame.origin.y + buttonFrame.size.height = 20;
self.scrollView.contentSize = scrollFrame.size;
}
You could stop the scrolling the table view. But you shouldn't be adding a tableview inside a scrollview. UITableView is subclass of UIScrollView and adding one scrollView on another will create problem. I suggest you to remove the scrollview and use the tableview alone ( as the tableview itself is a scrollview).
How would I go about setting the content size for a scrollview, when the content size is dynamic. I have added all my content to a UIView named "contentView", then try calling the setcontentsize as below, but this results in no scrolling.
sudo'ish code:
[scrollView setContentSize: contentView.frame.size];
Maybe "contentView" is not stretching its size to fit its children?
Any help would be appreciated.
UIView or UIScrollView will not auto stretch based on content. You have to manually calculate the frames and position it accordingly inside the scrollview and then set the contentSize of the scrollview to the biggest possible size that can hold all its subviews.
This depends on the type of content you are going to add dynamically. So let's say you have a big text data to show, then use the UITextView and as it is a subclass of the UIScrollView, you can get the setContentSize of TextView when you assign the text content. Based on that you can set the total size of the UIScrollView.
float yPoint = 0.0f;
UIScrollView *myScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0f, yPoint, 320.0f, 400.0f)];
UITextView *calculatorTextView = [[UITextView alloc] init];
calculatorTextView.text = #"My looong content text ..... this has a dynamic content";
[calculatorTextView sizeToFit];
yPoint = yPoint + calculatorTextView.contentSize.height; // Bingo, we have the new yPoiny now to start the next component.
// Now you know the height of your text and where it will end. So you can create a Label or another TextView and display your text there. You can add those components as subview to the scrollview.
UITextView *myDisplayContent = [[UITextView alloc] initWithFrame:CGRectMake(0.0f, yPoint, 300.f, calculatorTextView.contentSize.height)];
myDisplayContent.text = #"My lengthy text ....";
[myScrollView addSubview:myDisplayContent];
// At the end, set the content size of the 'myScrollView' to the total length of the display area.
[myScrollView setContentSize:yPoint + heightOfLastComponent];
This works for me.
When you add stuff to your contentView call [contentView sizeToFit] and then the content view will stretch to fit its subviews, then, the code you post will work.
I'm having a scrollview as the detailedview of tableview cell. There are multiple views on the detailedview like labels, buttons etc. which I'm creating through interface builder. What I'm creating through interface builder is static. I'm putting everything on a view of height 480.
A label on my detailedview is having dynamic text which can extend to any length. The problem is that I need to set the scrollview's content size for which I need its height.
How shall I set scrollview's height provided the content is dynamic?
You could try to use the scrollview'ers ContentSize. It worked for me and I had the same problem with the control using dynamic content.
// Calculate scroll view size
float sizeOfContent = 0;
int i;
for (i = 0; i < [myScrollView.subviews count]; i++) {
UIView *view =[myScrollView.subviews objectAtIndex:i];
sizeOfContent += view.frame.size.height;
}
// Set content size for scroll view
myScrollView.contentSize = CGSizeMake(myScrollView.frame.size.width, sizeOfContent);
I do this in the method called viewWillAppear in the controller for the view that holds the scrollview. It is the last thing i do before calling the viewDidLoad on the super.
Hope it will solve your problem.
//hannes
Correct shorter example:
float hgt=0; for (UIView *view in scrollView1.subviews) hgt+=view.frame.size.height;
[scrollView1 setContentSize:CGSizeMake(scrollView1.frame.size.width,hgt)];
Note that this only sums heights, e.g. if there are two subviews side by side their heights with both be added, making the sum greater than it should be. Also, if there are vertical gaps between the subviews, the sum will be less than it should be. Wrong height confuses scrollRectToVisible, giving random scroll positions :)
This loop is working and tested:
float thisy,maxy=0;for (UIView *view in scrollView1.subviews) {
thisy=view.frame.origin.y+view.frame.size.height; maxy=(thisy>maxy) ? thisy : maxy;
}
A somewhat easier way to do this is to nest your layout within a view then put that view within the scrollview. Assuming you use tags, this works as follows:
UIScrollView *scrollview = (UIScrollView *)[self.view viewWithTag:1];
UIView *longView = (UIView *)[self.view viewWithTag:2];
scrollview.contentSize = CGSizeMake(scrollView.frame.size.width, longView.frame.size.height);
That way the longView knows how tall it is, and the scrollview's content is just set to match.
This depends on the type of content you are going to add dynamically. So let's say you have a big text data to show, then use the UITextView and as it is a subclass of the UIScrollView, you can get the setContentSize of TextView when you assign the text content. Based on that you can set the total size of the UIScrollView.
float yPoint = 0.0f;
UIScrollView *myScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0f, yPoint, 320.0f, 400.0f)];
UITextView *calculatorTextView = [[UITextView alloc] init]; calculatorTextView.text = #"My looong content text ..... this has a dynamic content"; `
[calculatorTextView sizeToFit];
yPoint = yPoint + calculatorTextView.contentSize.height; // Bingo, we have the new yPoint now to start the next component.
// Now you know the height of your text and where it will end. So you can create a Label or another TextView and display your text there. You can add those components as subview to the scrollview.
UITextView *myDisplayContent = [[UITextView alloc] initWithFrame:CGRectMake(0.0f, yPoint, 300.f, calculatorTextView.contentSize.height)];
myDisplayContent.text = #"My lengthy text ....";
[myScrollView addSubview:myDisplayContent];
// At the end, set the content size of the 'myScrollView' to the total length of the display area.
[myScrollView setContentSize:yPoint + heightOfLastComponent];
This works for me.
I guess there's no auto in case of scrollview, and the contentsize should be calculated for static views on the screen at least and for dynamic once it should be calculated on the go.
scrollView.contentSize = [scrollView sizeThatFits:scrollView.frame.size]
I believe would also work
I had the same situation, but then I wrote a new version in Swift 4 mirroring the better answer in Objective-C by Hannes Larsson:
import UIKit
extension UIScrollView {
func fitSizeOfContent() {
let sumHeight = self.subviews.map({$0.frame.size.height}).reduce(0, {x, y in x + y})
self.contentSize = CGSize(width: self.frame.width, height: sumHeight)
}
}