How to use the .frame property in iOS? - ios

I am calling a custom picker in my application when i hit a button.
The picker looks like a bubble so i am pointing it to the button like this :
thePicker.presentFromRect = button.frame;
I need the picker to show 300 pixels down from this button. How can i do that?
How can i add 300 pixels height on the above statement ?

You need to use :
CGRect frame = self.window.frame;
frame.size.height += 30;
thePicker.presentFromRect = frame;

You should create a new frame and edit its height property like so:
CGRect frame = button.frame;
frame.size.height += 30;
thePicker.presentFromRect = frame;

First get the frame of the button so to be able to work on it.
Then change his height as you like, accessing the size attribute.
Finally, reassign the frame to the picker
CGRect buttonFrame = button.frame;
buttonFrame.size.height += 300;
thePicker.presentFromRect = buttonFrame;

Related

Changing just 1 value in a view frame

I am somewhat new to iOS and to change the width or height of a view I am using the following code:
view.frame = CGRectMake(view.frame.origin.x,
view.frame.origin.y,
view.frame.size.width,
newHeight);
This feels wrong because I am copying all of the old values into a new rect just to change a single value, but I can't just do:
view.frame.size.height = newHeight;
Is there a better way to do this?
You can't assign the values directly. You have to create a variable for it:
CGRect frame = view.frame;
frame.size.height = newHeight;
view.frame = frame; // or [view setFrame:frame];
Another way which helps you keep the frame variable in a different scope:
view.frame = ({
CGRect frame = view.frame;
frame.size.height = newHeight;
frame;
});

Set proper gap between text.view frame and button frame

