web-dev-qa-db-ja.com

複数のセクションがある水平スクロールのコレクションビュー

このような画面(Objective C)を開発したい: enter image description here

これにはセクション名があります:

  1. 私たちが愛する新しいゲーム
  2. 私たちが愛する新しいアプリ

どちらも水平スクロールがあり、互いに独立しています。

私の質問は、以下の2つのオプションからこれを実装するために使用する必要がある可能な方法は何ですか。可能な場合は、参照サンプルを提供してください。

  1. 単一のUICollectionViewで、異なるセクション(動的)を使用して同じ動作を実現できますか?ただし、異なるセクションのスクロールは独立している必要があります。セクション1のアイテム(行)の数が異なる可能性があり、セクション2のアイテム(行)の数が異なる可能性があるためです。
  2. プログラムで複数のcollectionviewを取得し、それをuiscrollview(垂直スクロールビュー)に挿入する必要がありますか?次に、abdは水平スクロールを定義し、collectionviewにタグを付けてセルにアイテムを追加します。

私は現在、以下のコードによる水平スクロールでコレクションビューを実行していました:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
    _collectionView=[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
    [_collectionView setDataSource:self];
    [_collectionView setDelegate:self];

    [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
    [_collectionView setBackgroundColor:[UIColor redColor]];

    [self.view addSubview:_collectionView];

    // Do any additional setup after loading the view, typically from a nib.
}

#pragma mark Collection View Methods

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 15;
}

// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];

    cell.backgroundColor=[UIColor greenColor];
    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(50, 50);
}

助けてください。

6
ios developer

あなたがやろうとしていることはそれほど難しいことではありません。私はあなたが見ているもののプロトタイプを作成しました。これがあなたのstoryboard's view controllerとそのドキュメントの概要は次のようになります。

Storyboard

各コンポーネントのコードは次のとおりです

TableViewController

class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

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

func numberOfSections(in tableView: UITableView) -> Int {
    return 5
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! MyTableViewCell

    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 160
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return (section%2 == 0) ? "Games we love" : "Apps we love"
}
}

MyTableViewCell

class MyTableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

@IBOutlet weak var collectionView: UICollectionView!

let imageNames = ["candy_crush", "cut_the_ropes", "game_1", "little_pet_shop", "zuba"]
let gameNames  = ["Candy Crush", "Cut the Ropes", "Arbitrary Game 1", "Littlest Pet Shop", "Zuba"]

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return imageNames.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as! MyCollectionViewCell
    cell.imageView.image  = UIImage.init(named: imageNames[indexPath.row])
    cell.titleLabel.text  = gameNames[indexPath.row]
    cell.detailLabel.text = "Games"

    return cell
}
}

MyCollectionViewCell

class MyCollectionViewCell: UICollectionViewCell {

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var detailLabel: UILabel!
}

これがシミュレーターでどのように見えるかです

enter image description here

16
Adeel

回避策(Swift 4)でUICollectionViewを使用)

同じ問題に直面していて、UICollectionViewFlowLayoutで機能させる方法が見つかりません。

UICollectionViewを使用したいが、SupplementaryViewの柔軟性が十分でない場合は、次の回避策を実行できます。

UILabelの左上に固定のCollectionViewがあり、それに応じて右に移動する1つのフローティングUILabelがあります。表示されているセクションが1つしかない場合は、2番目のラベルが非表示になります

collectionView:cellForItemAt indexPath:メソッドで作成/デキューされているすべてのセルをインターセプトできますが、多くのセルフレームが提供されます(それらの多くは準備されていますが、画面外にあり、どのフレームがどのセクションに対応するかを管理する必要があります。水平スクロールコレクションビューに複数の行がある場合、これは注意が必要です。

最小のx座標を見つけるには、セクションとセルフレームをインターセプトする必要があります。最も信頼できる方法は、collectionViewの.visibleCellsプロパティを調べることです。これは(目に見えるセルの数に応じて)多くの反復になる可能性があり、より効率的な方法を特定したいと思います。 (デリゲートメソッド、CollectionViewCellsDidAppearの種類の通知、または.visibleCellsプロパティにオブザーバーを追加できること(読み取り専用であるため不可能)

これまでのところ、これは機能しますが(Swift 4)、改善の余地があります。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID", for: indexPath) as! GalleryCell
    cell.label?.text = String((itemsArrays[indexPath.section][indexPath.row]))
    var pointsDict = Dictionary<Int, CGFloat>()
    for item in collectionView.visibleCells {
        let point = item.convert(CGPoint.zero, to: self.superview)
        let section = collectionView.indexPath(for: item)!.section
        if pointsDict[section] != nil {
            if point.x < pointsDict[section]! {
                pointsDict[section] = point.x
            }
        } else {
            pointsDict[section] = point.x
        }
    }
    updateLabels(dict: pointsDict)
    return cell
}

このコードは、表示されるセクション(キー)と各セクション(値)の最小のx座標を含む辞書を提供し、フローティングラベル2を整列させます(私のlabel1のコレクションビューの左側には固定のxがあります)。それに応じてラベルをアニメーション化、非表示/表示することもできます

この回避策は最適ではありません。UICollectionViewFlowLayoutを使用したソリューションの場合は、追加情報を投稿します。

0
eharo2