ios - UIScrollView 及其子项 : why are they placed on top of each other? (AutoLayout)

标签 ios uiview swift uiscrollview autolayout

我正在开发一款应用,用户可以在其中向订单中添加产品。每个产品都有自己的 UIView,所有这些产品都放在一个 UI 中(并放在一个数组中以供将来引用,如总价等)。我对添加产品并没有做太多花哨的事情:

/* Create the new product */        
var tmp = Product(data: product)
/* Add it to the scrollView */
scrollView.addSubview(tmp)

我正在为 UIScrollView 本身使用 AutoLayout,但没有设置约束(我也已清除它以进行检查)。

澄清一下:Product 是 UIView 的子类,只是为了标准化每个产品的外观。

但是,当我添加超过 1 个产品时,新产品会放置在第一个产品之上,而不是第一个产品之下。我有一种感觉,我错过了使用具有自动布局的 UIScrollView 的关键部分。谁能指出我正确的方向?

编辑:最后我通过创建一个方法来解决它(重新)计算位置,因为我在 UICollectionView 中得到了相同的行为。我在 Android 中开发同一个应用程序,您可以让子元素充当 block (在 CSS 意义上)元素。我固执地在 iOS 中寻找相同的解决方案 :)

最佳答案

当您调用 [scrollView addSubview:productView];

时,UIScrollView 不会自动将您的 subview 定位在正确的位置

在将 subview 添加到 UIScrollView 之前,您需要使用 initWithFrame 告诉 subview 正确的位置,在这种情况下,您似乎正在使用自动布局。

如果您对替代方案持开放态度,我认为 UICollectionView 可以实现您想要的。 Collection View 中的每个“单元格”都是您的产品 View 。 Collection View 具有 ScrollView 的所有功能。

如果您在产品 View 中使用框架,那么您可以这样做:

var view1:UIView = UIView(frame: CGRectMake(0, 0, 320, 480)];

// -----------------------------------------------------------------------
// Notice here, view2 has a Y position that takes the height of view1
//
// So we're telling iOS to put view2 right below view1 before we
// add it as a subview of our scrollView
// -----------------------------------------------------------------------
var view2:UIView = UIView(frame: CGRectMake(0, view1.frame.origin.y, 320, 480));

self.scrollView.addSubview(view1);
self.scrollView.addSubview(view2);

UICollectionView 自动布局演示:

为了完整起见,我将包含一个使用 Swift 的基本 UICollectionView Autolayout 演示。

View Controller

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    var arrItems:NSMutableArray = NSMutableArray();
    var collectionView:UICollectionView?;

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.arrItems.addObject("Apple");
        self.arrItems.addObject("Banana");
        self.arrItems.addObject("Orange");
        self.arrItems.addObject("Mango");
        self.arrItems.addObject("Watermelon");

        initViews();
        initConstraints();
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func initViews()
    {
        // ------------------------------------------------------
        // Init the collection View
        // ------------------------------------------------------

        var flowLayout:UICollectionViewFlowLayout = UICollectionViewFlowLayout();
        flowLayout.itemSize = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height / 2.0);

        self.collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: flowLayout);
        self.collectionView?.registerClass(ProductCell.self, forCellWithReuseIdentifier: "cellID");
        self.collectionView?.delegate = self;
        self.collectionView?.dataSource = self;
        self.collectionView?.backgroundColor = UIColor.whiteColor();
        self.collectionView?.pagingEnabled = true;

        self.view.addSubview(self.collectionView!);
    }

    func initConstraints()
    {
        self.collectionView?.setTranslatesAutoresizingMaskIntoConstraints(false);

        var views:NSMutableDictionary = NSMutableDictionary();

        views.setValue(self.collectionView!, forKey: "collectionView");

        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[collectionView]|", options: nil, metrics: nil, views: views));
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[collectionView]|", options: nil, metrics: nil, views: views));
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {


        return self.arrItems.count;
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        // ---------------------------------------------------
        // Note, Swift is able to detect all developer's own
        // class files, so no need to import ProductCell
        // ---------------------------------------------------

        // create a ProductCell
        var cell:ProductCell = collectionView.dequeueReusableCellWithReuseIdentifier("cellID", forIndexPath: indexPath) as ProductCell;

        // setup product info
        cell.productName.text = self.arrItems[indexPath.row] as NSString;
        cell.productDescription.text = "This is some text about the product. It can be a very long block of text or maybe a really short one. Up to you to design it anyway you like.";

        return cell;
    }

}

产品单元类

import UIKit

class ProductCell: UICollectionViewCell {
    var container:UIView = UIView();
    var productName:UILabel = UILabel();
    var productDescription:UILabel = UILabel();

    override init(frame: CGRect) {
        super.init(frame: frame);

        initViews();
        initConstraints();
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder);
    }

    func initViews()
    {
        self.container.backgroundColor = UIColor.lightGrayColor();
        self.container.layer.cornerRadius = 5.0;

        self.productName.font = UIFont.systemFontOfSize(14);
        self.productName.textColor = UIColor.whiteColor();
        self.productName.textAlignment = NSTextAlignment.Center;
        self.productName.numberOfLines = 0;
        self.productName.setContentHuggingPriority(1000, forAxis: UILayoutConstraintAxis.Vertical);
        self.productName.backgroundColor = UIColor(red: 0.2, green: 0.2, blue: 0.8, alpha: 1.0);
        self.productName.layer.cornerRadius = 5.0;
        self.productName.clipsToBounds = true;

        self.productDescription.font = UIFont.systemFontOfSize(14);
        self.productDescription.numberOfLines = 0;

        self.container.addSubview(self.productName);
        self.container.addSubview(self.productDescription);

        self.contentView.addSubview(self.container);
    }

    func initConstraints()
    {
        self.container.setTranslatesAutoresizingMaskIntoConstraints(false);
        self.productName.setTranslatesAutoresizingMaskIntoConstraints(false);
        self.productDescription.setTranslatesAutoresizingMaskIntoConstraints(false);

        var views:NSMutableDictionary = NSMutableDictionary();
        views.setValue(self.container, forKey: "container");
        views.setValue(self.productName, forKey: "productName");
        views.setValue(self.productDescription, forKey: "productDescription");

        // container constraints
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[container]-20-|", options: nil, metrics: nil, views: views));
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-20-[container]-20-|", options: nil, metrics: nil, views: views));

        // subview constraints

        self.container.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[productName]-10-|", options: nil, metrics: nil, views: views));

        self.container.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[productDescription]-10-|", options: nil, metrics: nil, views: views));

        self.container.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-10-[productName(50)]-10-[productDescription]-10-|", options: nil, metrics: nil, views: views));
    }
}

你应该得到这样的结果:

screenshot of UICollectionView Swift demo

关于ios - UIScrollView 及其子项 : why are they placed on top of each other? (AutoLayout),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26233999/

相关文章:

iphone - UIBackgroundModes位置和显着位置变化随区域监控

ios - 以编程方式将 UICollectionView 嵌套在 UIVIew 中

ios - 从 Swift 函数中的异步调用返回数据

ios - 为什么我的窗口比设备视口(viewport)小?

ios - Xcode 7 - 宏名称必须是标识符

ios - 选择单元格 iOS swift 时的复选框功能

ios - 无法在 Interface Builder 上预览 IBDesignable 自定义组件

objective-c - MKMapView 上的黑盒

ios - 如何在 Xcode 中为 UIView 的宽度和高度设置动画?

Swift 编译器无法区分两个初始化器