I am new to iOS application development and I am currently working on an existing iOS application written using Objective-C. I came across a requirement where I need to implement Safe Area programmatically. So I have implemented the following piece of code in "viewDidLoad" method.
if(#available(iOS 11, *)){
UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
[self.view.leadingAnchor constraintEqualToAnchor:guide.leadingAnchor].active = YES;
[self.view.trailingAnchor constraintEqualToAnchor:guide.trailingAnchor].active = YES;
[self.view.topAnchor constraintEqualToAnchor:guide.topAnchor].active = YES;
[self.view.bottomAnchor constraintEqualToAnchor:guide.bottomAnchor].active = YES;
}else{
UILayoutGuide * margins = self.view.layoutMarginsGuide;
[self.view.leadingAnchor constraintEqualToAnchor:margins.leadingAnchor].active = YES;
[self.view.trailingAnchor constraintEqualToAnchor:margins.trailingAnchor].active = YES;
[self.view.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor].active = YES;
[self.view.bottomAnchor constraintEqualToAnchor:self.bottomLayoutGuide.topAnchor].active = YES;
}
But, when I try to run the application connecting to iPhone XR iOS Simulator device, the above code is not working. The view is not getting started after the safe area in landscape mode instead it is getting started from the safe area itself due to which the text is getting cut off
Am I missing anything? Can you please suggest on what needs to be done so that the safe area can be implemented?
What UI element are you trying to layout in your view? You mention text is getting cut off. The code you provided is setting the anchor from the view to itself and not to the UI element. Update your code to set the anchors of the UI element to the view.
UITextField *textField; // Your text UI element
UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
[textField.leadingAnchor constraintEqualToAnchor:guide.leadingAnchor].active = YES;
[textField.trailingAnchor constraintEqualToAnchor:guide.trailingAnchor].active = YES;
[textField.topAnchor constraintEqualToAnchor:guide.topAnchor].active = YES;
[textField.bottomAnchor constraintEqualToAnchor:guide.bottomAnchor].active = YES;
I'd recommend you to use
constraintEqualToSystemSpacingAfterAnchor: multiplier:
and
constraintEqualToSystemSpacingBelowAnchor: multiplier:
instead of
constraintEqualToAnchor:
Also I'd recommend you to try setting translatesAutoresizingMaskIntoConstraints to NO manually:
textField.translatesAutoresizingMaskIntoConstraints = NO;
The full code:
UITextField *textField = [[UITextField alloc] init];
textField.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:textField];
if (#available(iOS 11, *)) {
UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
[textField.leadingAnchor constraintEqualToSystemSpacingAfterAnchor:guide.leadingAnchor
multiplier:1.0].active = YES;
[textField.trailingAnchor constraintEqualToSystemSpacingAfterAnchor:guide.trailingAnchor
multiplier:-1.0].active = YES;
[textField.topAnchor constraintEqualToSystemSpacingBelowAnchor:guide.topAnchor
multiplier:1.0].active = YES;
[textField.bottomAnchor constraintEqualToSystemSpacingBelowAnchor:guide.bottomAnchor
multiplier:1.0].active = YES;
} else {
// ...
}
Related
I am creating a UI component that should display a UILabel and a UISearchBar below.
However, I am not able to align them, the UISearchBar always has extra space on both left and right side (highlighted RED).
I was trying to set the dimensions of searchBarTextField by layout anchors directly, but it didn't work.
I would prefer to do it using layout anchors when possible.
SearchBar.m:
-(id) init {
self.titleLabel = [UILabel new];
self.searchBar = self.searchController.searchBar;
UIView *searchBarWrapper = [UIView new];
[self.view addSubview:self.titleLabel];
[self.view addSubview:searchBarWrapper];
[searchBarWrapper addSubview:self.searchBar];
[self.titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[searchBarWrapper setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.searchBar setTranslatesAutoresizingMaskIntoConstraints:NO];
//[self.titleLabel.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:1.0].active = YES;
[self.titleLabel.heightAnchor constraintEqualToConstant:14.0].active = YES;
[self.titleLabel.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[self.titleLabel.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[self.titleLabel.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
//[self.titleLabel.bottomAnchor constraintEqualToAnchor:searchBarTextField.topAnchor].active = YES;
[searchBarWrapper.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:1.0].active = YES;
//[self.searchBar.heightAnchor constraintEqualToConstant:36.0].active = YES;
[searchBarWrapper.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor].active = YES;
[searchBarWrapper.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
[searchBarWrapper.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[searchBarWrapper.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
[self.searchBar.topAnchor constraintEqualToAnchor:searchBarWrapper.topAnchor].active = YES;
[self.searchBar.bottomAnchor constraintEqualToAnchor:searchBarWrapper.bottomAnchor].active = YES;
[self.searchBar.leftAnchor constraintEqualToAnchor:searchBarWrapper.leftAnchor].active = YES;
[self.searchBar.rightAnchor constraintEqualToAnchor:searchBarWrapper.rightAnchor constant:16.0].active = YES;
return self;
}
The UISearchBarTextField is embedded in a UIView to which I don't have access to.
The constraints:
The approach by #BenOng - works fine, but breaks after tapping for the first time:
UISearchBar have this property searchFieldBackgroundPositionAdjustment:UIOffset which you can set to UIOffsetMake(-8,0) to make the left side of the text field align with the left edge of the search bar.
Create a UIView right where the full search bar should be and make the search bar it's subview. Set the right edge of the search bar beyond it's super view till the right edge aligns with the superview, it should be about 16 points extra. Make sure the superview's property clipsToBoundsis set to true, the extra 16 points of search bar background will be clipped.
When you open the view, it will look like the image below,
i Phone x open view
i Phone 8 open view
For iphone x, I would like to add a safe area programmatically in the current view.
The source to try is as follows.
UIView *view = self.view;
if (#available(iOS 11.0, *)) {
UILayoutGuide * guide = view.safeAreaLayoutGuide;
[view.topAnchor constraintEqualToAnchor:guide.topAnchor].active = YES;
[view.bottomAnchor constraintEqualToAnchor:guide.bottomAnchor].active = YES;
}
I suppose to apply this source, but I do not know what to do.
please answer about my question.!
Here is sample code for Safe Area Layout. Try this in Objective-C and see:
UIView * myView = // initialize view using IBOutlet or programtically
myView.backgroundColor = [UIColor red];
myView.translatesAutoresizingMaskIntoConstraints = NO;
UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
[self.myView.leadingAnchor constraintEqualToAnchor:guide.leadingAnchor].active = YES;
[self.myView.trailingAnchor constraintEqualToAnchor:guide.trailingAnchor].active = YES;
[self.myView.topAnchor constraintEqualToAnchor:guide.topAnchor].active = YES;
[self.myView.bottomAnchor constraintEqualToAnchor:guide.bottomAnchor].active = YES;
// Refresh myView and/or main view
[self.view layoutIfNeeded];
//[self.myView layoutIfNeeded];
Ref from: Use Safe Area Layout programmatically
Result:
I loaded a pdf in a scrollview, and I would like to go directly to the next page without having the animation scrolling.
CGRect scrollViewRect = CGRectInset(viewRect, -scrollViewOutset, 0.0f);
theScrollView = [[UIScrollView alloc] initWithFrame:scrollViewRect]; // All
theScrollView.autoresizesSubviews = NO;
theScrollView.contentMode = UIViewContentModeRedraw;
theScrollView.showsHorizontalScrollIndicator = NO;
theScrollView.showsVerticalScrollIndicator = NO;
theScrollView.scrollsToTop = NO;
theScrollView.delaysContentTouches = NO;
theScrollView.pagingEnabled = YES;
theScrollView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
theScrollView.backgroundColor = [UIColor clearColor];
theScrollView.delegate = self;
[self.view addSubview:theScrollView];
Is it possible ?
You have to use below method to jump on direct offset of your next page by below method.
[objUIScrollView setContentOffset:CGPointMake(YOUR_X, YOUR_Y) animated:NO]
animated = NO;
If you are loading PDF through WebView than you need to follow below code:
webview.scrollView.contentOffset = CGPointMake(YOUR_X, YOUR_Y);
Note : Use this above code in your Next Button page or after loading
WebView properly may be in below method.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
}
Hope this will work as you expected.
Sure, simply use:
[theScrollView scrollRectToVisible:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f) animated:NO];
or
[theScrollView setContentOffset:CGPointMake(0.0f, 0.0f) animated:NO];
and change the CGPoint or CGRect to the offset of the page of your liking.
I'm using the JASidePanels. I have set my project and storyboard to show in landscape orientation only. The result shown as below. It seems like the view are read as portrait by JASidePanels. However when i turn the device into to the other side, the panel orientation will be corrected. Please advise how to fix this issue.
Thanks.
You can add the following line in viewDidAppear() :
[self _layoutSideContainers:YES duration:0];
Try replacing the -(void)_layoutSidePanels method with this:
- (void)_layoutSidePanels {
if (self.rightPanel.isViewLoaded) {
....
}
if (self.leftPanel.isViewLoaded) {
CGRect frame = self.leftPanelContainer.bounds;
frame.size.width = floorf(self.view.bounds.size.width * self.rightGapPercentage);
if (self.shouldResizeLeftPanel) {
frame.size.width = floorf(self.view.bounds.size.width * self.rightGapPercentage);
}
self.leftPanel.view.frame = CGRectMake(0, 0, self.view.bounds.size.width * self.rightGapPercentage, self.view.bounds.size.height);
}
}
Please give me a feedback, I'm not sure if this is the problem
I think i found the solution. I replace the following code in viewDidLoad() to viewDidAppear(). The problem is after the view did appear, then it will get the correct view width.
self.centerPanelContainer = [[UIView alloc] initWithFrame:self.view.bounds];
_centerPanelRestingFrame = self.centerPanelContainer.frame;
_centerPanelHidden = NO;
self.leftPanelContainer = [[UIView alloc] initWithFrame:self.view.bounds];
NSLog(#"%f",self.leftPanelContainer.frame.size.width);
self.leftPanelContainer.hidden = YES;
self.rightPanelContainer = [[UIView alloc] initWithFrame:self.view.bounds];
self.rightPanelContainer.hidden = YES;
[self _configureContainers];
[self.view addSubview:self.centerPanelContainer];
[self.view addSubview:self.leftPanelContainer];
[self.view addSubview:self.rightPanelContainer];
self.state = JASidePanelCenterVisible;
[self _swapCenter:nil previousState:0 with:_centerPanel];
[self.view bringSubviewToFront:self.centerPanelContainer];
What I need is simple: I want my UICollectionView frame to always fill the screen no matter how the device is rotated.
Right now, I am accomplishing this by using the method "willAnimateRotationToInterfaceOrientation:..." and calling a method that re-creates the collection view on rotation. However, this results in a flicker of the view on rotation as the old view is removed and the new one is added.
So I know I need to use autolayout or struts and springs and I'd like to use the latter. I know how to set struts and springs using the interface builder but the project I am working on is not using nibs or storyboards.
Here is my method for creating the collection view (it is called in viewDidLoad), including the code I have that isn't working:
- (void)sceneSetup
{
CGFloat cvWidth;
CGFloat cvHeight;
if ([self getCurrentInterfaceOrientation] || [self getCurrentDeviceOrientation]) {
self.orientationIsLandscape = YES;
cvWidth = 1024;
cvHeight = 768;
} else {
self.orientationIsLandscape = NO;
cvWidth = 768;
cvHeight = 1024;
}
EmailsLayout *layout = [[EmailsLayout alloc]init];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.emailsCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, cvWidth, cvHeight) collectionViewLayout:layout];
//here is my attempt to programmatically set struts and springs
self.view.autoresizesSubviews = YES;
self.emailsCollectionView.autoresizingMask = (UIViewAutoresizingFlexibleWidth &
UIViewAutoresizingFlexibleHeight & UIViewAutoresizingFlexibleLeftMargin &
UIViewAutoresizingFlexibleRightMargin & UIViewAutoresizingFlexibleTopMargin &
UIViewAutoresizingFlexibleBottomMargin);
self.emailsCollectionView.dataSource = self;
self.emailsCollectionView.delegate = self;
[self.emailsCollectionView setScrollEnabled:YES];
self.emailsCollectionView.userInteractionEnabled = YES;
self.emailsCollectionView.pagingEnabled = YES;
self.emailsCollectionView.backgroundColor = UIColorFromRGB(0x262d32);
[self.emailsCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellIdentifierEmails];
[self.emailsCollectionView reloadData];
[self.view addSubview:self.emailsCollectionView];
}
Not sure what I am doing wrong. Any help is appreciated.
Try using or | to combine multiple autoresisingMask values together instead of and &.