I have a text view and buttons. For some reason i got unexpected result when trying to set proper gap between those 2 elements. I think there could be incorrect calculating of text.view frame. That is how i manage to set text.view frame:
//1 Setting properties for text, starting with dictionary containing font size and family
NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:[UIFont fontWithName:#"helvetica neue"
size:14]
forKey: NSFontAttributeName];
//Creating frame to hold textView
CGSize maximumLabelSize = CGSizeMake(self.myTextView.frame.size.width, FLT_MAX);
CGSize textViewSize = [self.descriptionStringShort boundingRectWithSize:maximumLabelSize
options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin
attributes:stringAttributes context:nil].size;
//Setting frame
CGRect frame = self.myTextView.frame;
frame.size.height = textViewSize.height;
NSLog(#"%f height", frame.size.height);
self.myTextView.frame = frame;
After that, when tried to set button frames it always show different gap between those to elements (my "rough" solutions is to check height of text.view and set "minimum" and "maximum" y depend on it, but it won't work in a real world app). For example, button frame may be draw on textView.frame or much below it. There is how i set map frame:
CGRect mapButtonFrame = self.mapButton.frame;
mapButtonFrame.origin.x = 30;
if (frame.size.height < 50){
mapButtonFrame.origin.y = (200+frame.size.height + 150);
} else if (frame.size.height >300){
mapButtonFrame.origin.y = (200+frame.size.height +50);
} else {
mapButtonFrame.origin.y = (200+frame.size.height +100);
}
self.mapButton.frame = mapButtonFrame;
Still, that approach is bad, please take a look at screenshots attached:
Here, as you can see, always different gap between 2 elements. How could i make it fixed?
By the way, auto layout is turned off.
Any advice would be appreciated, thanks1
This should work just fine:
[myTextView sizeToFit];//This will change the textView frame according to the text length
CGRect bFrame = self.mapButton.frame;
bFrame.origin.y = myTextView.frame.size.height + 20.0f;// The gap you want between the text and the button
self.mapButton.frame = bFrame;

How to create TextView with increasing frame size rather than increasing the scroll size when user types

I need to create two text entry field one beneath the other. When user types in the upper text field, I need to increase the frame size dynamically (scrolling inside the textview is not recommended.) and the lower text entry frame should go downwards. Will this can be possible in ios? Any help will be appreciated.
You can update the frame of your textView via its contentSize like below:
-(void)updateTextViewSize
{
CGRect rect = textView.frame;
rect.size.width = textView.contentSize.width;
rect.size.height = textView.contentSize.height;
textView.frame = rect;
//lowering the textView2 below this textView
//assuming that the lower textview touches the
//bottom of the upper textView.
CGRect rect2 = textViewLower.frame;
rect2.origin.y = textView.frame.origin.y + textView.frame.size.height;
textViewLower.frame = rect2;
//update your scrollView here
//assuming textView and textViewLower are already added to the scrollView
scrollView.contentSize = CGSizeMake(scrollView.contentSize.width, textViewLower.frame.origin.y + textViewLower.frame.size.height);
}
//implement this delegate method as shown below
-(void)textViewDidChange:(UITextView*)textView
{
[self updateTextViewSize];
}
It is easy to do resizing of the UITextView to its correct height according to its content using the UITextView contentSize.
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

UITextView contentSize automatically decreases

I have a UITextView whose height I am trying to resize as the number of lines increases. Apart form this, I need to resize the UIView in which the UITextView is contained. I am using the following code for this:
-(void) textViewDidChange:(UITextView *)textView{
CGFloat before = textView.frame.size.height;
CGRect frame = textView.frame;
frame.size = textView.contentSize;
CGFloat after = frame.size.height, diff = after - before, final = 0;
if (diff>16) {
final = 8;
}else if(diff<-1){
final = -16;
}else{
final = 0;
}
[self.containerView setFrame: CGRectMake(self.containerView.frame.origin.x,
self.containerView.frame.origin.y-final, self.containerView.frame.size.width,
frame.size.height+13)];
[textView setFrame: frame];
}
I am also trying to change the Y-position of the container as the text is changed. I am using static number values according to font size to avoid complications.
But the problem is that whenever the UITextView enters a new line, it resizes its contentSize to the original size and so the frame of the UITextView is also reduced for a moment, which looks really ugly. Also, the Y-position depends on this contentSize change and it gets all messed up when this automatic resize happens.
I am looking for the same behaviour which apps like whatsapp or viber have. Any idea how I can achieve this?
If I understand correctly, the containerView includes a textfield and must be drawn around it, regardless of the size of the textfield? If that is, try something like this
-(void) textViewDidChange:(UITextView *)textView
{
CGRect frame = textView.frame;
frame.size = textView.contentSize;
//do your magic calculations
[textView setFrame: frame];
[self.containerView setFrame: CGRectMake(self.containerView.frame.origin.x,
self.containerView.frame.origin.y-final, self.containerView.frame.size.width, frame.size.origin.y +frame.size.height+13)];
}

UIScrollView zooms subviews when increasing subview dimensions

I have a UIScrollView that contains a view derived from UIView that uses CATiledLayer. Essentially, in my ViewController viewDidLoad:
_tiledView = [[TiledView alloc] initWithFrame:rect tileSize:_tileSize];
_scrollView = [[ScrollingView alloc] initWithFrame:rect];
_scrollView.contentSize = _tiledView.frame.size;
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_scrollView.decelerationRate = UIScrollViewDecelerationRateFast;
_scrollView.scrollEnabled = YES;
_scrollView.delegate = self;
[_scrollView addSubview:_tiledView];
Initially, _tiledView is a 4x4 grid of 256x256 tiles. I'm trying increase the dimensions of _tiledView at runtime. When constructing _tiledView, I simply compute the size of the view by multiplying the number of tiles by its size. Then I set the size of _tiledView.frame and _tiledView.bounds, e.g.:
CGRect frame = self.frame;
frame.origin = CGPointZero;
frame.size = CGSizeMake(tileSize.width*4, tileSize.height*4);
self.frame = frame;
self.bounds = frame;
Now, when I hit a button in the interface, all I want to accomplish as a first step is increasing the dimensions of _tiledView by one 256x256 tile to both right and bottom. This is what I attempted:
- (void)addTiles:(id)sender
{
CGRect rect = _tiledView.frame;
rect.size.width += _tileSize.width;
rect.size.height += _tileSize.height;
_tiledView.frame = rect;
_tiledView.bounds = rect;
CGSize size = _scrollView.contentSize;
size.width += _tileSize.width;
size.height += _tileSize.height;
_scrollView.contentSize = size;
[_scrollView setNeedsLayout];
}
However, this doesn't work as expected. What happens is that _tiledView gets bigger as if it had been zoomed in - same number of tiles as the beginning though, i.e. 4x4. I checked the _scrollView.contentsScaleFactor property and it says 1.0. I assume _scrollView did not technically zoom the contents in.
I was expecting _tileView to stay put in its current place in the interface but add 9 new tiles, i.e. 4 to the right, 4 at the bottom and 1 at the bottom-right corner. Instead, the initial 16 tiles got bigger to fill in the space that could have been filled by 25 tiles.
What am I missing? What am I doing wrong? Any help would be appreciated.
In case anyone finds it useful. After digging further, I realized that I the contentMode defaults to ScaleToFill. So I set it to:
_tiledView.contentMode = UIViewContentModeRedraw;
upon initialization. And adjusted addTiles like this:
CGRect rect = _tiledView.frame;
rect.size.width += _tileSize.width;
rect.size.height += _tileSize.height;
_tiledView.frame = rect;
_tiledView.bounds = rect;
_scrollView.contentSize = rect.size;
[_tiledView setNeedsDisplay];
And, that had the effect I was looking for.

Resources