I have ViewController with UITextField(top view) and UITextView(bottom view). I want move UITextView to the top of the view, when user start editing it.
When user start editing from UITextView everything is fine, but when user first want to edit UITextField and then UITextView (without hidding keyboard) its not working. UITextField is hidden, but UITextView don't change his frame.
I tried to use UIKeyboardDidShowNotification but its called only when keyboard pops up.
Code to reproduce problem:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextViewDelegate>
#property (weak, nonatomic) IBOutlet UITextField *titleTF;
#property (weak, nonatomic) IBOutlet UITextView *bodyTV;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(void)textViewDidBeginEditing:(UITextView *)textView {
self.titleTF.hidden=YES;
CGRect newFrame=CGRectMake(20, 20, textView.frame.size.width, 100);
textView.frame=newFrame;
}
#end
Run app and click on UITextView, app will look like:
http://imageshack.us/photo/my-images/694/32568213.png
For now everything is fine (UITextField is hidden and UITextView is moved and resized).
Start app again. First click on UITextField and then click on UITextView. App look like this:
http://imageshack.us/photo/my-images/843/66433184.png
UITextField is hidden, but UITextView did not change his frame.
Move the view up, when the TextView editing begins,
Move it down when editing ends.
Just put these two methods,
-(void) textViewDidBeginEditing:(UITextView *)textView{
CGRect frame = self.view.frame;
frame.origin.y = -(textView.frame.origin.y + textView.frame.size.height);
[UIView animateWithDuration:0.3f animations:^{
self.view.frame = frame;
}];
}
-(void) textViewDidEndEditing:(UITextView *)textView{
CGRect frame = self.view.frame;
frame.origin.y = 0;
[UIView animateWithDuration:0.3f animations:^{
self.view.frame = frame;
}];
}
Related
I have a custom UIView XIB that gets loaded onto my ViewController and the frame is adjusted to be collapsed before added to subview. The UIButton tied to my XIB is showing when the frame is smaller than the button location. How can I hide and show my UIButton as the frame is expanding/collapsing? My XIB is not using AutoLayout.
ViewController.m
self.greenView = [[[NSBundle mainBundle] loadNibNamed:#"Green" owner:self options:nil] objectAtIndex:0];
[self.navigationController.view addSubview:self.greenView];
GreenView.h
#interface GreenView : UIView
#property (weak, nonatomic) IBOutlet UIView *expandView;
#property (nonatomic, getter = isExpanded) BOOL expand;
#property (weak, nonatomic) IBOutlet UIButton *testButton;
- (IBAction)testButtonTapped:(id)sender;
#end
GreenView.m
#interface GreenView()
#property (nonatomic) UITapGestureRecognizer *tapGesture;
#end
#implementation GreenView
- (void)awakeFromNib {
CGRect frame = self.frame;
frame.size.height = self.expandView.frame.size.height;
frame.origin.y = 200;
self.frame = frame;
self.expand = NO;
[self.expandView addGestureRecognizer:self.tapGesture];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (UITapGestureRecognizer *)tapGesture {
if (!_tapGesture) {
_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapClicked:)];
}
return _tapGesture;
}
- (void)tapClicked:(UIGestureRecognizer *)recognizer {
CGRect frame = self.frame;
self.expand = !self.expand;
frame.size.height = self.expand ? gvExpandedHeight : gvCollapsedHeight;
[UIView animateWithDuration:0.5 animations:^{
self.frame = frame;
} completion:^(BOOL finished) {
NSLog(#"Frame after animation: %#", NSStringFromCGRect(self.frame));
}];
}
- (IBAction)testButtonTapped:(id)sender {
NSLog(#"Test button tapped");
}
#end
Collapsed:
Expanded:
GreenView.xib:
GrenenView.xib Struts and Springs:
If I understood you just want to clip it, if the button is outside to the view bounds. In -awakeFromNib add:
self.clipsToBounds = YES;
Using this property you are telling the view to cut everything that is not inside its bounds, views caw draw subviews even if they are place outside. Is a little expensive by means of performance, if you use it a lot or during heavy animations.
One way around could be hide it while the view is collapsed.
You change the frame to frame.origin.y = 200;
I think you have to set the UIButton constraint relative to your GreenView in you nib file
I am a newbie to IOS programming and currently i have a image application with swipe images on uiview. I have questions.
i want to swipe image to right when click on right button and swipe image to left when click left button in iphone.
i am using this code:-
.h file
#import<UIKit/UIKit.h>
#interface flashViewcontroller : UIViewController<UIScrollViewDelegate>
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
#property (nonatomic, strong) IBOutlet UIPageControl *pageControl;
#property (nonatomic, strong) NSArray *pageImages;
#property (nonatomic, strong) NSMutableArray *pageViews;
#property(nonatomic,strong) IBOutlet UIButton *next;
#property(nonatomic,strong) IBOutlet UIButton *previous;
-(void)loadVisiblePages;
-(void)loadPage:(NSInteger)page;
-(void)purgePage:(NSInteger)page;
-(IBAction)next:(id)sender;
-(IBAction)previos:(id)sender;
-(IBAction)skipes:(id)sender;
#end
// Left Button Click
-(IBAction)click_LeftBtn:(id)sender{
[imgView setFrame:CGRectMake(imgView.frame.orign.x, imgView.frame.orign.y, imgView.frame.size.width, imgView.frame.size.height)];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.5]; //// Set Animationt time Duration
[imgView setFrame:CGRectMake(0, imgView.frame.orign.y, imgView.frame.size.width, imgView.frame.size.height)];
[UIView commitAnimations];
}
// Right Button Click
-(IBAction)click_RightBtn:(id)sender
{
[imgView setFrame:CGRectMake(imgView.frame.orign.x, imgView.frame.orign.y, imgView.frame.size.width, imgView.frame.size.height)];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.5]; //// Set Animationt time Duration
[imgView setFrame:CGRectMake(320-imgView.frame.size.width, imgView.frame.orign.y, imgView.frame.size.width, imgView.frame.size.height)];
[UIView commitAnimations];
}
So I am trying to move a UIButton after it is clicked.
The _addMoreFields method is called after the button is clicked.
_addMoreFieldBtn is a global UIButton. When I click it nothing happens.
The strange part is if I comment out the addSubView code then the button moves.
If I keep that code the button doesn't move.
Any Ideas?
-(void)movePlusButton {
NSLog(#"Moving button");
[UIButton beginAnimations:nil context:nil];
[UIButton setAnimationDuration:0.3];
_addMoreFieldsBtn.center = CGPointMake(30,30);
[UIButton commitAnimations];
}
- (IBAction)addMoreFields:(id)sender {
CGRect currentBtnFrame = [(UIButton *)sender frame];
CGPoint org = currentBtnFrame.origin;
UILabel *whoWasIn = [[UILabel alloc] initWithFrame:CGRectMake(110, org.y, 85, 21)];
whoWasIn.text = #"test";
UITextField *whoWasInField = [[UITextField alloc] initWithFrame:CGRectMake(59, whoWasIn.frame.origin.y+40, 202, 30)];
whoWasInField.placeholder = #"test2";
UILabel *with = [[UILabel alloc] initWithFrame:CGRectMake(136, whoWasInField.frame.origin.y+40, 49, 21)];
with.text = #"with";
whoWasInField.borderStyle = UITextBorderStyleRoundedRect;
UITextField *withField = [[UITextField alloc] initWithFrame:CGRectMake(59, with.frame.origin.y+40, 202, 30)];
withField.placeholder = #"test3";
withField.borderStyle = UITextBorderStyleRoundedRect;
[_homeView addSubview:whoWasIn];
[_homeView addSubview:with];
[_homeView addSubview:whoWasInField];
[_homeView addSubview:withField];
[self movePlusButton];
}
NOTE: I also tried changing the frame but I get the same issue. It starts animating from the new location I put to the existing spot.
The issue is that new projects in iOS 6 / Xcode 4.5 have "Autolayout" enabled by default. Autolayout is a replacement for "Springs and Struts" (but it only works iOS 6). This feature adds constraints to a view which take precedence over the move you were attempting in your code.
So there are three possible fixes to this:
1) Create new constraints on the button programmatically. Autolayout is pretty powerful and flexible... especially if you are trying to support the footprint of both the iPhone 5 and earlier models. You can find more info on how to do this by checking out the WWDC video: Introduction to Auto Layout for iOS and OS X
2) Don't use Autolayout. Select a view in your Storyboard, and in the File Inspector, uncheck "Use Autolayout."
3) Create IBOutlets for each of the constraints on the button. Then before you move the button, remove those constraints:
#interface MyViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *addMoreFieldsBtn;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *hConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *vConstraint;
- (IBAction)addMoreFields:(id)sender;
#end
and...
-(void)movePlusButton {
NSLog(#"Moving button");
[self.view removeConstraint:self.hConstraint];
[self.view removeConstraint:self.vConstraint];
[UIButton beginAnimations:nil context:nil];
[UIButton setAnimationDuration:0.3];
_addMoreFieldsBtn.center = CGPointMake(30,30);
[UIButton commitAnimations];
}
(the actual view you need to call removeConstraints: on is the parent view of the button, which may or may not be self.view).
Actually, I think that whats happening is that your subview is coming onto to screen first, and therefore taking precedence, and then once the subview is removed, the button would move, if you change the code:
[_homeView addSubview:whoWasIn];
[_homeView addSubview:with];
[_homeView addSubview:whoWasInField];
[_homeView addSubview:withField];
[self movePlusButton];
}// move the [self movePlusButton]; up 6 lines of code, or make it first line
[self movePlusButton];
[_homeView addSubview:whoWasIn];
[_homeView addSubview:with];
[_homeView addSubview:whoWasInField];
[_homeView addSubview:withField];
This should solve all of your problems
:)
I can't seem to get scrollViewDidEndDecelerating called.
I have a scrollView with 2 Views inside. Now I need it to set a value to a label in the first view when the scrollview is finished scrolling to the second view.
Header File:
#interface ViewController: UIViewController
{
UIScrollView *scrollView;
UIView *view1;
UIView *view2;
}
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (strong, nonatomic) IBOutlet UIView *view1;
#property (strong, nonatomic) IBOutlet UIView *view2;
#property (weak, nonatomic) IBOutlet UILabel *lbl;
Implementation File:
#synthesize scrollView, view1, view2;
-(void)viewDidLoad
{
self.view1=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.view2=[[UIView alloc] initWithFrame:CGRectMake(320, 0, 320, 480)];
[self.scrollView addSubView:self.view1];
[self.scrollView addSubView:self.view2];
self.scrollView.bounces=NO;
self.scrollView.contentSize=CGSizeMake(640,460);
[self.scrollView setShowHorizontalScrollIndicator:NO];
[self.scrollView scrollRectToVisible:CGRectMake(0, 0, 320, 416) animated:NO];
}
-(void)scrollViewDidEndDecelerating:(UIView *)scrollView
{
lbl.text=#"0";
}
I don't see anything wrong, it should be working. Can someone help me out? Would appreciate it.
scrollViewDidEndDecelerating is not called if the user is scrolling slowly (i.e. the scroll view does not continue to scroll on touch up). In that case the delegate calls scrollViewDidEndDragging. So to do something when the user has stopped scrolling and the scrollview has stopped you can combine them:
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
endOfScroll()
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
endOfScroll()
}
func endOfScroll() {
//The user finished scrolling
}
In Objective-C
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if(!decelerate) [self endOfScroll];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[self endOfScroll];
}
-(void)endOfScroll{
//Do something
}
Either connect the delegate property of the scrollview to the File's Owner object in Interface Builder or just set the delegate manually in your ViewController's ViewDidLoad.
scrollview.delegate = self
This would do:
Header File:
#interface ViewController: UIViewController <UIScrollViewDelegate> //promise that you'll act as scrollView's delegate
{
UIScrollView *scrollView;
UIView *view1;
UIView *view2;
}
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (strong, nonatomic) IBOutlet UIView *view1;
#property (strong, nonatomic) IBOutlet UIView *view2;
#property (weak, nonatomic) IBOutlet UILabel *lbl;
Implementation File:
#synthesize scrollView, view1, view2;
-(void)viewDidLoad
{
self.view1=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.view2=[[UIView alloc] initWithFrame:CGRectMake(320, 0, 320, 480)];
[self.scrollView addSubView:self.view1];
[self.scrollView addSubView:self.view2];
self.scrollView.bounces=NO;
self.scrollView.contentSize=CGSizeMake(640,460);
[self.scrollView setShowHorizontalScrollIndicator:NO];
[self.scrollView scrollRectToVisible:CGRectMake(0, 0, 320, 416) animated:NO];
[self.scrollView setDelegate:self];//Set delegate
}
-(void)scrollViewDidEndDecelerating:(UIView *)scrollView
{
lbl.text=#"0";
}
Swift 5
When scrolling UIScrollView programmatically, the scrollViewDidEndDecelerating is not called , but you can still use the scrollViewDidEndScrollingAnimation delegate function as a substitude for that, however there are some limitations stated in Apple documentation :
The scroll view calls this method at the end of its implementations of the setContentOffset(:animated:) and scrollRectToVisible(:animated:) methods, but only if animations are requested.
Therefore if you are not using default animated:true, but rather animating scrolling with custom UIView.animate animation (for example to change scrolling speed) , the only delegate method that still executes is scrollViewDidScroll
UIScrollView *scrl = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 768,1024)];
scrl.contentSize = CGSizeMake(768 * 8, 1024);
Here is the definition of my UIScrollView, I have a fill the scroll with 8 images each image is a 768*1024, how can I make UIScrollView slide show, each image stay 2 seconds and slides to the next image, how can I do that ?
You could use an UIImageView instead of a UIScrollView.
In your .h file:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
int imageId;
UIImageView *imageView;
}
#property(nonatomic, retain) IBOutlet UIImageView * imageView;
#end
In your .m file:
#implementation ViewController
#import <QuartzCore/CAAnimation.h>
#define NUMBER_OF_IMAGES 8;
#synthesize imageView;
- (void)viewDidLoad
{
[super viewDidLoad];
imageId = 0;
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(changeImage) userInfo:nil repeats:YES];
}
-(void)changeImage
{
imageId = imageId + 1;
CATransition * trs = [CATransition animation];
trs.duration = 1;
[trs setType:kCATransitionPush];
int id = imageId % NUMBER_OF_IMAGES;
imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"image_%d.jpg", id]];
[imageView.layer addAnimation:trs forKey:kCATransition];
}
#end
You will need to add the QuartzCore.framework to your project.
I will not give you any code (that's YOUR job)...
Here is how to do such a thing:
Have a parent UIScrollView that handles paging - must implement the delegate method of scrollViewDidScroll:
Have a UIPageControl (used for keeping track of what page you are on, code-wise or UI wise)
IMPORTANT for zooming:
1. Create a subclass of UIScrollView and add a UIImageView to it as a subview.
2. Allow scrolling and no paging.
3. Make this subclass have implement the delegate method of viewForZoomingInScrollView: (return the UIImageView)