I have a UIView of 320 x 900 with a scrollview in it and when keyboard shows my scroll view shrinks to 320x300 ! so far so good but when i go from a text field to another the scroll view goes back to 900 by it self. anyone can tell me what is going on ?
The keyboard will hide method works just fine as well
thank you
-(void)keyboardWasShown:(NSNotification *)notification{
NSLog(#"Keyboard is shown.");
self.scrollView.frame = CGRectMake(0, 0, 320, 300);
}
-(void)keyboardWillHide:(NSNotification *)notification{
NSLog(#"Keyboard is hidden.");
self.scrollView.frame = CGRectMake(0, 0, 320, 900);
}
Related
I'm dealing with a tricky bug on my app. I have a chat view controller where I deal with keyboard showing and hiding. But the weird part is when putting the app on background.
This is the view controller before going to background (tapping the home button)
And this is the app when returning from background
If I put the app on background using the home button, the black screen only appears for a second, but if I block the phone and then unlock, the black screen keeps there.
This is how I deal with the keyboard
- (void)keyboardWillShowWithRect:(CGRect)rect
{
//We adjust inverted insets because tableview will be inverted
CGFloat displacementDistance = rect.size.height - self.composeBarView.bounds.size.height;
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, displacementDistance, 0);
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - displacementDistance, self.view.frame.size.width, self.view.frame.size.height)];
}
- (void)keyboardWillDismissWithRect:(CGRect)rect
{
//We adjust inverted insets because tableview will be inverted
CGFloat displacementDistance = rect.size.height - self.composeBarView.bounds.size.height;
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, 0, 0);
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + displacementDistance, self.view.frame.size.width, self.view.frame.size.height)];
}
The tableView used to display the messages is inverted in order to display the first message at the bottom. Here's how I do it:
- (void)setupTableView
{
self.tableView.delegate = self;
self.tableView.dataSource = self;
//We adjust inverted insets because tableview will be inverted
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, 0, 0);
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 500.0;
self.tableView.sectionFooterHeight = 30.0;
self.tableView.showsVerticalScrollIndicator = NO;
[self.tableView registerNib:[UINib nibWithNibName:#"MessagesDateHeader" bundle:nil] forHeaderFooterViewReuseIdentifier:#"MessagesDateHeader"];
// Table View is inverted so we display last messages at the bottom instead of top
self.tableView.transform = CGAffineTransformMakeRotation(-M_PI);
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapOnTableView)];
tap.numberOfTapsRequired = 1;
[self.tableView addGestureRecognizer:tap];
}
Also, I have self.definesPresentationContext = YES; set on viewDidLoad
Anyone can give me a hint of what's happening?
Thanks
I used to have a similar problem. Issue was the resizing of the tableView when keyboard appears/disappears based on its frame.
What I did was set a constraint between the bottom of the tableView and the superView and then change its constant with the appearance/disappearance of the keyboard.
Instead of relying on keyboardWillShowWithRect: and keyboardWillDismissWithRect: you can use listen to UIKeyboardWillChangeFrameNotification and handle it like follows
- (void) keyboardWillChangeFrame:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd toView:nil];
[UIView animateWithDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]
delay:0.f
options:[userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue] << 16
animations:^{
self.bottomConstraint.constant = CGRectGetHeight(self.view.frame) - keyboardFrameEnd.origin.y;
[self.view layoutIfNeeded];
} completion:nil];
}
[self.view layoutIfNeeded] is used so that view shows the whole animation
I am developing app in which my parent view is UIScrollView and child views are UIView and UIButton.
When i click on UIButton i am increasing the height of UIView programatically(this works fine)
But after when i scroll my scrollView my UIView resizes to its original height, i also tried changing height of UIView in scrollViewDidScroll method but it doesn't work :(
Please help..
Here is my code snippet:
- (IBAction)ButtonClicked:(id)sender {
[UIView animateWithDuration:0.8f delay:0.0f options:UIViewAnimationOptionTransitionNone animations: ^{
MyView.frame = CGRectMake(8, 243, 304, 400);
} completion:nil];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
MyView.frame = CGRectMake(8, 243, 304, 400);
}
Thanks in advance !!
You should connect left(top, width or height) constraints as IBOutlets and should change them.
Because view is re-layouted with auto layout constraints when you scroll scrollview.
So
myViewLeftConstraint.constant = 8
myViewTopConstraint.constant = 243
myViewWidthConstraint.constant = 304
myViewHeightConstraint.constant = 400
like this.
I used the code below to present vViewController1
#property (retain,nonatomic) ViewController1 *vViewController1;
...
push vViewController1 from rootViewController
[self.navigationController pushViewController:vViewController1 animated:NO];
Viewcontroller1's viewWillAppear
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CGRect frame = CGRectMake(0, 20, 320, 480);
self.view.frame = frame; ///aaa
NSLog(#"%f:%f:%f:%f",
frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);
}
it outputs
0.000000:20.000000:320.000000:480.000000
but the view y position is always at
0
rather than
20
it looks like it is always
CGRectMake(0, 0, 320, 480);
and
self.view.frame = frame; ///aaa
can not relocate the position of the view.
I have try to set the position using code when call pushViewController,
but there is no way to make it work correctly.
Just wonder if it is a bug for pushViewController
Your comment welcome
I think you have autolayout turned on. So you need to override viewDidLayoutSubviews method like this:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.view.frame = CGRectMake(0, 0, 320, 480);
NSLog(#"%#", NSStringFromCGRect(self.view.frame));
}
And it's better to use NSStringFromCGRect for NSLog, rather creating 4 outputs doubles.
I am experiencing animation problems.
This is my current setup so far
I have initialized my objects (UIViews) in the
- (id)initWithFrame:(CGRect)frame method
I adjust and layer the frames of views as well as added subviews in the - (void)layoutSubviews method.
When I try to animate the views/subviews, nothing happens. Everything worked well until I moved the layering to the "initWithFrame" method, it works good.
Could somebody explain what the the cause could be and why the layered views in layoutSubviews can't be animated well?
I believe that it might be due to the hierarchy of calling methods, am I right in thinking that?
Code (subclass of UIView):
- (id)initWithFrame:(CGRect)frame
{
(...)
backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
backgroundView.backgroundColor = [UIColor whiteColor];
(...)
}
- (void)layoutSubviews
{
CGRect frame = CGRectZero;
(...)
frame = (CGRect){ 100, 100, 200, 200 };
[backgroundView setFrame:frame];
(...)
[self addSubview:backgroundView];
}
- (void)animate
{
[UIView animateWithDuration:1.0f animations:^{
backgroundView.frame = CGRectMake(100, 100, 300, 300);
} completion:^{BOOL f){
NSLog(#"w: %f h: %f", backgroundView.frame.size.width, backgroundView.frame.size.height);
}];
}
Tried to call "animate" from subview (by using [(MyClass *)self.superview animate]) as well as send notification.
Always log was
w: 200 h: 200
I created the UIScrollView with content insets.
scrollView.frame = CGRectMake(-80, 180, 480, 190)
self.scrollView.contentInset = UIEdgeInsetsMake(0, 160, 0, 160);
self.scrollView.pagingEnabled = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];
// Add three Views
[self.scrollView addSubview:view1];
[self.scrollView addSubview:view2];
[self.scrollView addSubview:view3];
[view1 setFrame:CGRectMake(0, 0, 160, 190)];
[view2 setFrame:CGRectMake(160, 0, 160, 190)];
[view3 setFrame:CGRectMake(320, 0, 160, 190)];
At first time, scrollView.contentOffset.x was -160.0
But the weird problem is when I tap on scrollView(Yellow Area), content offset x value is resetting to 0 and shown like this.
I tried several times, but tapping on Scroll View resets the content offset to 0.
How can I prevent this?
UIScrollView paging works by scrolling pages with the same width of the scrollView (in your case pages of 480 width). This means that you have 1 single page (you'd still be able to scroll left and right due to the 160 content inset).
One way to make this work would be:
self.scrollView.frame = CGRectMake(80, 180, 160, 190);
self.scrollView.clipsToBounds = NO;
self.scrollView.contentInset = UIEdgeInsetsZero;
self.scrollView.pagingEnabled = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];
This will draw and scroll correctly, however, the sides of the screen will not be interactive (80 pixels on each side, since the control starts at frame.origin.x=80 and ends at 80+160=240).
Second option would be to handle paging yourself, by using methods provided by UIScrollViewDelegate.
- (void)viewDidLoad
{
[super viewDidLoad];
// pageIndex must be declared as a class member - this is used to prevent skipping pages during scroll
pageIndex = 0;
self.scrollView.frame = CGRectMake(0, 180, 320, 190);
self.scrollView.contentInset = UIEdgeInsetsMake(0, 80, 0, 80);
self.scrollView.pagingEnabled = NO;
self.scrollView.clipsToBounds = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];
self.scrollView.delegate = self;
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
int pageWidth = 160;
int pageX = pageIndex*pageWidth-scrollView.contentInset.left;
if (targetContentOffset->x<pageX) {
if (pageIndex>0) {
pageIndex--;
}
}
else if(targetContentOffset->x>pageX){
if (pageIndex<3) {
pageIndex++;
}
}
targetContentOffset->x = pageIndex*pageWidth-scrollView.contentInset.left;
NSLog(#"%d %d", pageIndex, (int)targetContentOffset->x);
}
In addition to alex's first approach with setting clipsToBounds to NO, I need to react to the scroll outside of the scroll view bounds. So I created ScrollForwarderView class which is subclass of UIView.
ScrollForwarderView.h
#import <UIKit/UIKit.h>
#interface ScrollForwarderView : UIView
#property (nonatomic, weak) UIScrollView *scrollView;
#end
ScrollForwarderView.m
...
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self pointInside:point withEvent:event]) {
return _scrollView;
}
return nil;
}
Then place UIView with custom class ScrollForwarderView above the scroll view, link scrollView property to my scroll view and it nicely forwarded the user events to scrollview.