Improve travel album list selection layout
This commit is contained in:
@ -23,8 +23,10 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
|||||||
private var collectionView: UICollectionView!
|
private var collectionView: UICollectionView!
|
||||||
private var dataSource: UICollectionViewDiffableDataSource<Int, TravelAlbumMaterial>!
|
private var dataSource: UICollectionViewDiffableDataSource<Int, TravelAlbumMaterial>!
|
||||||
private let bottomBar = UIView()
|
private let bottomBar = UIView()
|
||||||
|
private let bottomActionStack = UIStackView()
|
||||||
private let deleteSelectedButton = UIButton(type: .system)
|
private let deleteSelectedButton = UIButton(type: .system)
|
||||||
private let uploadButton = UIButton(type: .system)
|
private let uploadButton = UIButton(type: .system)
|
||||||
|
private var isDeleteSelectedButtonVisible = false
|
||||||
|
|
||||||
init(albumId: Int, api: any TravelAlbumServing = NetworkServices.shared.travelAlbumAPI) {
|
init(albumId: Int, api: any TravelAlbumServing = NetworkServices.shared.travelAlbumAPI) {
|
||||||
viewModel = TravelAlbumDetailViewModel(albumId: albumId)
|
viewModel = TravelAlbumDetailViewModel(albumId: albumId)
|
||||||
@ -85,9 +87,12 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bottomBar.backgroundColor = AppColor.pageBackground
|
bottomBar.backgroundColor = AppColor.pageBackground
|
||||||
|
bottomActionStack.axis = .vertical
|
||||||
|
bottomActionStack.spacing = 8
|
||||||
configureBottomButton(deleteSelectedButton, title: "删除选中(0)", color: UIColor(hex: 0xE53935))
|
configureBottomButton(deleteSelectedButton, title: "删除选中(0)", color: UIColor(hex: 0xE53935))
|
||||||
configureBottomButton(uploadButton, title: "上传照片", color: AppColor.primary)
|
configureBottomButton(uploadButton, title: "上传照片", color: AppColor.primary)
|
||||||
deleteSelectedButton.isHidden = true
|
deleteSelectedButton.isHidden = true
|
||||||
|
deleteSelectedButton.alpha = 0
|
||||||
|
|
||||||
view.addSubview(scrollContainer)
|
view.addSubview(scrollContainer)
|
||||||
scrollContainer.addSubview(infoCard)
|
scrollContainer.addSubview(infoCard)
|
||||||
@ -99,24 +104,25 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
|||||||
manageCard.addSubview(selectButton)
|
manageCard.addSubview(selectButton)
|
||||||
manageCard.addSubview(collectionView)
|
manageCard.addSubview(collectionView)
|
||||||
view.addSubview(bottomBar)
|
view.addSubview(bottomBar)
|
||||||
bottomBar.addSubview(deleteSelectedButton)
|
bottomBar.addSubview(bottomActionStack)
|
||||||
bottomBar.addSubview(uploadButton)
|
bottomActionStack.addArrangedSubview(deleteSelectedButton)
|
||||||
|
bottomActionStack.addArrangedSubview(uploadButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setupConstraints() {
|
override func setupConstraints() {
|
||||||
bottomBar.snp.makeConstraints { make in
|
bottomBar.snp.makeConstraints { make in
|
||||||
make.leading.trailing.bottom.equalToSuperview()
|
make.leading.trailing.bottom.equalToSuperview()
|
||||||
}
|
}
|
||||||
deleteSelectedButton.snp.makeConstraints { make in
|
bottomActionStack.snp.makeConstraints { make in
|
||||||
make.top.equalToSuperview().offset(12)
|
make.top.equalToSuperview().offset(12)
|
||||||
make.leading.trailing.equalToSuperview().inset(20)
|
make.leading.trailing.equalToSuperview().inset(20)
|
||||||
make.height.equalTo(48)
|
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-12)
|
||||||
|
}
|
||||||
|
deleteSelectedButton.snp.makeConstraints { make in
|
||||||
|
make.height.equalTo(48).priority(.high)
|
||||||
}
|
}
|
||||||
uploadButton.snp.makeConstraints { make in
|
uploadButton.snp.makeConstraints { make in
|
||||||
make.top.equalTo(deleteSelectedButton.snp.bottom).offset(8)
|
make.height.equalTo(48).priority(.high)
|
||||||
make.leading.trailing.equalTo(deleteSelectedButton)
|
|
||||||
make.height.equalTo(48)
|
|
||||||
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-12)
|
|
||||||
}
|
}
|
||||||
scrollContainer.snp.makeConstraints { make in
|
scrollContainer.snp.makeConstraints { make in
|
||||||
make.top.equalTo(view.safeAreaLayoutGuide).offset(12)
|
make.top.equalTo(view.safeAreaLayoutGuide).offset(12)
|
||||||
@ -189,12 +195,15 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
|||||||
selectButton.isHidden = viewModel.selectedTab != .all
|
selectButton.isHidden = viewModel.selectedTab != .all
|
||||||
selectButton.setImage(UIImage(systemName: viewModel.isSelectionMode ? "checkmark.circle.fill" : "circle"), for: .normal)
|
selectButton.setImage(UIImage(systemName: viewModel.isSelectionMode ? "checkmark.circle.fill" : "circle"), for: .normal)
|
||||||
selectButton.tintColor = viewModel.isSelectionMode ? AppColor.primary : AppColor.textTertiary
|
selectButton.tintColor = viewModel.isSelectionMode ? AppColor.primary : AppColor.textTertiary
|
||||||
deleteSelectedButton.isHidden = !(viewModel.isSelectionMode && !viewModel.selectedMaterialIds.isEmpty)
|
|
||||||
deleteSelectedButton.setTitle("删除选中(\(viewModel.selectedMaterialIds.count))", for: .normal)
|
deleteSelectedButton.setTitle("删除选中(\(viewModel.selectedMaterialIds.count))", for: .normal)
|
||||||
|
setDeleteSelectedButtonVisible(viewModel.isSelectionMode && !viewModel.selectedMaterialIds.isEmpty)
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Int, TravelAlbumMaterial>()
|
var snapshot = NSDiffableDataSourceSnapshot<Int, TravelAlbumMaterial>()
|
||||||
snapshot.appendSections([0])
|
snapshot.appendSections([0])
|
||||||
snapshot.appendItems(viewModel.materials)
|
snapshot.appendItems(viewModel.materials)
|
||||||
|
if !snapshot.itemIdentifiers.isEmpty {
|
||||||
|
snapshot.reconfigureItems(snapshot.itemIdentifiers)
|
||||||
|
}
|
||||||
dataSource.apply(snapshot, animatingDifferences: true)
|
dataSource.apply(snapshot, animatingDifferences: true)
|
||||||
|
|
||||||
if viewModel.isLoading && viewModel.album == nil {
|
if viewModel.isLoading && viewModel.album == nil {
|
||||||
@ -231,6 +240,29 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
|||||||
button.layer.cornerRadius = 10
|
button.layer.cornerRadius = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func setDeleteSelectedButtonVisible(_ visible: Bool) {
|
||||||
|
guard visible != isDeleteSelectedButtonVisible else { return }
|
||||||
|
isDeleteSelectedButtonVisible = visible
|
||||||
|
|
||||||
|
let changes = {
|
||||||
|
self.deleteSelectedButton.isHidden = !visible
|
||||||
|
self.deleteSelectedButton.alpha = visible ? 1 : 0
|
||||||
|
self.view.layoutIfNeeded()
|
||||||
|
}
|
||||||
|
guard view.window != nil else {
|
||||||
|
changes()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
view.layoutIfNeeded()
|
||||||
|
UIView.animate(
|
||||||
|
withDuration: 0.25,
|
||||||
|
delay: 0,
|
||||||
|
options: [.curveEaseInOut, .beginFromCurrentState],
|
||||||
|
animations: changes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private func makeLayout() -> UICollectionViewCompositionalLayout {
|
private func makeLayout() -> UICollectionViewCompositionalLayout {
|
||||||
UICollectionViewCompositionalLayout { _, environment in
|
UICollectionViewCompositionalLayout { _, environment in
|
||||||
let spacing: CGFloat = 8
|
let spacing: CGFloat = 8
|
||||||
|
|||||||
@ -42,7 +42,7 @@ final class TravelAlbumEntryViewController: BaseViewController {
|
|||||||
tableView.backgroundColor = .white
|
tableView.backgroundColor = .white
|
||||||
tableView.separatorStyle = .none
|
tableView.separatorStyle = .none
|
||||||
tableView.rowHeight = UITableView.automaticDimension
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
tableView.estimatedRowHeight = 132
|
tableView.estimatedRowHeight = 148
|
||||||
tableView.delegate = self
|
tableView.delegate = self
|
||||||
tableView.register(TravelAlbumTaskCell.self, forCellReuseIdentifier: TravelAlbumTaskCell.reuseIdentifier)
|
tableView.register(TravelAlbumTaskCell.self, forCellReuseIdentifier: TravelAlbumTaskCell.reuseIdentifier)
|
||||||
|
|
||||||
@ -305,10 +305,14 @@ private final class TravelAlbumTaskCell: UITableViewCell {
|
|||||||
|
|
||||||
nameLabel.font = .systemFont(ofSize: 16, weight: .bold)
|
nameLabel.font = .systemFont(ofSize: 16, weight: .bold)
|
||||||
nameLabel.textColor = AppColor.textPrimary
|
nameLabel.textColor = AppColor.textPrimary
|
||||||
|
nameLabel.numberOfLines = 1
|
||||||
timeLabel.font = .systemFont(ofSize: 12)
|
timeLabel.font = .systemFont(ofSize: 12)
|
||||||
timeLabel.textColor = AppColor.textTertiary
|
timeLabel.textColor = AppColor.textTertiary
|
||||||
|
timeLabel.numberOfLines = 1
|
||||||
phoneLabel.font = .systemFont(ofSize: 12)
|
phoneLabel.font = .systemFont(ofSize: 12)
|
||||||
phoneLabel.textColor = AppColor.textTertiary
|
phoneLabel.textColor = AppColor.textTertiary
|
||||||
|
phoneLabel.numberOfLines = 1
|
||||||
|
phoneLabel.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
|
|
||||||
shareButton.setImage(UIImage(systemName: "square.and.arrow.up"), for: .normal)
|
shareButton.setImage(UIImage(systemName: "square.and.arrow.up"), for: .normal)
|
||||||
shareButton.tintColor = AppColor.primary
|
shareButton.tintColor = AppColor.primary
|
||||||
@ -336,8 +340,8 @@ private final class TravelAlbumTaskCell: UITableViewCell {
|
|||||||
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 6, left: 20, bottom: 6, right: 20))
|
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 6, left: 20, bottom: 6, right: 20))
|
||||||
}
|
}
|
||||||
coverView.snp.makeConstraints { make in
|
coverView.snp.makeConstraints { make in
|
||||||
make.leading.top.bottom.equalToSuperview().inset(10)
|
make.leading.top.bottom.equalToSuperview().inset(12)
|
||||||
make.size.equalTo(86)
|
make.size.equalTo(112)
|
||||||
}
|
}
|
||||||
iconView.snp.makeConstraints { make in
|
iconView.snp.makeConstraints { make in
|
||||||
make.center.equalToSuperview()
|
make.center.equalToSuperview()
|
||||||
@ -360,16 +364,18 @@ private final class TravelAlbumTaskCell: UITableViewCell {
|
|||||||
}
|
}
|
||||||
timeLabel.snp.makeConstraints { make in
|
timeLabel.snp.makeConstraints { make in
|
||||||
make.top.equalTo(nameLabel.snp.bottom).offset(7)
|
make.top.equalTo(nameLabel.snp.bottom).offset(7)
|
||||||
make.leading.trailing.equalTo(nameLabel)
|
make.leading.equalTo(nameLabel)
|
||||||
|
make.trailing.equalToSuperview().offset(-12)
|
||||||
}
|
}
|
||||||
phoneLabel.snp.makeConstraints { make in
|
phoneLabel.snp.makeConstraints { make in
|
||||||
make.top.equalTo(timeLabel.snp.bottom).offset(5)
|
make.top.equalTo(timeLabel.snp.bottom).offset(5)
|
||||||
make.leading.trailing.equalTo(nameLabel)
|
make.leading.equalTo(nameLabel)
|
||||||
|
make.trailing.equalToSuperview().offset(-12)
|
||||||
}
|
}
|
||||||
uploadButton.snp.makeConstraints { make in
|
uploadButton.snp.makeConstraints { make in
|
||||||
make.top.equalTo(phoneLabel.snp.bottom).offset(9)
|
make.top.equalTo(phoneLabel.snp.bottom).offset(9)
|
||||||
make.trailing.equalToSuperview().offset(-10)
|
make.trailing.equalToSuperview().offset(-10)
|
||||||
make.bottom.equalToSuperview().offset(-10)
|
make.bottom.equalToSuperview().offset(-12)
|
||||||
make.height.equalTo(34)
|
make.height.equalTo(34)
|
||||||
make.width.greaterThanOrEqualTo(104)
|
make.width.greaterThanOrEqualTo(104)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user