Swift 4 + Xcode 9.
I have been working on this problem for weeks, trying to solve it myself. I would appreciate any help that anyone could provide. I'm not posting any code in my initial question because it's proprietary. I will be happy to provide pieces of it if it's required to help solve my problem.
I have a UITableView with a custom cell, which contains a very complex layout of subviews, some of which are hidden or shown (using 1000-priority height=0 constraints which are added and removed during cellForRowAt) depending on the data. There is also an ImageView which should always be full width, and should change height to match the image, which is loaded via Kingfisher.shared.retrieveImage(). Once I have the image, I update the aspectRatio constraint on the image for that cell, and the cells display. This works perfectly for the first 15-20 cells, but as I scroll through more rows, it simply stops functioning. The images are small and centered, certain data fields are not updated, etc. If I keep scrolling, sometimes a cell will behave correctly here and there, but nearly all do not.
Now for the interesting part: If I scroll BACK UP, every single cell reformats itself automatically to look as it should, and after that, every cell is perfect. The code obviously works - and I feel like this may be a bug in the platform, but before I assume that, I wanted to see if anyone else had run into something like this.
Again, thank you very much for any help you can provide - I'm very anxious to solve this.
UPDATE: To answer a couple of the questions, here is a snippet of code that is part of the custom cell class. This is how I set the cell's image (which includes updating the aspect ratio constraint), and how I reset the cell for re-use.
internal var aspectConstraint : NSLayoutConstraint? {
didSet {
if oldValue != nil {
imageView.removeConstraint(oldValue!)
}
if aspectConstraint != nil {
imageView.addConstraint(aspectConstraint!)
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
aspectConstraint = nil
imageView.image = nil
for view in subviews {
for c in view.constraints {
if c.firstAttribute == NSLayoutAttribute.height && c.constant == 0 {
view.removeConstraint(c)
}
}
}
}
func setCustomImage(image : UIImage) {
let aspect = image.size.width / image.size.height
let constraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: imageView, attribute: NSLayoutAttribute.height, multiplier: aspect, constant: 0.0)
constraint.priority = UILayoutPriority(999)
aspectConstraint = constraint
imageView.image = image
}
For anyone who comes to this question, due to complete lack of resolution on this issue, I have concluded that UIKit is unsuitable for my purposes. I went with Texture (formerly AsyncDisplayKit), and my progress has resumed.
Related
I currently trying to learn iOS development, however I’ve got stuck in interface builder. What I am trying to do is actually quite basic view. Unfortunately I feel pretty confused about „Less Than or Equal” relations. I thought that if a constraint is set as less than or equal, it will mean that it will have max size stetted in constant when there will be a plenty of space, otherwise it will be smaller. Turns out that no matter what, it always have the biggest size, which is not what I am trying to achieve.
On iPhone 11 interface looks like this:
On iPhone 8 interface looks like this:
For sure I don’t have all necessary knowledge about auto constraints right now, but maybe someone know where is a problem in this case? Also I would appreciate any good tutorials about interface builder or some good habits.
Thanks
Peter
So, this seems to be the sort of thing you're after. Here it is on a 6s:
And here it is on an iPhone 11:
And here it is, for good measure, on the iPhone 6s rotated:
As you can see, there are four "groups" - the two labels, the label-and-text-field, the second label-and-text-field, and the button. They are evenly distributed from top to bottom on both screens.
That's the right idea, isn't it?
So how is that done? Simple. One vertical stack view filling the screen, with distribution set to Equal Spacing. Inside that, a UIView containing each group (except the button which is on its own), and each UIView given a fixed height by its own height constraint. There's a little more to it but that's the heart of the matter. Once you have that, you can tweak further as desired, of course.
Absolutely no code; the whole thing was configured in a few moments in Xcode's nib editor ("interface builder").
It sounds like you are trying to create spacing between inputs based on the size of the device? I don't know if it will look like you expect, but I've had to do this before in different situations. You can use something like this NSLayoutConstraint subclass to accommodate to accomplish what you want. Essentially, depending on whether the constraint is vertical or horizontal, this class will calculate the screen size at runtime and modify the constraint size based on the percentage value you give it.
/// Layout constraint to calculate size based on multiplier.
class PercentLayoutConstraint: NSLayoutConstraint {
#IBInspectable var marginPercent: CGFloat = 0
var screenSize: (width: CGFloat, height: CGFloat) {
return (UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height)
}
override func awakeFromNib() {
super.awakeFromNib()
guard marginPercent > 0 else { return }
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(layoutDidChange),
name: UIDeviceOrientationDidChangeNotification,
object: nil)
}
/**
Re-calculate constant based on orientation and percentage.
*/
func layoutDidChange() {
guard marginPercent > 0 else { return }
switch firstAttribute {
case .Top, .TopMargin, .Bottom, .BottomMargin:
constant = screenSize.height * marginPercent
case .Leading, .LeadingMargin, .Trailing, .TrailingMargin:
constant = screenSize.width * marginPercent
default: break
}
}
deinit {
guard marginPercent > 0 else { return }
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
source: https://basememara.com/percentage-based-margin-using-autolayout-storyboard/
I'm trying to create reusable views in a xib/nib file in swift iOS 10.
When I create a stack view and have 2 objects in it and make sure my stackview is constrained to the container view of the nib/xib (top to top, bottom to bottom, leading to leading and finally trailing to trailing), I get an error saying I'm missing my Y position for the first and the second object. Creating just one of them usually fixes it. Although this is where things to go sideways. In all my previous research, I shouldn't need to do this if I have my distribution of my stackview to Fill. Although this seems to quiet Xcode, it creates a over constraint issue when I try to run my program.
Here is what I used to load my nib in a view from my main storyboard :
public protocol NibOwnerLoadable: class {
static var nib: UINib { get }
}
//MARK:- Generic Implementation
public extension NibOwnerLoadable {
// Use the xib file with the same name as your UIView subclass located in the bundle of that class
static var nib: UINib {
return UINib(nibName: String(describing: self), bundle: Bundle(for: self))
}
}
//MARK:- Support for instation from the XIB file
public extension NibOwnerLoadable where Self: UIView {
// Function to load content and constraints automatically
func loadNibContent() {
let layoutAttributes: [NSLayoutAttribute] = [.top, .leading, .bottom, .trailing]
for view in Self.nib.instantiate(withOwner: self, options: nil) {
if let view = view as? UIView {
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = bounds
self.addSubview(view)
layoutAttributes.forEach{ attribute in self.addConstraint(NSLayoutConstraint(item: view, attribute: attribute, relatedBy: .equal, toItem: self, attribute: attribute, multiplier: 1, constant: 0.0))
}
}
}
}
}
I know my issue is an extra constraint being added by Auto Layout but why and where. This other question is very close to what I'm trying to do but for some reason my AutoLayout knowledge is a jumbled in my head. Adding a subclassed UIView to a Nib with its auto layout constraints
A little help would be appreciate. Please explain the why, not just how to do it. I'm a guy who likes to understand the back story. It makes it logical and easier to retain.
Here are pictures of my filterView as a nib/xib that is loaded inside searchAndFilterView as FilterView (UIView) that is loaded inside one my view controller inside my storyboard. Think reusable Tool Views.
Woohou!
Here is how I figured this out.
I realized that my height constraints on my views using XIB/NIB are necessary to setup the view when its not hidden. But when I set the .isHidden to true value this would conflict with my height constraint.
I needed to let Autolayout do its auto layout when the view changed from hidden to not hidden and vice-versa. By setting a constraint with a Priority default value of 1000, I was telling to Autolayout to absolutely make sure this constraint is always active.
I realized that by setting the priority to 999, I told Autolayout it could override my constraint when its really needed to do it. Why 999, I assume that when a view isHidden, it really has no size and that is very high priority for Autolayout.
I wish I knew this or knew how to find out default autolayout priorities before.
If anyone knows more about this I would appreciate more info or a link!!!
You can download a sample project demonstrating the issue below here:
https://github.com/DimaVartanian/keyboard-extension-height-bug
When creating a keyboard extension and not specifying a concrete height for its components but instead anchoring them to the view/inputView so that in theory the system will determine their height based on environment and orientation, in some situations that height instead turns into 0 and the keyboard is crushed (with the exception of anything that has a concrete height such as a self sized label or button).
This only seems to occur on iOS 10. On iOS 9, the child views resized correctly to fit the default automatic keyboard height.
There are several scenarios this can manifest and this project demonstrates a basic one. It starts with the basic keyboard extension template with the default "next keyboard" button and the 2 size constraints it comes with:
self.nextKeyboardButton.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.nextKeyboardButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
Next, we create a single other view that we want to fill the space of the superview without defining a concrete size for itself:
let anotherView = UIView()
anotherView.backgroundColor = UIColor.red
anotherView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(anotherView)
anotherView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
anotherView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
anotherView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
Now, let's say we just want to anchor this new view to the bottom of our keyboard superview. We would just do something like:
anotherView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
The result looks like this:
iOS 9
iOS 10
This layout is exactly what we expect. Now instead, let's anchor the new view to the top of our next keyboard button. We get rid of the constraint we just added and replace it with
anotherView.bottomAnchor.constraint(equalTo: self.nextKeyboardButton.topAnchor).isActive = true
Logically, the resulting height should be the same (determined by the system)
The result is now this:
iOS 9
iOS 10
On iOS 9 it behaves as expected but on iOS 10, the flexible height view is resized down to 0 and all that is left is the fixed height button.
There are no messages about conflicting constraints. I'm trying to figure out what could be causing this and why it would only be happening on iOS 10.
Apple has responded to my DTS ticket and told me to file a bug report, so this is actually an iOS 10 bug. I have filed a radar (#28532959) and will update this answer if I ever get a response. If someone else comes up with a concrete solution that allows me to still use autolayout to achieve an automatic height, answers are still accepted.
I got it solved by setting a new constrain for the height.
Here's my workaround. It is a little laggy when the device rotates, but it will do the job until Apple fixes this bug. I first thought it had something to do with inputView.allowSelfSizing, but that variable didn't seem to change anything.
First, declare heightConstraint:
var heightConstraint: NSLayoutConstraint!
In viewDidLoad, Add your custom view:
let nibName: String! = UIDevice.isPhone ? "KeyboardViewiPhone" : "KeyboardViewiPad"
customView = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?.first as! UIView
customView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(customView)
Add a constraint for the width as you would do normally:
let widthConstraint = NSLayoutConstraint(item: view, attribute: .width, relatedBy: .equal, toItem: customView, attribute: .width, multiplier: 1.0, constant: 0.0)
Add a constant constraint for the height:
heightConstraint = NSLayoutConstraint(item: customView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: view.frame.height)
view.addConstraints([widthConstraint, heightConstraint])
Now comes the fix:
override func viewDidLayoutSubviews() {
heightConstraint.constant = view.bounds.height
}
As viewDidLayoutSubviews is called every time view.bounds changes, it will handle orientation changes correctly.
I also faced the same issue. this is because of the Autolayout Constraints. Just remove all constraints. and set auto resizing.
I have also faced the same problem for the custom keyboard extension in Xcode 8.2. This is caused by the auto resizing. In my case, I solved this in the below manner.
Initially, my custom keyboard have 3 views.
In this, I was fixed the trailing, leading, top and height for the first and last view. And place the middle view like in the image.
after that select the middle view and open the show the size inspector in the storyboard. In the size inspector, you will find an option auto resizing. In that select the constraint indicators for that view.
After selecting that you run your project in a device and it will work correctly without missing any view.
Note: - It will work for both portrait and landscape modes. And mainly you don't have to give constraints for the middle view.
IMHO, best working solution is using "Proportional Height". For example, in my case, I finally ended with 2 views. Top one got 0.8 of height of superview, bottom - 0.2. It's not perfect solution, but you can still benefits from autolayout.
I am essentially trying to mimic the look and feel of Instagram's timeline view, which allows for photos of various aspect ratios to be displayed in a UITableViewCell, and to sit flush against the left and right margins of the view.
As of now, I have auto-layout constraints set for trailing and leading set to the superview, both set with a constant of 0, and bottom space and top space constraints set for the surrounding elements. As far as the image itself, I have it set to an aspect ratio constraint of 16:9, but ticked to "remove at build time", as images may sometimes have a different aspect ratio (16:12 is one).
Since I'll have access to the image's dimensional information in the downloaded JSON file before downloading the related images asynchronously, I want to set the height / width constraints of the image when the tableView is created with the JSON data. As of now, I'm creating the constraints in the UITableViewCell subclass within a function that is called from the UITableViewController's cellForRowAtIndexPath. Here is the code I'm using to create constraints:
func configurePostTableViewCell(post: Post) {
self.newsfeedPhotoImageView.translatesAutoresizingMaskIntoConstraints = false
let photoHeight: CGFloat = CGFloat(post.photoHeight)
let photoWidth: CGFloat = CGFloat(post.photoWidth)
let aspectRatioConstraint: NSLayoutConstraint = NSLayoutConstraint(item: self.timelinePhotoImageView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: self.timelinePhotoImageView, attribute: NSLayoutAttribute.Width, multiplier: (photoHeight / photoWidth), constant: 0)
aspectRatioConstraint.identifier = "$programmaticAspectRatio$"
self.timelinePhotoImageView.addConstraint(aspectRatioConstraint)
}
As I mentioned, the function itself is called within cellForRowAtIndexPath, and I've tried using the same code with cell. within the tableViewController, but the end result is the same:
When I build and run, the code at first seems to work perfectly, with both photos of different aspects being displayed correctly. The problem however, is when I scroll down 11 or so rows and (I'm assuming) the first few cells are dequeued for re-use. I set up a property observer in the cell to print to console when the cell is de-initialized, and the following error appeared at the same time the cells were dequeued:
2016-03-08 23:59:34.277 MyProject[12255:8479975] 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.
(
"<NSLayoutConstraint:0x7fe8c2c31820 '$timelinePhotoLeading$' H:|-(0)-[MyProject.AsyncImageView:0x7fe8c2d16080] (Names: '|':UITableViewCellContentView:0x7fe8c2d13cb0 )>",
"<NSLayoutConstraint:0x7fe8c2d0b230 '$timelinePhotoTrailing$' H:[MyProject.AsyncImageView:0x7fe8c2d16080]-(0)-| (Names: '|':UITableViewCellContentView:0x7fe8c2d13cb0 )>",
"<NSLayoutConstraint:0x7fe8c2d1b3d0 '$programmaticAspectRatio$' MyProject.AsyncImageView:0x7fe8c2d16080.height == 0.75*MyProject.AsyncImageView:0x7fe8c2d16080.width>",
"<NSLayoutConstraint:0x7fe8c0dae7f0 '$programmaticAspectRatio$' MyProject.AsyncImageView:0x7fe8c2d16080.height == 0.5625*MyProject.AsyncImageView:0x7fe8c2d16080.width>",
"<NSLayoutConstraint:0x7fe8c2d2e220 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7fe8c2d13cb0(375)]>")
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fe8c2d1b3d0 '$programmaticAspectRatio$' MyProject.AsyncImageView:0x7fe8c2d16080.height == 0.75*MyProject.AsyncImageView:0x7fe8c2d16080.width>
When I scroll back up to the top, the 16:12 photo no longer sits flush with the left and right margins, and appears to be taking the constraint of the 16:9 photo (which is consistent from what I'm inferring from the error message). If I'm understanding the error correctly, it seems the cell is trying to apply both constraints (16:9 and 16:12) to the same cell, despite what is specified in the code... which is what's causing the conflict. The tableViewController subclass is holding an array of "post" objects, each of which has a height / width value saved for its associated image, but it doesn't seem that data is being used after the cell is dequeued.
So my question is what am I supposed to do, to prevent these constraints from being messed up after being dequeued? Furthermore, after the error message appears, none of the following 16:12 images are appearing correctly, and I get the same error message a few more times (additional JSON is downloaded every 8 posts or so... similar to Instagram or Facebook, etc).
Here is a visual explanation of what's going wrong...
The first two images in that gallery reflect the intended appearance, but this third image depicts the error.
I've been struggling with this problem for at least a week now, and I'm not sure if there's something wrong in my strategy or if there is an additional function that I need to be calling when new cells are added and old ones are recycled. If anyone has any ideas or would like to see more of my code, I'd be very grateful for the assistance.
EDIT: Thanks to the help of the commenters below, I was able to fix my problem by removing the already existing aspect ratio constraint and then assigning the desired values from the UITableViewController to create a new one:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = timelineComponent.content[indexPath.row]
let photoHeight: CGFloat = CGFloat(post.photoHeight)
let photoWidth: CGFloat = CGFloat(post.photoWidth)
cell.aspectRatio = photoHeight / photoWidth
cell.configurePostTableViewCell(post)
return cell
}
And in the UITableViewCell itself:
var aspectRatioLayoutConstraint: NSLayoutConstraint!
var aspectRatio: CGFloat! {
didSet {
self.postPhotoImageView.translatesAutoresizingMaskIntoConstraints = false
if self.aspectRatioLayoutConstraint != nil {
self.postPhotoImageView.removeConstraint(self.aspectRatioLayoutConstraint)
}
self.aspectRatioLayoutConstraint = NSLayoutConstraint(item: self.postPhotoImageView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: self.postPhotoImageView, attribute: NSLayoutAttribute.Width, multiplier: aspectRatio, constant: 0)
self.postPhotoImageView.addConstraint(aspectRatioLayoutConstraint)
self.setNeedsLayout()
}
I have tried to make a UILabel that is a certain width using preferredMaxLayoutWidth but no matter what I do it won't work. Can you help me? I have tries so many different combinations to make it work.
#IBAction func addBottomTextButton(sender: AnyObject) {
if addBottomTextField.text.isEmpty == false {
let halfScreenWidth = screenSize.width * 0.5
let bottomScreenPosition = screenSize.width
memeBottomText = addBottomTextField.text
fontName = "Impact"
let memeBottomTextCaps = memeBottomText.uppercaseString // --> THIS IS A STRING!
labelBottom.text = memeBottomTextCaps
labelBottom.textColor = UIColor.blackColor()
labelBottom.textAlignment = .Center
labelBottom.font = UIFont(name: fontName, size: 32.0)
labelBottom.sizeToFit()
labelBottom.userInteractionEnabled = true
labelBottom.adjustsFontSizeToFitWidth = true
labelBottom.numberOfLines = 1
labelBottom.preferredMaxLayoutWidth = screenSize.width
labelBottom.setTranslatesAutoresizingMaskIntoConstraints(true)
var r = CGFloat(halfScreenWidth)
var s = CGFloat(bottomScreenPosition)
labelBottom.center = CGPoint(x: r, y: s)
self.view.addSubview(labelBottom)
self.view.addConstraint(NSLayoutConstraint(item: labelBottom, attribute:
NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: labelBottom,
attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0))
dismissKeyboard()
}
}
Judging by your code I'd say your problem was you haven't got your constraints setup correctly and you're mixing using NSLayoutConstraints with setting the position using center and setting the size using sizeToFit.
Firstly, in the constraint you've setup you're relating labelBottom (the item argument) to itself (the toItem argument). I'm not exactly sure what you were trying to achieve with that? I'd recommend having a look at some tutorials on AutoLayout if you're unfamiliar with its concepts. Here's a good one: http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1
Secondly, just a small point, on the line let memeBottomTextCaps = memeBottomText.uppercaseString you've written // --> THIS IS A STRING. An easier way to remind yourself of the variable type when looking back at your code could be to use: let memeBottomTextCaps: String = memeBottomText.uppercaseString.
Thirdly, preferredMaxLayoutWidth isn't used to set the width of a UILabel - that's what the frame is for (or NSLayoutConstraints if you're using AutoLayout).
Lets get on with it!
Here's an example of how to create a label that is pinned to the bottom edge of its container view and is not allowed to be wider than it's container: (Keep in mind that all this can be done in IB)
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel()
// 1.
label.setTranslatesAutoresizingMaskIntoConstraints(false)
// 2.
label.text = // Put your text here.
// 3.
self.view.addSubview(label)
// 4.
let pinToBottomConstraint = NSLayoutConstraint(item: label,
attribute: .Bottom,
relatedBy: .Equal,
toItem: self.view,
attribute: .Bottom,
multiplier: 1.0,
constant: -8.0)
// 5.
let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("|-8-[label]-8-|",
options: .DirectionLeadingToTrailing,
metrics: nil,
views: ["label" : label])
// 6.
self.view.addConstraint(pinToBottomConstraint)
self.view.addConstraints(horizontalConstraints)
}
}
The following referrers to the commented numbers in the code above.
1. You need to set setTranslatesAutoresizingMaskIntoConstraints to false to stop constraints being created that would otherwise conflict with the constraints we're going to create later. Here's the what Apple have to say about it:
Because the autoresizing mask naturally gives rise to constraints that fully specify a view’s position, any view that you wish to apply more flexible constraints to must be set to ignore its autoresizing mask using this method. You should call this method yourself for programmatically created views. Views created using a tool that allows setting constraints should have this set already.
2. You need to make sure you put your own text here, otherwise the code won't run.
3. The label must be added to the view hierarchy before adding constraints between it and it's superview! Otherwise, in this case, you'll get a runtime error saying:
Unable to parse constraint format:
Unable to interpret '|' character, because the related view doesn't have a superview
|-8-[label]-8-|
This is due to our horizontalConstraints needing to know the label's superview (the superview is denoted by the "|") but the label doesn't have a superview.
4. The pinToBottomConstraint constraint does what it says. The constant of -8 just specifies that I want the label to be 8 points from the bottom of its container view.
We don't need to create a constraint to specify the label's size - that's an intrinsic property of the UILabel which is determined, for example, by the number of lines and font.
5. The horiontalConstraints are created using Visual Format Language. Here's a good tutorial: http://code.tutsplus.com/tutorials/introduction-to-the-visual-format-language--cms-22715 Basically, "|-8-[label]-8-|" creates constraints to pin the left and right edges of the label to the left and right edges of its superview.
6. Finally add the constraints!
This is what it looks like:
I hope that answers your question.
I think the property only work for multiline situation.
// Support for constraint-based layout (auto layout)
// If nonzero, this is used when determining -intrinsicContentSize for multiline labels
#available(iOS 6.0, *)
open var preferredMaxLayoutWidth: CGFloat
And it indeed true after my test. So, we need set multiline. It will work.
titleLabel.numberOfLines = 0
I don't why Apple limit it to only multiline. In fact, we often need to set max width on label easily by one property.
Finally, if we want set max width , we need set max constaint, like the following
if device.isNew == "1" {
self.title.mas_updateConstraints { (make) in
make?.width.lessThanOrEqualTo()(163.w)
}
self.newTag.isHidden = false
} else {
self.newTag.isHidden = true
self.title.mas_updateConstraints { (make) in
make?.width.lessThanOrEqualTo()(207.w)
}
}