首先,我一直在阅读与此类似的所有问题,但没有成功,所以最后我会尝试询问我的具体案例。
我有一个UIScrollView,我以这种方式编程填充组件:
- (void) fillScrollView(int numItems)
{
float posY = 10.0;
for(int i = 0; i < numItems; i++)
{
UIImageView *leftImg = [[UIImageView alloc] init];
[leftImg setTranslatesAutoresizingMaskIntoConstraints:NO];
[leftImg setFrame:CGRectMake(10.0, posY, 20.0, 20.0)];
[leftImg setImage:[UIImage imageNamed:@"img1"]];
UILabel *txtLb = [[UILabel alloc] init];
[txtLb setTranslatesAutoresizingMaskIntoConstraints:NO];
[txtLb setFont:[UIFont systemFontOfSize:15.0]];
[txtLb setNumberOfLines:0];
[txtLb setLineBreakMode:NSLineBreakByWordWrapping];
[txtLb setFrame:CGRectMake(40.0, posY, 240.0, 20.0)];
NSString *data = @"This is my example text, it could be longer.";
[txtLb setText:data];
CGRect paragraphRect = [dato boundingRectWithSize:CGSizeMake(txtLb.frame.size.width, 9999.0)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:@{NSFontAttributeName: txtLb.font}
context:nil];
float height = paragraphRect.size.height;
CGRect frame = txtLb.frame;
frame.size.height = ceil(height);
[txtLb setFrame:frame];
UIImageView *rightImg = [[UIImageView alloc] init];
[rightImg setTranslatesAutoresizingMaskIntoConstraints:NO];
[rightImg setFrame:CGRectMake(290.0, posY, 20.0, 20.0)];
[rightImg setImage:[UIImage imageNamed:@"img2"]];
[_scrollV addSubview:leftImg];
[_scrollV addSubview:txtLb];
[_scrollV addSubview:rightImg];
height = height + 20.0;
if(height < 40.0) height = 40.0;
posY = posY + height;
}
[_scrollV setContentSize:CGSizeMake(_scrollV.frame.size.width, posY)];
}
我希望这些限制是:
H:| -10- [leftImg(20)] - 10- [txtLb] -10- [rightImg(20)] - 10- | 并且垂直每行的空间与上面一行的垂直间距为10px。
我尝试过使用constraintWithItem,但在这种情况下,我对如何使用它感到困惑。
非常感谢任何帮助。亲切的问候!
修改
根据张的建议,我已将3个组件放入UIView中。这样我可以在它们之间使用autolayout而不会出现问题,并且每个UIView内的所有内容都处于正确的位置。
但是我在循环内部的UIViews之间使用autolayout时仍然遇到问题。我这样做:
所有块都没有UIScrollView的左/右边距。
// 0px to the left of the UIScrollView
NSLayoutConstraint *constraintLeft = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeLeftMargin
relatedBy:NSLayoutRelationEqual
toItem:_scrollV
attribute:NSLayoutAttributeRightMargin
multiplier:1.0
constant:0.0];
// 0px to the right of the UIScrollView
NSLayoutConstraint *constraintRight = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeRightMargin
relatedBy:NSLayoutRelationEqual
toItem:_scrollV
attribute:NSLayoutAttributeLeftMargin
multiplier:1.0
constant:0.0];
[_scrollV addConstraint:constraintLeft];
[_scrollV addConstraint:constraintRight];
关于块之间的垂直分隔,当UIView是UIScrollView的第一个块时:
// 10px below UIScrollView top
NSLayoutConstraint *constraintTop = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeTopMargin
relatedBy:NSLayoutRelationEqual
toItem:_scrollV
attribute:NSLayoutAttributeBottomMargin
multiplier:1.0
constant:10.0];
[_scrollV addConstraint:constraintTop];
当UIView上方有任何阻挡时:
// 10px below previous block
NSLayoutConstraint *constraintTop = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeTopMargin
relatedBy:NSLayoutRelationEqual
toItem:previousBlock
attribute:NSLayoutAttributeBottomMargin
multiplier:1.0
constant:10.0];
[_scrollV addConstraint:constraintTop];
这显示所有没有垂直分离的块,都在相同的Y位置,并且还给出了应用约束的错误。 我确定我没有使用正确的约束方法,但我找不到这种用法的例子。
答案 0 :(得分:7)
看起来你正试图重新发明轮子队友。您可能应该使用UICollectionView或UITableView而不是UIScrollView并手动添加单元格。
无论如何,对于你的scrollView方法,你可以实现它的一种方法是:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView;
@end
#import "ViewController.h"
#import "Cell.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initViews];
[self initConstraints];
[self fillScrollView:15];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)prefersStatusBarHidden
{
return YES;
}
-(void)initViews
{
self.scrollView = [[UIScrollView alloc] init];
// ------------------------------------------------------------------
// This content view will be the only child view of scrollview
// ------------------------------------------------------------------
self.contentView = [[UIView alloc] init];
// add content view to scrollview now
[self.scrollView addSubview:self.contentView];
// add scrollview to main view
[self.view addSubview:self.scrollView];
}
-(void)initConstraints
{
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"scrollView": self.scrollView,
@"contentView": self.contentView
};
// setup scrollview constraints
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:nil views:views]];
// ---------------------------------------
// setup content view constraint
//
// note: need to pin all four side of
// contentView to scrollView
// ---------------------------------------
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:nil views:views]];
}
-(void)fillScrollView:(int) numItems
{
// clear any previous cells before adding new ones
[self.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
// Need to construct the layout visual format string
NSMutableString *strVerticalConstraint = [[NSMutableString alloc] init];
[strVerticalConstraint appendString:@"V:|"];
// this dictionary will hold all the key-value pair that identifies all the subviews
NSMutableDictionary *subviews = [[NSMutableDictionary alloc] init];
for(int i = 0; i < numItems; i++)
{
Cell *cell = [[Cell alloc] init];
// customize the cell's appearance here
cell.leftImage.image = [UIImage imageNamed:@"leftImage.png"];
cell.textLabel.text = @"This is my example text, it could be longer.";
cell.rightImage.image = [UIImage imageNamed:@"rightImage.png"];
[self.contentView addSubview:cell];
cell.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"cell": cell
};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[cell]|" options:0 metrics:nil views:views]];
// prevent cell's width to extend beyond screen width
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1.0 constant:self.view.bounds.size.width]];
// cell name
NSString *cellName = [[NSString alloc] initWithFormat:@"cell%d", i];
// construct each cell's vertical constraint to add it strVerticalConstraint
NSString *viewName = nil;
if(i < numItems - 1)
{
viewName = [[NSString alloc] initWithFormat:@"[%@(50)]-10-", cellName];
}
else
{
viewName = [[NSString alloc] initWithFormat:@"[%@(50)]", cellName];
}
[strVerticalConstraint appendString:viewName];
// add cell name to dictionary
[subviews setValue:cell forKey:cellName];
}
[strVerticalConstraint appendString:@"|"];
NSLog(@"strVerticalConstraint: \n%@", strVerticalConstraint);
// Finally, use the long vertical constraint string
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:strVerticalConstraint options:0 metrics:nil views:subviews]];
}
@end
#import <UIKit/UIKit.h>
@interface Cell : UIView
@property (nonatomic, strong) UIImageView *leftImage;
@property (nonatomic, strong) UILabel *textLabel;
@property (nonatomic, strong) UIImageView *rightImage;
@end
#import "Cell.h"
@implementation Cell
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
self.backgroundColor = [UIColor grayColor];
self.leftImage = [[UIImageView alloc] init];
self.leftImage.contentMode = UIViewContentModeScaleAspectFill;
self.leftImage.clipsToBounds = YES;
self.leftImage.layer.cornerRadius = 10.0;
self.textLabel = [[UILabel alloc] init];
self.textLabel.numberOfLines = 0;
self.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.rightImage = [[UIImageView alloc] init];
self.rightImage.contentMode = UIViewContentModeScaleAspectFill;
self.rightImage.layer.cornerRadius = 10.0;
self.rightImage.clipsToBounds = YES;
[self addSubview:self.leftImage];
[self addSubview:self.textLabel];
[self addSubview:self.rightImage];
}
-(void)initConstraints
{
self.leftImage.translatesAutoresizingMaskIntoConstraints = NO;
self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.rightImage.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"leftImage": self.leftImage,
@"textLabel": self.textLabel,
@"rightImage": self.rightImage
};
// horizontal constraints
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[leftImage(20)]-10-[textLabel]-[rightImage(20)]-10-|" options:0 metrics:nil views:views]];
// vertical constraints
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.leftImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.rightImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[leftImage(20)]" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[rightImage(20)]" options:0 metrics:nil views:views]];
}
@end
你应该看到这样的事情:
也许您有理由使用scrollView并手动添加每一行,否则,如果您打开替代方案,则可以使用UICollectionView或UITableView。
如果您有1000行,应用程序需要计算,渲染并在内存中存储1000行,上面的方法将导致大量内存使用。不可扩展,不可行。
这就是UITableView或UICollectionView的用武之地,当它从屏幕上移开时重用每个单元格,你只需要在屏幕上渲染和存储可见单元格。
所以,如果你想看到一个UICollectionView方法,这是一个如何做到这一点的演示:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) NSArray *items;
@end
#import "ViewController.h"
#import "CustomCell.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initViews];
[self initConstraints];
// --------------------------------------------------------
// Hardcoding 15 sample items as the data source.
// Your data might be from a JSON webservice REST API.
// --------------------------------------------------------
self.items = @[
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer.",
@"This is my example text, it could be longer."
];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)initViews
{
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.minimumInteritemSpacing = 0;
flowLayout.minimumLineSpacing = 10;
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
self.collectionView.backgroundColor = [UIColor whiteColor];
// need to tell CollectionView beforehand the cell class you want to use
[self.collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"cellID"];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.view addSubview:self.collectionView];
}
-(void)initConstraints
{
self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"collectionView": self.collectionView
};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[collectionView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[collectionView]|" options:0 metrics:nil views:views]];
}
#pragma mark - UICollectionView Methods -
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.items.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// note: reuse identifier must match what you specified in the register cell above
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellID" forIndexPath:indexPath];
// ---------------------------------------------------------------
// hardcoding images here, you might load your images from JSON
// data using an image caching library like SDWebImage
// ---------------------------------------------------------------
cell.leftImage.image = [UIImage imageNamed:@"leftImage.png"];
// getting text data from data source "self.items"
cell.textLabel.text = self.items[indexPath.row];
cell.rightImage.image = [UIImage imageNamed:@"rightImage.png"];
return cell;
}
// ----------------------------------------------------------------
// Tells the collection view the width and height of each cell
// ----------------------------------------------------------------
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize size = CGSizeMake(self.view.frame.size.width, 50.0);
return size;
}
@end
#import <UIKit/UIKit.h>
@interface CustomCell : UICollectionViewCell
@property (nonatomic, strong) UIImageView *leftImage;
@property (nonatomic, strong) UILabel *textLabel;
@property (nonatomic, strong) UIImageView *rightImage;
@end
#import "CustomCell.h"
@implementation CustomCell
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
self.backgroundColor = [UIColor grayColor];
self.leftImage = [[UIImageView alloc] init];
self.leftImage.contentMode = UIViewContentModeScaleAspectFill;
self.leftImage.clipsToBounds = YES;
self.leftImage.layer.cornerRadius = 10.0;
self.textLabel = [[UILabel alloc] init];
self.textLabel.numberOfLines = 0;
self.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.rightImage = [[UIImageView alloc] init];
self.rightImage.contentMode = UIViewContentModeScaleAspectFill;
self.rightImage.layer.cornerRadius = 10.0;
self.rightImage.clipsToBounds = YES;
[self.contentView addSubview:self.leftImage];
[self.contentView addSubview:self.textLabel];
[self.contentView addSubview:self.rightImage];
}
-(void)initConstraints
{
self.leftImage.translatesAutoresizingMaskIntoConstraints = NO;
self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.rightImage.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"leftImage": self.leftImage,
@"textLabel": self.textLabel,
@"rightImage": self.rightImage
};
// horizontal constraints
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[leftImage(20)]-10-[textLabel]-[rightImage(20)]-10-|" options:0 metrics:nil views:views]];
// vertical constraints
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.leftImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.rightImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[leftImage(20)]" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[rightImage(20)]" options:0 metrics:nil views:views]];
}
@end
你最终得到这样的东西:
看起来相同但效率更高:D
不,我没有上传相同的屏幕截图:P
希望有帮助吗?