<code>// // ImageBubbleView.swift // JianDao // // Created by licrifan on 16/2/26. // Copyright © 2016年 licrifan. All rights reserved. // import UIKit class ImageBubbleView: UIView { var resMsg:ResourceMessage var bubbleImageView:UIImageView var isLoaded:Bool var isRefreshed:Bool var imageView:UIImageView // var refreshImgConstraintGroup:ConstraintGroup init(frame:CGRect, resourceMessage:ResourceMessage){ self.resMsg = resourceMessage self.bubbleImageView = UIImageView() self.isLoaded = false self.imageView = UIImageView() self.isRefreshed = false super.init(frame: frame) let placeHolderImageSize = BubbleImagePlaceHolder.size gLog.debug("placeHolderImageSize=\(placeHolderImageSize), self.resMsg.fileItem name=\(self.resMsg.fileItem.name), downloadUrl=\(self.resMsg.fileItem.downloadUrl)") let bubbleImage = MessageBubbleFactory.bubbleImageForType(self.resMsg.directionType) self.bubbleImageView.image = bubbleImage self.addSubview(self.bubbleImageView) constrain(bubbleImageView) { bubbleImageView in bubbleImageView.top == bubbleImageView.superview!.top bubbleImageView.left == bubbleImageView.superview!.left bubbleImageView.right == bubbleImageView.superview!.right bubbleImageView.bottom == bubbleImageView.superview!.bottom } if self.resMsg.fileItem.downloadUrl.isEmpty { self.imageView.image = BubbleImagePlaceHolder self.bubbleImageView.addSubview(self.imageView) constrain(self.imageView) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + 1 + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - 1 } imageView.width == placeHolderImageSize.width imageView.height == placeHolderImageSize.height } } else { let cacheKey = self.resMsg.fileItem.id let downloadUrl = NSURL(string: self.resMsg.fileItem.downloadUrl)! gLog.debug("key=\(cacheKey) for URL=\(downloadUrl)") //key=resource-128553c9-8d9b-4053-a134-cb333f2624ee for URL=http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-128553c9-8d9b-4053-a134-cb333f2624ee/download?token=9184uk795a33vnnsbbf4un1msl let downloadResource = Resource(downloadURL: downloadUrl, cacheKey: cacheKey) self.imageView.kf_setImageWithResource( downloadResource, placeholderImage: BubbleImagePlaceHolder, optionsInfo: nil, progressBlock: { (receivedSize, totalSize) -> () in let downloadPercent:Float = 100 * Float(receivedSize) / Float(totalSize) gLog.debug("Downloaded: \(receivedSize)/\(totalSize)=\(downloadPercent)%") }, //((image: Image?, error: NSError?, cacheType: CacheType, imageURL: NSURL?) -> ()) completionHandler: { (image, error, cacheType, imageURL) -> () in gLog.debug("image=\(image), cacheType=\(cacheType), imageURL=\(imageURL)") //image=Optional(<UIImage: 0x7daadc80>, {747, 495}), cacheType=Memory, imageURL=Optional(http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-27ddfda6-c33a-49cf-8941-e7cf7151a686/download?token=ecn9jo4dbvua2ua1j2h56rsbnu) if error != nil { gLog.error("load image \(self.resMsg.name) error \(error?.localizedDescription)") self.imageView.image = BubbleImageLoadFail } else { gLog.info("load image \(self.resMsg.name) completed") self.isLoaded = true //calculate proper ratio if let curImage = image { let newImageSize = calculateScaledSize(curImage.size, maxSize: BubbleImageMaxSize) constrain(self.imageView) { imageView in imageView.width == newImageSize.width imageView.height == newImageSize.height } // if !self.isRefreshed { // self.isRefreshed = true // // self.updateResMsgCell() // } } } dispatchMain_async({ self.layoutIfNeeded() }) }) self.bubbleImageView.addSubview(self.imageView) constrain(imageView) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + 1 + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - 1 } } } } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } </code>
自动布局的约束出现警告:
<code>2016-04-28 10:06:35.540 JianDao[8985:464975] 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:0x7b7eeb00 H:[image_placeholder(120)] (Names: image_placeholder:0x7c831840 )>", "<NSLayoutConstraint:0x7b7eeb40 H:|-(9)-[image_placeholder](LTR) (Names: image_placeholder:0x7c831840, '|':UIImageView:0x7b285140 )>", "<NSLayoutConstraint:0x7b7c0320 image_placeholder.right == UIImageView:0x7b285140.right - 2 (Names: image_placeholder:0x7c831840 )>", "<NSLayoutConstraint:0x7b796610 H:|-(0)-[UIImageView:0x7b285140](LTR) (Names: '|':JianDao.ImageBubbleView:0x7c83ebd0 )>", "<NSLayoutConstraint:0x7b7d6d90 UIImageView:0x7b285140.right == JianDao.ImageBubbleView:0x7c83ebd0.right>", "<NSLayoutConstraint:0x7b7d9b00 H:[JianDao.ImageBubbleView:0x7c83ebd0(<=120)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7b7eeb00 H:[image_placeholder(120)] (Names: image_placeholder:0x7c831840 )> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. </code>
结果改了,还是出错:
<code>2016-04-28 10:24:27.001 [Verbose] [main] [ImageBubbleView.swift:104] init(frame:resourceMessage:) > curImage.size=(750.0, 1378.0), BubbleImageMaxSize=(120.0, 120.0)-> newImageSize=(65.312, 120.0) 2016-04-28 10:24:27.002 JianDao[9298:480875] 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:0x7b874850 V:|-(10)-[UIButton:0x7b83fc10] (Names: '|':UITableViewCellContentView:0x7b8317f0 )>", "<NSLayoutConstraint:0x7b819f20 V:|-(0)-[UIImageView:0x7b846ac0] (Names: '|':JianDao.ImageBubbleView:0x78e03510 )>", "<NSLayoutConstraint:0x7b83fbc0 UIImageView:0x7b846ac0.bottom == JianDao.ImageBubbleView:0x78e03510.bottom>", "<NSLayoutConstraint:0x78ec8ce0 JianDao.ImageBubbleView:0x78e03510.top == UIButton:0x7b83fc10.top>", "<NSLayoutConstraint:0x78e93960 JianDao.ImageBubbleView:0x78e03510.bottom <= UITableViewCellContentView:0x7b8317f0.bottom>", "<NSLayoutConstraint:0x7a285620 V:|-(2)-[UIImageView:0x7b870380] (Names: '|':UIImageView:0x7b846ac0 )>", "<NSLayoutConstraint:0x7a688f40 UIImageView:0x7b870380.bottom == UIImageView:0x7b846ac0.bottom - 2>", "<NSLayoutConstraint:0x78fa9170 V:[UIImageView:0x7b870380(120)]>", "<NSLayoutConstraint:0x7a239ad0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b8317f0(130)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x78fa9170 V:[UIImageView:0x7b870380(120)]> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. </code>
改了代码,结果还是有问题。。。
<code>2016-2016-04-28 10:51:08.664 JianDao[9593:498647] 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:0x79fe3af0 V:|-(10)-[UIButton:0x7a7f35a0] (Names: '|':UITableViewCellContentView:0x7a7f3a60 )>", "<NSLayoutConstraint:0x79fe6050 V:[UIImageView:0x79fe4790(67.1137)]>", "<NSLayoutConstraint:0x79fe5bd0 V:|-(2)-[UIImageView:0x79fe4790] (Names: '|':UIImageView:0x79fe46b0 )>", "<NSLayoutConstraint:0x79fe6220 UIImageView:0x79fe4790.bottom == UIImageView:0x79fe46b0.bottom - 2>", "<NSLayoutConstraint:0x79fe49c0 V:|-(0)-[UIImageView:0x79fe46b0] (Names: '|':JianDao.ImageBubbleView:0x79fe45d0 )>", "<NSLayoutConstraint:0x79fe5130 UIImageView:0x79fe46b0.bottom == JianDao.ImageBubbleView:0x79fe45d0.bottom>", "<NSLayoutConstraint:0x7a7f5a00 JianDao.ImageBubbleView:0x79fe45d0.top == UIButton:0x7a7f35a0.top>", "<NSLayoutConstraint:0x7a7f5a70 JianDao.ImageBubbleView:0x79fe45d0.bottom <= UITableViewCellContentView:0x7a7f3a60.bottom>", "<NSLayoutConstraint:0x79fb0940 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7a7f3a60(81)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x79fe6050 V:[UIImageView:0x79fe4790(67.1137)]> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. </code>
改为:
<code>// // ImageBubbleView.swift // JianDao // // Created by licrifan on 16/2/26. // Copyright © 2016年 licrifan. All rights reserved. // import UIKit class ImageBubbleView: UIView { var resMsg:ResourceMessage var bubbleImageView:UIImageView var isLoaded:Bool var isRefreshed:Bool var imageView:UIImageView var imageViewConstraintGroup:ConstraintGroup // var refreshImgConstraintGroup:ConstraintGroup init(frame:CGRect, resourceMessage:ResourceMessage){ self.resMsg = resourceMessage self.bubbleImageView = UIImageView() self.isLoaded = false self.imageView = UIImageView() self.isRefreshed = false self.imageViewConstraintGroup = ConstraintGroup() super.init(frame: frame) let placeHolderImageSize = BubbleImagePlaceHolder.size gLog.debug("placeHolderImageSize=\(placeHolderImageSize), self.resMsg.fileItem name=\(self.resMsg.fileItem.name), downloadUrl=\(self.resMsg.fileItem.downloadUrl)") let bubbleImage = MessageBubbleFactory.bubbleImageForType(self.resMsg.directionType) self.bubbleImageView.image = bubbleImage self.addSubview(self.bubbleImageView) constrain(bubbleImageView) { bubbleImageView in bubbleImageView.top == bubbleImageView.superview!.top bubbleImageView.left == bubbleImageView.superview!.left bubbleImageView.right == bubbleImageView.superview!.right bubbleImageView.bottom == bubbleImageView.superview!.bottom } self.bubbleImageView.addSubview(self.imageView) if self.resMsg.fileItem.downloadUrl.isEmpty { self.imageView.image = BubbleImagePlaceHolder self.imageViewConstraintGroup = constrain(self.imageView) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin } imageView.width == placeHolderImageSize.width imageView.height == placeHolderImageSize.height } } else { let cacheKey = self.resMsg.fileItem.id let downloadUrl = NSURL(string: self.resMsg.fileItem.downloadUrl)! gLog.debug("key=\(cacheKey) for URL=\(downloadUrl)") //key=resource-128553c9-8d9b-4053-a134-cb333f2624ee for URL=http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-128553c9-8d9b-4053-a134-cb333f2624ee/download?token=9184uk795a33vnnsbbf4un1msl let downloadResource = Resource(downloadURL: downloadUrl, cacheKey: cacheKey) self.imageView.kf_setImageWithResource( downloadResource, placeholderImage: BubbleImagePlaceHolder, optionsInfo: nil, progressBlock: { (receivedSize, totalSize) -> () in let downloadPercent:Float = 100 * Float(receivedSize) / Float(totalSize) gLog.verbose("Downloaded: \(receivedSize)/\(totalSize)=\(downloadPercent)%") }, //((image: Image?, error: NSError?, cacheType: CacheType, imageURL: NSURL?) -> ()) completionHandler: { (image, error, cacheType, imageURL) -> () in gLog.info("image=\(image), cacheType=\(cacheType), imageURL=\(imageURL)") //image=Optional(<UIImage: 0x7daadc80>, {747, 495}), cacheType=Memory, imageURL=Optional(http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-27ddfda6-c33a-49cf-8941-e7cf7151a686/download?token=ecn9jo4dbvua2ua1j2h56rsbnu) if error != nil { gLog.error("load image \(self.resMsg.name) error \(error?.localizedDescription)") dispatchMain_async({ self.imageView.image = BubbleImageLoadFail }) } else { gLog.info("load image \(self.resMsg.name) completed") self.isLoaded = true //calculate proper ratio if let curImage = image { let newImageSize = calculateScaledSize(curImage.size, maxSize: BubbleImageMaxSize) gLog.verbose("curImage.size=\(curImage.size), BubbleImageMaxSize=\(BubbleImageMaxSize)-> newImageSize=\(newImageSize)") constrain(self.imageView, replace: self.imageViewConstraintGroup) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin } imageView.width == newImageSize.width imageView.height == newImageSize.height } // if !self.isRefreshed { // self.isRefreshed = true // // self.updateResMsgCell() // } dispatchMain_async({ self.updateConstraintsIfNeeded() }) } } // dispatchMain_async({ // self.updateConstraints() // //self.layoutIfNeeded() // }) }) self.imageViewConstraintGroup = constrain(imageView) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin } } } } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func updateResMsgCell() { if let cellContentView = self.superview { gLog.verbose("cellContentView=\(cellContentView)") //<UITableViewCellContentView: 0x7bf72790; frame = (0 0; 320 130); gestureRecognizers = <NSArray: 0x7bf72cb0>; layer = <CALayer: 0x7bf72860>> if let msgTableViewCell = cellContentView.superview { gLog.verbose("msgTableViewCell=\(msgTableViewCell)") //<JianDao.MessageTableViewCell: 0x79a29800; baseClass = UITableViewCell; frame = (0 300; 320 130); hidden = YES; autoresize = W; layer = <CALayer: 0x787a3e30>> if let msgTableViewWrapperView = msgTableViewCell.superview { gLog.verbose("msgTableViewWrapperView=\(msgTableViewWrapperView)") //<UITableViewWrapperView: 0x7aadee00; frame = (0 0; 320 1200); gestureRecognizers = <NSArray: 0x78ec4400>; layer = <CALayer: 0x78a0abe0>; contentOffset: {0, 0}; contentSize: {320, 1200}> if let msgTableView = msgTableViewWrapperView.superview { gLog.verbose("msgTableView=\(msgTableView)") //<UITableView: 0x7c121e00; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = H+BM; gestureRecognizers = <NSArray: 0x7ca445a0>; layer = <CALayer: 0x7cea9a90>; contentOffset: {0, 740}; contentSize: {320, 1609.5}> msgTableView.layoutIfNeeded() } } } } } } </code>
但是还有:
<code>2016-04-28 10:58:45.505 JianDao[9717:505337] 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:0x7dac0d70 V:|-(10)-[UIButton:0x7b76e0d0] (Names: '|':UITableViewCellContentView:0x7b7f9e50 )>", "<NSLayoutConstraint:0x7b743010 V:[UIImageView:0x7dac1900(23.229)]>", "<NSLayoutConstraint:0x7b742e10 V:|-(2)-[UIImageView:0x7dac1900] (Names: '|':UIImageView:0x7dac1820 )>", "<NSLayoutConstraint:0x7b742ec0 UIImageView:0x7dac1900.bottom == UIImageView:0x7dac1820.bottom - 2>", "<NSLayoutConstraint:0x7dac1b00 V:|-(0)-[UIImageView:0x7dac1820] (Names: '|':JianDao.ImageBubbleView:0x7dac1740 )>", "<NSLayoutConstraint:0x7dac1fd0 UIImageView:0x7dac1820.bottom == JianDao.ImageBubbleView:0x7dac1740.bottom>", "<NSLayoutConstraint:0x7b743f00 JianDao.ImageBubbleView:0x7dac1740.top == UIButton:0x7b76e0d0.top>", "<NSLayoutConstraint:0x7b743f70 JianDao.ImageBubbleView:0x7dac1740.bottom <= UITableViewCellContentView:0x7b7f9e50.bottom>", "<NSLayoutConstraint:0x7b7f8380 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b7f9e50(37)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7b743010 V:[UIImageView:0x7dac1900(23.229)]> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. </code>
后来调试,看到具体是哪个view了:
<code>2016-04-28 11:08:59.530 JianDao[9821:517584] 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:0x7b1b8e90 V:|-(10)-[UIButton:0x7b1bc310] (Names: '|':UITableViewCellContentView:0x7b1baf20 )>", "<NSLayoutConstraint:0x7b1b7820 V:|-(0)-[UIImageView:0x7b1b7b70] (Names: '|':JianDao.ImageBubbleView:0x7b1b7a90 )>", "<NSLayoutConstraint:0x7b1b6270 UIImageView:0x7b1b7b70.bottom == JianDao.ImageBubbleView:0x7b1b7a90.bottom>", "<NSLayoutConstraint:0x79f2e430 JianDao.ImageBubbleView:0x7b1b7a90.top == UIButton:0x7b1bc310.top>", "<NSLayoutConstraint:0x79f4d320 JianDao.ImageBubbleView:0x7b1b7a90.bottom <= UITableViewCellContentView:0x7b1baf20.bottom>", "<NSLayoutConstraint:0x79fc30c0 V:|-(2)-[UIImageView:0x7b1b7c50] (Names: '|':UIImageView:0x7b1b7b70 )>", "<NSLayoutConstraint:0x79f34090 UIImageView:0x7b1b7c50.bottom == UIImageView:0x7b1b7b70.bottom - 2>", "<NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]>", "<NSLayoutConstraint:0x79f2e400 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b1baf20(44)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. (lldb) po imageView <UIImageView: 0x7b1b7c50; frame = (10 2; 120 30); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=<CABasicAnimation: 0x7b26c2d0>; bounds.size=<CABasicAnimation: 0x7b26ca50>; position=<CABasicAnimation: 0x7b26cb90>; }; layer = <CALayer: 0x7b1b7d30>> - (null) (lldb) po imageView.superview ▿ Optional<UIView> - Some : <UIImageView: 0x7b1b7b70; frame = (0 0; 132 34); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=<CABasicAnimation: 0x7b26c300>; bounds.size=<CABasicAnimation: 0x7b26c740>; position=<CABasicAnimation: 0x7b26c960>; }; layer = <CALayer: 0x7b1b8fb0>> - (null) (lldb) po self.bubbleImageView <UIImageView: 0x7b1b7b70; frame = (0 0; 132 34); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=<CABasicAnimation: 0x7b26c300>; bounds.size=<CABasicAnimation: 0x7b26c740>; position=<CABasicAnimation: 0x7b26c960>; }; layer = <CALayer: 0x7b1b8fb0>> - (null) (lldb) po self <JianDao.ImageBubbleView: 0x7b1b7a90; frame = (45 10; 132 34); animations = { bounds.origin=<CABasicAnimation: 0x7b26c350>; bounds.size=<CABasicAnimation: 0x7b26c460>; position=<CABasicAnimation: 0x7b26c670>; }; layer = <CALayer: 0x7b1b7d60>> (lldb) po self.superview ▿ Optional<UIView> - Some : <UITableViewCellContentView: 0x7b1baf20; frame = (0 0; 320 44); gestureRecognizers = <NSArray: 0x7b1baac0>; animations = { position=<CABasicAnimation: 0x7b26ae10>; bounds.origin=<CABasicAnimation: 0x7b26afd0>; bounds.size=<CABasicAnimation: 0x7b26b0f0>; }; layer = <CALayer: 0x7b1baff0>> (lldb) po self.superview?.superview ▿ Optional<UIView> - Some : <JianDao.MessageTableViewCell: 0x7937d400; baseClass = UITableViewCell; frame = (0 988; 320 44); autoresize = W; animations = { position=<CABasicAnimation: 0x7b26a8b0>; bounds.origin=<CABasicAnimation: 0x7b26ab10>; bounds.size=<CABasicAnimation: 0x7b26ac20>; }; layer = <CALayer: 0x7b1baef0>> (lldb) po self.superview?.superview?.superview ▿ Optional<UIView> - Some : <UITableViewWrapperView: 0x792ccc00; frame = (0 0; 320 460); gestureRecognizers = <NSArray: 0x79e02e50>; layer = <CALayer: 0x79e2b6d0>; contentOffset: {0, 0}; contentSize: {320, 460}> (lldb) po self.superview?.superview?.superview?.superview ▿ Optional<UIView> - Some : <UITableView: 0x792a1000; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = H+BM; gestureRecognizers = <NSArray: 0x787f89f0>; animations = { bounds.origin=<CABasicAnimation: 0x798342a0>; bounds.size=<CABasicAnimation: 0x798343c0>; }; layer = <CALayer: 0x7b185390>; contentOffset: {0, 768}; contentSize: {320, 2302}> (lldb) po self.subviews ▿ 1 elements - [0] : <UIImageView: 0x7b1b7b70; frame = (0 0; 132 34); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=<CABasicAnimation: 0x7b26c300>; bounds.size=<CABasicAnimation: 0x7b26c740>; position=<CABasicAnimation: 0x7b26c960>; }; layer = <CALayer: 0x7b1b8fb0>> - (null) (lldb) </code>
剩下的问题就是:如何看懂约束冲突
how debug Unable to simultaneously satisfy constraints
Auto Layout Guide: Debugging Tricks and Tips
Auto Layout Guide: Visual Format Language
上述的问题中:
<code> "<NSLayoutConstraint:0x7b1b8e90 V:|-(10)-[UIButton:0x7b1bc310] (Names: '|':UITableViewCellContentView:0x7b1baf20 )>", "<NSLayoutConstraint:0x7b1b7820 V:|-(0)-[UIImageView:0x7b1b7b70] (Names: '|':JianDao.ImageBubbleView:0x7b1b7a90 )>", "<NSLayoutConstraint:0x7b1b6270 UIImageView:0x7b1b7b70.bottom == JianDao.ImageBubbleView:0x7b1b7a90.bottom>", "<NSLayoutConstraint:0x79f2e430 JianDao.ImageBubbleView:0x7b1b7a90.top == UIButton:0x7b1bc310.top>", "<NSLayoutConstraint:0x79f4d320 JianDao.ImageBubbleView:0x7b1b7a90.bottom <= UITableViewCellContentView:0x7b1baf20.bottom>", "<NSLayoutConstraint:0x79fc30c0 V:|-(2)-[UIImageView:0x7b1b7c50] (Names: '|':UIImageView:0x7b1b7b70 )>", "<NSLayoutConstraint:0x79f34090 UIImageView:0x7b1b7c50.bottom == UIImageView:0x7b1b7b70.bottom - 2>", "<NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]>", "<NSLayoutConstraint:0x79f2e400 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b1baf20(44)]>" </code>
最后一个:
UIView-Encapsulated-Layout
是系统主动设置的,是你没法改的-》是系统帮你修正后的结果
-》说明就是这部分有点问题
-》说明此处就是UIView-Encapsulated-Layout-Height中的Height高度出了问题
-》系统自动帮忙把UITableViewCellContentView的高度设置为了44
另外对于Will attempt to recover by breaking constraint的部分,是说系统尝试恢复这部分的问题
而此处的是:
<code><NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]> </code>
-》
容易看出:
此处是UIImageView的V=Vertical=高度,设置为了90.1408
-》很明显,和上面系统强制恢复,设置UITableViewCellContentView的高度为44,两者冲突了
-》此处的背景逻辑是:
当前的一些视图属于tableview的cell的content部分:UITableViewCellContentView
UITableViewCellContentView部分的高度只有44
但是内部的一个view:UIImageView,高度却设置为90.1408
-》内部元素高度高于外部父视图的高度,所以冲突了
-》但是其实狠怪异的是:
此处的UITableViewCellContentView的高度
不应该是44的
而应该是
后来多次类似错误:
<code>( "<NSLayoutConstraint:0x7d19a4f0 V:|-(10)-[UIButton:0x7be4c080] (Names: '|':UITableViewCellContentView:0x7be44f30 )>", "<NSLayoutConstraint:0x7d054610 V:|-(0)-[UIImageView:0x7b92e610] (Names: '|':JianDao.ImageBubbleView:0x7b9151d0 )>", "<NSLayoutConstraint:0x7a75a6b0 UIImageView:0x7b92e610.bottom == JianDao.ImageBubbleView:0x7b9151d0.bottom>", "<NSLayoutConstraint:0x7d05eec0 JianDao.ImageBubbleView:0x7b9151d0.top == UIButton:0x7be4c080.top>", "<NSLayoutConstraint:0x7d06d2d0 JianDao.ImageBubbleView:0x7b9151d0.bottom <= UITableViewCellContentView:0x7be44f30.bottom>", "<NSLayoutConstraint:0x7beae800 V:|-(2)-[UIImageView:0x7d167cd0] (Names: '|':UIImageView:0x7b92e610 )>", "<NSLayoutConstraint:0x7be456d0 UIImageView:0x7d167cd0.bottom == UIImageView:0x7b92e610.bottom - 2>", "<NSLayoutConstraint:0x7be46170 V:[UIImageView:0x7d167cd0(67.1137)]>", "<NSLayoutConstraint:0x7d194600 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7be44f30(81)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7be46170 V:[UIImageView:0x7d167cd0(67.1137)]> </code>
最后改为:
<code>// // ImageBubbleView.swift // JianDao // // Created by licrifan on 16/2/26. // Copyright © 2016年 licrifan. All rights reserved. // import UIKit class ImageBubbleView: UIView { var resMsg:ResourceMessage var bubbleImageView:UIImageView var isLoaded:Bool var isRefreshed:Bool var imageView:UIImageView var imageViewConstraintGroup:ConstraintGroup // var refreshImgConstraintGroup:ConstraintGroup init(frame:CGRect, resourceMessage:ResourceMessage){ self.resMsg = resourceMessage self.bubbleImageView = UIImageView() self.isLoaded = false self.imageView = UIImageView() self.isRefreshed = false self.imageViewConstraintGroup = ConstraintGroup() super.init(frame: frame) let placeHolderImageSize = BubbleImagePlaceHolder.size gLog.debug("placeHolderImageSize=\(placeHolderImageSize), self.resMsg.fileItem name=\(self.resMsg.fileItem.name), downloadUrl=\(self.resMsg.fileItem.downloadUrl)") let bubbleImage = MessageBubbleFactory.bubbleImageForType(self.resMsg.directionType) self.bubbleImageView.image = bubbleImage self.addSubview(self.bubbleImageView) constrain(bubbleImageView) { bubbleImageView in bubbleImageView.top == bubbleImageView.superview!.top bubbleImageView.left == bubbleImageView.superview!.left bubbleImageView.right == bubbleImageView.superview!.right bubbleImageView.bottom == bubbleImageView.superview!.bottom } self.bubbleImageView.addSubview(self.imageView) if self.resMsg.fileItem.downloadUrl.isEmpty { self.imageView.image = BubbleImagePlaceHolder constrain(self.imageView, replace: self.imageViewConstraintGroup) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin } imageView.width == placeHolderImageSize.width imageView.height == placeHolderImageSize.height } } else { let cacheKey = self.resMsg.fileItem.id let downloadUrl = NSURL(string: self.resMsg.fileItem.downloadUrl)! gLog.debug("key=\(cacheKey) for URL=\(downloadUrl)") //key=resource-128553c9-8d9b-4053-a134-cb333f2624ee for URL=http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-128553c9-8d9b-4053-a134-cb333f2624ee/download?token=9184uk795a33vnnsbbf4un1msl let downloadResource = Resource(downloadURL: downloadUrl, cacheKey: cacheKey) self.imageView.kf_setImageWithResource( downloadResource, placeholderImage: BubbleImagePlaceHolder, optionsInfo: nil, progressBlock: { (receivedSize, totalSize) -> () in let downloadPercent:Float = 100 * Float(receivedSize) / Float(totalSize) gLog.verbose("Downloaded: \(receivedSize)/\(totalSize)=\(downloadPercent)%") }, //((image: Image?, error: NSError?, cacheType: CacheType, imageURL: NSURL?) -> ()) completionHandler: { (image, error, cacheType, imageURL) -> () in gLog.info("image=\(image), cacheType=\(cacheType), imageURL=\(imageURL)") //image=Optional(<UIImage: 0x7daadc80>, {747, 495}), cacheType=Memory, imageURL=Optional(http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-27ddfda6-c33a-49cf-8941-e7cf7151a686/download?token=ecn9jo4dbvua2ua1j2h56rsbnu) if (error != nil) || (image == nil) { gLog.error("load \(image) for \(self.resMsg.name) error \(error?.localizedDescription)") dispatchMain_async({ self.imageView.image = BubbleImageLoadFail }) return } gLog.info("load image \(self.resMsg.name) completed") self.isLoaded = true //calculate proper ratio let newImageSize = calculateScaledSize(image!.size, maxSize: BubbleImageMaxSize) gLog.verbose("image.size=\(image!.size), BubbleImageMaxSize=\(BubbleImageMaxSize)-> newImageSize=\(newImageSize)") dispatchMain_async({ constrain(self.imageView, replace: self.imageViewConstraintGroup) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin } imageView.width == newImageSize.width imageView.height == newImageSize.height } self.updateConstraintsIfNeeded() self.layoutIfNeeded() // self.updateResMsgCell() }) }) constrain(imageView, replace: self.imageViewConstraintGroup) { imageView in imageView.top == imageView.superview!.top + BubbleMargin imageView.bottom == imageView.superview!.bottom - BubbleMargin if self.resMsg.directionType == MessageDirectionType.Receive { imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth imageView.right == imageView.superview!.right - BubbleMargin }else if self.resMsg.directionType == MessageDirectionType.Send { imageView.left == imageView.superview!.left + BubbleMargin imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin } } } } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } </code>
基本上解决了此处的约束警告了。
转载请注明:在路上 » [已解决]iOS中自动布局约束出错:Unable to simultaneously satisfy constraints