Skip to content
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 66 additions & 38 deletions Sources/AloeStackView/AloeStackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,35 +64,39 @@ open class AloeStackView: UIScrollView {
/// Adds a row to the end of the stack view.
///
/// If `animated` is `true`, the insertion is animated.
open func addRow(_ row: UIView, animated: Bool = false) {
insertCell(withContentView: row, atIndex: stackView.arrangedSubviews.count, animated: animated)
open func addRow(_ row: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
insertCell(withContentView: row, atIndex: stackView.arrangedSubviews.count, animated: animated, completion: completion)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please wrap multiple statements onto separate lines

insertCell(
  withContentView: row, 
  atIndex: stackView.arrangedSubviews.count, 
  animated: animated, 
  completion: completion)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above comment

}

/// Adds multiple rows to the end of the stack view.
///
/// If `animated` is `true`, the insertions are animated.
open func addRows(_ rows: [UIView], animated: Bool = false) {
rows.forEach { addRow($0, animated: animated) }
open func addRows(_ rows: [UIView], animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
rows.forEach { group.enter(); addRow($0, animated: animated) { _ in group.leave() } }
group.notify(queue: .main) { completion?(true) }
}

/// Adds a row to the beginning of the stack view.
///
/// If `animated` is `true`, the insertion is animated.
open func prependRow(_ row: UIView, animated: Bool = false) {
insertCell(withContentView: row, atIndex: 0, animated: animated)
open func prependRow(_ row: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
insertCell(withContentView: row, atIndex: 0, animated: animated, completion: completion)
}

/// Adds multiple rows to the beginning of the stack view.
///
/// If `animated` is `true`, the insertions are animated.
open func prependRows(_ rows: [UIView], animated: Bool = false) {
rows.reversed().forEach { prependRow($0, animated: animated) }
open func prependRows(_ rows: [UIView], animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please wrap these function signatures on to multiple lines

open func prependRows(
    _ rows: [UIView],
    animated: Bool = false,
    completion: ((Bool) -> Void)? = nil)
{

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i broke the line of function name that longer then 110 characters.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

however, here is my break line style.

open func prependRows(_ rows: [UIView],
                      animated: Bool = false,
                      completion: ((Bool) -> Void)? = nil) {
       // code is here
}

if you don't like this style please commit the additional feedback. i will apply as soon as possible.

let group = DispatchGroup()
rows.reversed().forEach { group.enter(); prependRow($0, animated: animated) { _ in group.leave() } }
group.notify(queue: .main) { completion?(true) }
}

/// Inserts a row above the specified row in the stack view.
///
/// If `animated` is `true`, the insertion is animated.
open func insertRow(_ row: UIView, before beforeRow: UIView, animated: Bool = false) {
open func insertRow(_ row: UIView, before beforeRow: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
#if swift(>=5.0)
guard
let cell = beforeRow.superview as? StackViewCell,
Expand All @@ -102,20 +106,22 @@ open class AloeStackView: UIScrollView {
let cell = beforeRow.superview as? StackViewCell,
let index = stackView.arrangedSubviews.index(of: cell) else { return }
#endif
insertCell(withContentView: row, atIndex: index, animated: animated)
insertCell(withContentView: row, atIndex: index, animated: animated, completion: completion)
}

/// Inserts multiple rows above the specified row in the stack view.
///
/// If `animated` is `true`, the insertions are animated.
open func insertRows(_ rows: [UIView], before beforeRow: UIView, animated: Bool = false) {
rows.forEach { insertRow($0, before: beforeRow, animated: animated) }
open func insertRows(_ rows: [UIView], before beforeRow: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
rows.forEach { group.enter(); insertRow($0, before: beforeRow, animated: animated) { _ in group.leave() } }
group.notify(queue: .main) { completion?(true) }
}

/// Inserts a row below the specified row in the stack view.
///
/// If `animated` is `true`, the insertion is animated.
open func insertRow(_ row: UIView, after afterRow: UIView, animated: Bool = false) {
open func insertRow(_ row: UIView, after afterRow: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
#if swift(>=5.0)
guard
let cell = afterRow.superview as? StackViewCell,
Expand All @@ -125,44 +131,52 @@ open class AloeStackView: UIScrollView {
let cell = afterRow.superview as? StackViewCell,
let index = stackView.arrangedSubviews.index(of: cell) else { return }
#endif
insertCell(withContentView: row, atIndex: index + 1, animated: animated)
insertCell(withContentView: row, atIndex: index + 1, animated: animated, completion: completion)
}

/// Inserts multiple rows below the specified row in the stack view.
///
/// If `animated` is `true`, the insertions are animated.
open func insertRows(_ rows: [UIView], after afterRow: UIView, animated: Bool = false) {
open func insertRows(_ rows: [UIView], after afterRow: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
_ = rows.reduce(afterRow) { currentAfterRow, row in
insertRow(row, after: currentAfterRow, animated: animated)
group.enter()
insertRow(row, after: currentAfterRow, animated: animated) { _ in group.leave() }
return row
}
group.notify(queue: .main) { completion?(true) }
}

/// Removes the given row from the stack view.
///
/// If `animated` is `true`, the removal is animated.
open func removeRow(_ row: UIView, animated: Bool = false) {
open func removeRow(_ row: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
if let cell = row.superview as? StackViewCell {
removeCell(cell, animated: animated)
removeCell(cell, animated: animated, completion: completion)
}
}

/// Removes the given rows from the stack view.
///
/// If `animated` is `true`, the removals are animated.
open func removeRows(_ rows: [UIView], animated: Bool = false) {
rows.forEach { removeRow($0, animated: animated) }
open func removeRows(_ rows: [UIView], animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
rows.forEach { group.enter(); removeRow($0, animated: animated) { _ in group.leave() } }
group.notify(queue: .main) { completion?(true) }
}

/// Removes all the rows in the stack view.
///
/// If `animated` is `true`, the removals are animated.
open func removeAllRows(animated: Bool = false) {
open func removeAllRows(animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
stackView.arrangedSubviews.forEach { view in
if let cell = view as? StackViewCell {
removeRow(cell.contentView, animated: animated)
group.enter()
removeRow(cell.contentView, animated: animated) { _ in group.leave() }
}
}
group.notify(queue: .main) { completion?(true) }
}

// MARK: Accessing Rows
Expand Down Expand Up @@ -205,53 +219,62 @@ open class AloeStackView: UIScrollView {
/// Hides the given row, making it invisible.
///
/// If `animated` is `true`, the change is animated.
open func hideRow(_ row: UIView, animated: Bool = false) {
setRowHidden(row, isHidden: true, animated: animated)
open func hideRow(_ row: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
setRowHidden(row, isHidden: true, animated: animated, completion: completion)
}

/// Hides the given rows, making them invisible.
///
/// If `animated` is `true`, the changes are animated.
open func hideRows(_ rows: [UIView], animated: Bool = false) {
rows.forEach { hideRow($0, animated: animated) }
open func hideRows(_ rows: [UIView], animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
rows.forEach { group.enter(); hideRow($0, animated: animated) { _ in group.leave() } }
group.notify(queue: .main) { completion?(true) }
}

/// Shows the given row, making it visible.
///
/// If `animated` is `true`, the change is animated.
open func showRow(_ row: UIView, animated: Bool = false) {
setRowHidden(row, isHidden: false, animated: animated)
open func showRow(_ row: UIView, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
setRowHidden(row, isHidden: false, animated: animated, completion: completion)
}

/// Shows the given rows, making them visible.
///
/// If `animated` is `true`, the changes are animated.
open func showRows(_ rows: [UIView], animated: Bool = false) {
rows.forEach { showRow($0, animated: animated) }
open func showRows(_ rows: [UIView], animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
rows.forEach { group.enter(); showRow($0, animated: animated) { _ in group.leave() } }
group.notify(queue: .main) { completion?(true) }
}

/// Hides the given row if `isHidden` is `true`, or shows the given row if `isHidden` is `false`.
///
/// If `animated` is `true`, the change is animated.
open func setRowHidden(_ row: UIView, isHidden: Bool, animated: Bool = false) {
open func setRowHidden(_ row: UIView, isHidden: Bool, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
guard let cell = row.superview as? StackViewCell, cell.isHidden != isHidden else { return }

if animated {
UIView.animate(withDuration: 0.3) {
UIView.animate(withDuration: 0.3, animations: {
cell.isHidden = isHidden
cell.layoutIfNeeded()
}) { flag in
completion?(flag)
}
} else {
cell.isHidden = isHidden
completion?(true)
}
}

/// Hides the given rows if `isHidden` is `true`, or shows the given rows if `isHidden` is
/// `false`.
///
/// If `animated` is `true`, the change are animated.
open func setRowsHidden(_ rows: [UIView], isHidden: Bool, animated: Bool = false) {
rows.forEach { setRowHidden($0, isHidden: isHidden, animated: animated) }
open func setRowsHidden(_ rows: [UIView], isHidden: Bool, animated: Bool = false, completion: ((Bool) -> Void)? = nil) {
let group = DispatchGroup()
rows.forEach { group.enter(); setRowHidden($0, isHidden: isHidden, animated: animated) { _ in group.leave() } }
group.notify(queue: .main) { completion?(true) }
}

/// Returns `true` if the given row is hidden, `false` otherwise.
Expand Down Expand Up @@ -529,7 +552,7 @@ open class AloeStackView: UIScrollView {
return cell
}

private func insertCell(withContentView contentView: UIView, atIndex index: Int, animated: Bool) {
private func insertCell(withContentView contentView: UIView, atIndex index: Int, animated: Bool, completion: ((Bool) -> Void)? = nil) {
let cellToRemove = containsRow(contentView) ? contentView.superview : nil

let cell = createCell(withContentView: contentView)
Expand All @@ -551,16 +574,20 @@ open class AloeStackView: UIScrollView {
if animated {
cell.alpha = 0
layoutIfNeeded()
UIView.animate(withDuration: 0.3) {
UIView.animate(withDuration: 0.3, animations: {
cell.alpha = 1
}) { flag in
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little confusing, perhaps we could split this handler out to a separate completionHandler above, like with the removeCell method?

Copy link
Copy Markdown
Author

@blick9 blick9 Aug 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove closure block, just input the argument

completion?(flag)
}
} else {
completion?(true)
}
}

private func removeCell(_ cell: StackViewCell, animated: Bool) {
private func removeCell(_ cell: StackViewCell, animated: Bool, completion: ((Bool) -> Void)? = nil) {
let aboveCell = cellAbove(cell: cell)

let completion: (Bool) -> Void = { [weak self] _ in
let completion: (Bool) -> Void = { [weak self] flag in
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of the handler conflicts with the argument to the method. Perhaps rename the local variable to completionHandler to disambiguate. Also the argument to the function might be better called finished rather than flag.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for your feedback!
i applied all feedbacks. could you check one more time?

guard let `self` = self else { return }
cell.removeFromSuperview()

Expand All @@ -569,6 +596,7 @@ open class AloeStackView: UIScrollView {
if let aboveCell = aboveCell {
self.updateSeparatorVisibility(forCell: aboveCell)
}
completion?(flag)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Insert one blank line above this line.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i did

}

if animated {
Expand Down