默认情况下,当您在集合视图中使用流布局时,单元是垂直居中。有没有办法改变这种对齐方式?UICollection视图流布局垂直对齐
回答
下面的代码为我工作
@interface TopAlignedCollectionViewFlowLayout : UICollectionViewFlowLayout
- (void)alignToTopForSameLineElements:(NSArray *)sameLineElements;
@end
@implementation TopAlignedCollectionViewFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
{
NSArray *attrs = [super layoutAttributesForElementsInRect:rect];
CGFloat baseline = -2;
NSMutableArray *sameLineElements = [NSMutableArray array];
for (UICollectionViewLayoutAttributes *element in attrs) {
if (element.representedElementCategory == UICollectionElementCategoryCell) {
CGRect frame = element.frame;
CGFloat centerY = CGRectGetMidY(frame);
if (ABS(centerY - baseline) > 1) {
baseline = centerY;
[self alignToTopForSameLineElements:sameLineElements];
[sameLineElements removeAllObjects];
}
[sameLineElements addObject:element];
}
}
[self alignToTopForSameLineElements:sameLineElements];//align one more time for the last line
return attrs;
}
- (void)alignToTopForSameLineElements:(NSArray *)sameLineElements
{
if (sameLineElements.count == 0) {
return;
}
NSArray *sorted = [sameLineElements sortedArrayUsingComparator:^NSComparisonResult(UICollectionViewLayoutAttributes *obj1, UICollectionViewLayoutAttributes *obj2) {
CGFloat height1 = obj1.frame.size.height;
CGFloat height2 = obj2.frame.size.height;
CGFloat delta = height1 - height2;
return delta == 0. ? NSOrderedSame : ABS(delta)/delta;
}];
UICollectionViewLayoutAttributes *tallest = [sorted lastObject];
[sameLineElements enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *obj, NSUInteger idx, BOOL *stop) {
obj.frame = CGRectOffset(obj.frame, 0, tallest.frame.origin.y - obj.frame.origin.y);
}];
}
@end
的UICollectionViewFlowLayout
类是从UICollectionViewLayout
基类派生的。如果你看看documentation for that,你会发现有很多方法可以覆盖,最有可能的选择是layoutAttributesForItemAtIndexPath:
。
如果您重写该方法,则可以让它调用其超级实现,然后调整返回的对象的属性。具体而言,您可能需要调整frame
属性以重新定位该项目,以便它不再居中。
谢谢,我会尝试使用此解决方案。 –
这可能会或可能不适合你的特殊情况下工作,但我有一些运气下列方式继承UICollectionViewFlowLayout
:
@interface CustomFlowLayout : UICollectionViewFlowLayout
@end
@implementation CustomFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
if (nil == attributes.representedElementKind) {
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
currentItemAttributes.frame = CGRectOffset(currentItemAttributes.frame, 0, 0.5 * CGRectGetHeight(currentItemAttributes.frame));
return currentItemAttributes;
}
@end
@DongXu:您的解决方案也为我工作。这里是SWIFT版本,如果它:
class TopAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout
{
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
if let attrs = super.layoutAttributesForElementsInRect(rect)
{
var baseline: CGFloat = -2
var sameLineElements = [UICollectionViewLayoutAttributes]()
for element in attrs
{
if element.representedElementCategory == .Cell
{
let frame = element.frame
let centerY = CGRectGetMidY(frame)
if abs(centerY - baseline) > 1
{
baseline = centerY
TopAlignedCollectionViewFlowLayout.alignToTopForSameLineElements(sameLineElements)
sameLineElements.removeAll()
}
sameLineElements.append(element)
}
}
TopAlignedCollectionViewFlowLayout.alignToTopForSameLineElements(sameLineElements) // align one more time for the last line
return attrs
}
return nil
}
private class func alignToTopForSameLineElements(sameLineElements: [UICollectionViewLayoutAttributes])
{
if sameLineElements.count < 1
{
return
}
let sorted = sameLineElements.sort { (obj1: UICollectionViewLayoutAttributes, obj2: UICollectionViewLayoutAttributes) -> Bool in
let height1 = obj1.frame.size.height
let height2 = obj2.frame.size.height
let delta = height1 - height2
return delta <= 0
}
if let tallest = sorted.last
{
for obj in sameLineElements
{
obj.frame = CGRectOffset(obj.frame, 0, tallest.frame.origin.y - obj.frame.origin.y)
}
}
}
}
你可以像下面那样去掉for循环中的'if'子句:for元素中的attrs where元素。representElementCategory == .cell {。 。 。 } – kikettas
我后东旭的解决方案也不太工作中使用此代码(https://github.com/yoeriboven/TopAlignedCollectionViewLayout)。唯一的修改是,它最初被设计为与电网中使用,所以我需要一个任意高的列数来实例化布局...
let collectionViewFlowLayout = YBTopAlignedCollectionViewFlowLayout(numColumns: 1000)
斯威夫特3版本,以防有人只是想复制粘贴&:
class TopAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
if let attrs = super.layoutAttributesForElements(in: rect) {
var baseline: CGFloat = -2
var sameLineElements = [UICollectionViewLayoutAttributes]()
for element in attrs {
if element.representedElementCategory == .cell {
let frame = element.frame
let centerY = frame.midY
if abs(centerY - baseline) > 1 {
baseline = centerY
alignToTopForSameLineElements(sameLineElements: sameLineElements)
sameLineElements.removeAll()
}
sameLineElements.append(element)
}
}
alignToTopForSameLineElements(sameLineElements: sameLineElements) // align one more time for the last line
return attrs
}
return nil
}
private func alignToTopForSameLineElements(sameLineElements: [UICollectionViewLayoutAttributes]) {
if sameLineElements.count < 1 { return }
let sorted = sameLineElements.sorted { (obj1: UICollectionViewLayoutAttributes, obj2: UICollectionViewLayoutAttributes) -> Bool in
let height1 = obj1.frame.size.height
let height2 = obj2.frame.size.height
let delta = height1 - height2
return delta <= 0
}
if let tallest = sorted.last {
for obj in sameLineElements {
obj.frame = obj.frame.offsetBy(dx: 0, dy: tallest.frame.origin.y - obj.frame.origin.y)
}
}
}
}
@ DongXu's answer是正确的。但是,我建议在UICollectionViewFlowLayout
的prepare()
方法中进行这些计算。它会阻止对同一个单元的属性进行多次计算。而且,prepare()
是管理属性缓存的好地方。
我已经使用了类似以前的答案。 在我的情况下,我想按不同高度的柱子对齐单元格。
import UIKit
class AlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
if let attributes = super.layoutAttributesForElements(in: rect) {
let sectionElements: [Int : [UICollectionViewLayoutAttributes]] = attributes
.filter {
return $0.representedElementCategory == .cell //take cells only
}.groupBy {
return $0.indexPath.section //group attributes by section
}
sectionElements.forEach { (section, elements) in
//get suplementary view (header) to align each section
let suplementaryView = attributes.first {
return $0.representedElementCategory == .supplementaryView && $0.indexPath.section == section
}
//call align method
alignToTopSameSectionElements(elements, with: suplementaryView)
}
return attributes
}
return super.layoutAttributesForElements(in: rect)
}
private func alignToTopSameSectionElements(_ elements: [UICollectionViewLayoutAttributes], with suplementaryView: UICollectionViewLayoutAttributes?) {
//group attributes by colum
let columElements: [Int : [UICollectionViewLayoutAttributes]] = elements.groupBy {
return Int($0.frame.midX)
}
columElements.enumerated().forEach { (columIndex, object) in
let columElement = object.value.sorted {
return $0.indexPath < $1.indexPath
}
columElement.enumerated().forEach { (index, element) in
var frame = element.frame
if columIndex == 0 {
frame.origin.x = minimumLineSpacing
}
switch index {
case 0:
if let suplementaryView = suplementaryView {
frame.origin.y = suplementaryView.frame.maxY
}
default:
let beforeElement = columElement[index-1]
frame.origin.y = beforeElement.frame.maxY + minimumInteritemSpacing
}
element.frame = frame
}
}
}
}
public extension Array {
func groupBy <U> (groupingFunction group: (Element) -> U) -> [U: Array] {
var result = [U: Array]()
for item in self {
let groupKey = group(item)
if result.has(groupKey) {
result[groupKey]! += [item]
} else {
result[groupKey] = [item]
}
}
return result
}
}
这是此布局的结果是:你想
- 1. 如何像3列布局垂直对齐布局(只是垂直)
- 2. 垂直流动布局
- 3. 智能垂直流布局
- 4. 自动布局子视图垂直
- 5. 在两列布局中垂直对齐图标和文本
- 6. 垂直对齐
- 7. 垂直对齐
- 8. 垂直对齐
- 9. 垂直对齐
- 10. 垂直对齐
- 11. 垂直对齐
- 12. 垂直对齐
- 13. 垂直对齐
- 14. 垂直对齐
- 15. CSS图标垂直对齐
- 16. 图片不垂直对齐?
- 17. 垂直对齐nvd3图例
- 18. 垂直对齐图像
- 19. Bootstrap垂直对齐图像
- 20. 垂直对齐图标
- 21. 相对布局与分组垂直对齐
- 22. 马蒂斯垂直流布局
- 23. 流量容器与VB.NET垂直对齐
- 24. 垂直对齐文本在流体div
- 25. 流体图像,垂直对齐(中间)在宽度流体DIV
- 26. GWT垂直布局
- 27. Dijit垂直布局
- 28. Android - 对齐布局末端的视图
- 29. CSS布局垂直对齐的滚动集装箱
- 30. 在两列布局垂直对齐按钮
什么对准/设计? –
底部对齐(沿着红线)。但底部或顶部,这并不重要,实现它的方式应该是一样的,对吗? –