I'm having scrollView contains one UIImageView on Top and UITextView with scrollingEnabled = NO , I want to scroll scrollView at the position where I type.
- (void)createScrollView{
//TPKeyboardAvoidingScrollView *scrollView = [[TPKeyboardAvoidingScrollView alloc]init];
UIScrollView *scrollView = [[UIScrollView alloc]init];
//[self.view insertSubview:scrollView belowSubview:_mediaSelectionView];
[self.view addSubview: scrollView];
[scrollView setTranslatesAutoresizingMaskIntoConstraints: NO];
self.scrollView = scrollView;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.bouncesZoom = NO;
scrollView.alwaysBounceVertical = YES;
scrollView.clipsToBounds = YES;
self.automaticallyAdjustsScrollViewInsets = YES;
NSLayoutConstraint *scrollViewTop = [NSLayoutConstraint
constraintWithItem: scrollView
attribute: NSLayoutAttributeTop
relatedBy: NSLayoutRelationEqual
toItem: self.navigationBarBGView
attribute: NSLayoutAttributeBottom
multiplier: 1 constant:0.0
];
NSLayoutConstraint *scrollViewLeading = [NSLayoutConstraint
constraintWithItem: scrollView
attribute: NSLayoutAttributeLeading
relatedBy: NSLayoutRelationEqual
toItem: self.view
attribute: NSLayoutAttributeLeading
multiplier: 1 constant:0.0
];
NSLayoutConstraint *superViewTraling = [NSLayoutConstraint
constraintWithItem: self.view
attribute: NSLayoutAttributeTrailing
relatedBy: NSLayoutRelationEqual
toItem: scrollView
attribute: NSLayoutAttributeTrailing
multiplier: 1 constant:0.0
];
NSLayoutConstraint *bottomLayoutGuideTop = [NSLayoutConstraint
constraintWithItem:self.view
attribute: NSLayoutAttributeBottom
relatedBy: NSLayoutRelationEqual
toItem: scrollView
attribute: NSLayoutAttributeBottom
multiplier: 1 constant:0.0
];
//Add All Constrains.
[self.view addConstraints: #[scrollViewTop , scrollViewLeading , superViewTraling , bottomLayoutGuideTop ]];
_contentView = [[UIView alloc]init];
[scrollView addSubview: _contentView];
[_contentView setConstraintFlag];
[_contentView setFullWidth];
[_contentView setTopFromParent:0];
}
- (void)createCommentTextView{
UITextView *textView = [[UITextView alloc]init];
textView.backgroundColor = [UIColor clearColor];
textView.textColor = [UIColor colorWithR:67 G:83 B:83 A:1.0f];
textView.delegate = self;
textView.scrollEnabled = NO;
_commentTextView = textView;
[_textViewContainer addSubview:textView];
}
-(void)updateContentSize{
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, self.contentView.frame.size.height);
}
scrollView contains _contentView and contentView contains UITextView. textView height increases as user types and _contentView's bottom is equal to bottom of textView.
use:
pod 'TPKeyboardAvoiding' or
https://github.com/michaeltyson/TPKeyboardAvoiding
pod 'AnimatedTextInput'
https://github.com/jobandtalent/AnimatedTextInput
I have gone through several posts and blogs, but I didn't get exact answer I want. After that, I came up with some sort of soln with the help of other posts and blogs. Hope this will help.
- (void)scrollToCursor{
if(self.currentTextView.selectedRange.location != NSNotFound) {
NSRange range = self.currentTextView.selectedRange;
NSString *string = [<YOUR_TEXTVIEW>.text substringToIndex:range.location];
CGSize size = [string boundingRectWithSize:<YOUR_TEXTVIEW>.frame.size
options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingUsesFontLeading
attributes:#{NSFontAttributeName:<YOUR_TEXTVIEW>.font}
context:nil].size;
NSInteger yPosition = (<YOUR_TEXTVIEW>.frame.origin.y+size.height+<OFFSET(if required)>);
NSInteger scrollViewVisibeYPositionStart = self.scrollView.contentOffset.y;
NSInteger scrollViewVisibeYPositionEnd = scrollViewVisibeYPositionStart+self.scrollView.frame.size.height;
BOOL needToSetOffset = NO;
if (yPosition > scrollViewVisibeYPositionEnd) {
yPosition = yPosition - self.scrollView.frame.size.height;
needToSetOffset = YES;
}else if (yPosition < scrollViewVisibeYPositionStart){
yPosition = self.scrollView.frame.size.height + (scrollViewVisibeYPositionStart - yPosition);
needToSetOffset = YES;
}
if (needToSetOffset) {
CGPoint offset = CGPointMake(0,yPosition);
[self.scrollView setContentOffset:offset];
}
}
}
Related
I want to update center anchor of a UILabel on a Button Click but it not Updating although when I set ist 1st Time in viewDidload It's working but on click not updating its centerX point.
Here is My Sample Code:
MyCustomView.h
#import <UIKit/UIKit.h>
#interface MyCustomView : UIView
#property (nonatomic,strong)UILabel *MyLbl;
#property (nonatomic,strong)NSLayoutConstraint * MyLblConstraint;
- (id)initWithFrame:(CGRect)frame;
#end
MyCustomView.m
#import "MyCustomView.h"
#implementation MyCustomView
#synthesize MyLbl;
- (id)initWithFrame:(CGRect)frame;
{
self = [super initWithFrame:frame];
if (self) {
self.translatesAutoresizingMaskIntoConstraints = NO;
self.backgroundColor = [UIColor whiteColor];
NSString *LblTxtStr = #"This is My Label Text";
CGSize LblTxtStrSize = [LblTxtStr sizeWithAttributes: #{NSFontAttributeName:[UIFont fontWithName: #"Helvetica-Bold" size: 18]}];
CGSize LblFrameSize = CGSizeMake(ceilf(LblTxtStrSize.width), ceilf(LblTxtStrSize.height));
self.MyLbl = [UIView new];
self.MyLbl.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview: self.MyLbl];
[self.MyLbl.widthAnchor constraintEqualToConstant: LblFrameSize.width].active = YES;
[self.MyLbl.bottomAnchor constraintEqualToAnchor: self.bottomAnchor].active = YES;
[self.MyLbl.heightAnchor constraintEqualToConstant: self.LblFrameSize.height].active = YES;
self.MyLblConstraint = [NSLayoutConstraint constraintWithItem:self.MyLbl attribute: NSLayoutAttributeCenterX relatedBy: NSLayoutRelationEqual toItem: self attribute: NSLayoutAttributeCenterX multiplier: 0.5 constant: 0];
self.MyLblConstraint.active = YES;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.translatesAutoresizingMaskIntoConstraints = NO;
[btn setTitle:#"test 1" forState: UIControlStateNormal];
[btn addTarget: self action:#selector(MyBtnClick:) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview: btn];
[self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[btn]|" options: 0 metrics: nil views: #{#"btn": btn}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[MyLbl]-100-[btn(50)]" options:0 metrics:nil views: #{#"MyLbl": self.MyLbl ,#"btn": btn}]];
}
return self;
}
-(void)MyBtnClick:(id)sender {
NSLog(#"My Button Click");
self.MyLblConstraint = [self.MyLbl.centerXAnchor constraintEqualToAnchor: self.centerXAnchor];
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping: 1 initialSpringVelocity: 1 options:UIViewAnimationOptionCurveEaseOut animations:^{[self layoutIfNeeded];} completion: nil];
}
#end
Now in My ViewController's viewDidload method is as follows:
ViewController.m
#import "ViewController.h"
#import "MyCustomView.h"
#interface INVRShareController (){
MyCustomView *MyView;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
MyView = [MyCustomView new];
MyView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview: MyView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[MyView]|" options:0 metrics:nil views: #{#"MyView" : MyView}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[MyView(600)]" options:0 metrics:nil views: #{#"MyView" : MyView}]];
}
After creating the constraint, you have to activate it.
self.MyLblConstraint = [self.MyLbl.centerXAnchor constraintEqualToAnchor: self.centerXAnchor].active = true;
*Edit
The issue is that you have 2 constraints that are conflicting.
The solution is to create both constraints in viewDidLoad. Then make only one constraint 'active' at a time.
In viewDidLoad,
constraint1 = [NSLayoutConstraint constraintWithItem:self.MyLbl attribute: NSLayoutAttributeCenterX relatedBy: NSLayoutRelationEqual toItem: self attribute: NSLayoutAttributeCenterX multiplier: 0.5 constant: 0];
constraint1.active = true
constraint2 = [self.MyLbl.centerXAnchor constraintEqualToAnchor: self.centerXAnchor];
In the button action,
constraint1.active = false
constraint2.active = true
Change btn click to this
-(void)MyBtnClick:(id)sender {
[self removeConstraint:self.MyLblConstraint];
self.MyLblConstraint = [self.MyLbl.centerXAnchor constraintEqualToAnchor: self.centerXAnchor];
self.MyLblConstraint.active = YES;
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping: 1 initialSpringVelocity: 1 options:UIViewAnimationOptionCurveEaseOut animations:^{[self layoutIfNeeded];} completion: nil];
}
I've noticed that iOS 11 has made some change to the UIBarButtonItem. After solving the sizing problem of the image of UIBarButtonItem, I find myself facing another even more strange issue.
We have a UIToolBar with several UIBarButtonItems and we used to set the width of the UIBarButtonItem as 40 and the width of the UIButton.image as 24, which leaves a nice spacing between every two UIBarButtonItems. However, in iOS 11, the space disappear.
I tried with
[self.deleteButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(40, 24));
}];
NSLayoutConstraint *w = [self.deleteButton.imageView.widthAnchor constraintEqualToConstant:24];
NSLayoutConstraint *h = [self.deleteButton.imageView.widthAnchor constraintEqualToConstant:24];
w.active = YES;
h.active = YES;
but it doesn't work as I thought.
I either get a list of stretched images with CGSize(40, 24) or a list of UIBarButtonItem with CGSize(24, 24) lining up in the UINavigationBar one by one without spacing.
Are there anything other constraints I need to add to create the spacing?
Try this:
UIButton*(^buttonWith)(NSString *) = ^(NSString *imageName) {
CGFloat size = 40.0;
UIButton *button = [[UIButton alloc] initWithFrame: CGRectMake(0.0, 0.0, size, size)];
[button setImage: [[UIImage imageNamed: imageName] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] forState: UIControlStateNormal];
[button addConstraint: [NSLayoutConstraint constraintWithItem: button attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: size]];
[button addConstraint: [NSLayoutConstraint constraintWithItem: button attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: size]];
return button;
};
Usage:
UIButton *resetButton = buttonWith(#"reset");
self.resetBarButton = [[UIBarButtonItem alloc] initWithCustomView: resetButton];
UIButton *backButton = buttonWith(#"back");
self.backBarButton = [[UIBarButtonItem alloc] initWithCustomView: backButton];
self.navigationItem.leftBarButtonItems = #[self.backBarButton, self.resetBarButton];
In storyboard you can place another UIBarButtonItem in between the buttons that need spacing. set the text to spaces only. see screen shots.
I would like to setup a series of UILabels that have their X-centers aligned along a 45degree angel.
I imagine I can do this mathematically, but is there a way I can draw a 45degree line and then assign each UILabel to be positioned at different points along that 45degree line?
You could set up a constraint for your label's center-x, center-y to be a percentage of the containing view's width / height. Here's a quick example in the context of a generic view controller:
for ( CGFloat m = 0.25 ; m < 1 ; m += .25 ) {
UILabel* label = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, 100, 40)];
label.text = #"Hello, World";
label.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview: label];
NSLayoutConstraint* lcx = [NSLayoutConstraint constraintWithItem: label
attribute: NSLayoutAttributeCenterX
relatedBy: NSLayoutRelationEqual
toItem: self.view
attribute: NSLayoutAttributeRight
multiplier: m
constant: 0];
NSLayoutConstraint* lcy = [NSLayoutConstraint constraintWithItem: label
attribute: NSLayoutAttributeCenterY
relatedBy: NSLayoutRelationEqual
toItem: self.view
attribute: NSLayoutAttributeBottom
multiplier: m
constant: 0];
[self.view addConstraint: lcx];
[self.view addConstraint: lcy];
}
I have a constraint based super view which looks like
CGFloat _expandedHeight = 500;
NSLayoutConstraint *_heightConstraint =
[NSLayoutConstraint constraintWithItem: superView
attribute: NSLayoutAttributeHeight
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 0.0
constant: _expandedHeight];
[superView addConstraint: _heightConstraint];
it's size and origin are not determined(Actually, it's the system input view in custom keyboard extension).
Is there any possibility can I add a frame based subview such as
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
to that constraint based super view?
I tried to directly add subView to the superView but got a unable to simultaneously satisfy constraints exception. Then I add
subView.translatesAutoresizingMaskIntoConstraints = NO;
but it still doesn't work.
I have a custom UITableViewCell with a subview that resizes using Auto Layout. This subview is a toolbar at the bottom of the cell. It has a height of zero when the cell is unselected and grows to 30 in the selected state. The cell toggles between 100 and 130.
Here is the init:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
_toolbarView = [[FOToolbarView alloc] init];
_toolbarView.translatesAutoresizingMaskIntoConstraints = NO;
_toolbarView.backgroundColor = [UIColor blueColor];
[self.contentView addSubview: _toolbarView];
[self setNeedsUpdateConstraints];
}
return self;
}
And here are the constraints
- (void)updateConstraints
{
[self.contentView addConstraint: [NSLayoutConstraint constraintWithItem: _toolbarView
attribute: NSLayoutAttributeWidth
relatedBy: NSLayoutRelationEqual
toItem: self.contentView
attribute: NSLayoutAttributeWidth
multiplier: 1.0
constant: 0]];
[self.contentView addConstraint: [NSLayoutConstraint constraintWithItem: _toolbarView
attribute: NSLayoutAttributeLeft
relatedBy: NSLayoutRelationEqual
toItem: self.contentView
attribute: NSLayoutAttributeLeft
multiplier: 1.0
constant: 0]];
[self.contentView addConstraint: [NSLayoutConstraint constraintWithItem: _toolbarView
attribute: NSLayoutAttributeTop
relatedBy: NSLayoutRelationEqual
toItem: self.contentView
attribute: NSLayoutAttributeTop
multiplier: 0.0
constant: 100.0]];
[self.contentView addConstraint: [NSLayoutConstraint constraintWithItem: _toolbarView
attribute: NSLayoutAttributeBottom
relatedBy: NSLayoutRelationEqual
toItem: self.contentView
attribute: NSLayoutAttributeBottom
multiplier: 1.0
constant: 0]];
[super updateConstraints];
}
The layout works as intended, but I am getting the following error:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x1f810f50 FOToolbarView:0x1f812900.top == + 70>",
"<NSLayoutConstraint:0x1f810dc0 FOToolbarView:0x1f812900.bottom == UITableViewCellContentView:0x1f8286d0.bottom>",
"<NSAutoresizingMaskLayoutConstraint:0x1f821230 h=--& v=--& V: [UITableViewCellContentView:0x1f8286d0(69)]>"
)
I've tried many things, without success. How can I get rid of this error?
Problem seems to be that autoresizingmask constraints from tableviewcell.contentview is being automatically added by the system. Try this:
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;