Improve travel album list selection layout

This commit is contained in:
2026-07-10 11:33:44 +08:00
parent b6d3207665
commit c03a625409
2 changed files with 53 additions and 15 deletions

View File

@ -23,8 +23,10 @@ final class TravelAlbumDetailViewController: BaseViewController {
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<Int, TravelAlbumMaterial>!
private let bottomBar = UIView()
private let bottomActionStack = UIStackView()
private let deleteSelectedButton = UIButton(type: .system)
private let uploadButton = UIButton(type: .system)
private var isDeleteSelectedButtonVisible = false
init(albumId: Int, api: any TravelAlbumServing = NetworkServices.shared.travelAlbumAPI) {
viewModel = TravelAlbumDetailViewModel(albumId: albumId)
@ -85,9 +87,12 @@ final class TravelAlbumDetailViewController: BaseViewController {
}
bottomBar.backgroundColor = AppColor.pageBackground
bottomActionStack.axis = .vertical
bottomActionStack.spacing = 8
configureBottomButton(deleteSelectedButton, title: "删除选中(0)", color: UIColor(hex: 0xE53935))
configureBottomButton(uploadButton, title: "上传照片", color: AppColor.primary)
deleteSelectedButton.isHidden = true
deleteSelectedButton.alpha = 0
view.addSubview(scrollContainer)
scrollContainer.addSubview(infoCard)
@ -99,24 +104,25 @@ final class TravelAlbumDetailViewController: BaseViewController {
manageCard.addSubview(selectButton)
manageCard.addSubview(collectionView)
view.addSubview(bottomBar)
bottomBar.addSubview(deleteSelectedButton)
bottomBar.addSubview(uploadButton)
bottomBar.addSubview(bottomActionStack)
bottomActionStack.addArrangedSubview(deleteSelectedButton)
bottomActionStack.addArrangedSubview(uploadButton)
}
override func setupConstraints() {
bottomBar.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview()
}
deleteSelectedButton.snp.makeConstraints { make in
bottomActionStack.snp.makeConstraints { make in
make.top.equalToSuperview().offset(12)
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
make.top.equalTo(deleteSelectedButton.snp.bottom).offset(8)
make.leading.trailing.equalTo(deleteSelectedButton)
make.height.equalTo(48)
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-12)
make.height.equalTo(48).priority(.high)
}
scrollContainer.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide).offset(12)
@ -189,12 +195,15 @@ final class TravelAlbumDetailViewController: BaseViewController {
selectButton.isHidden = viewModel.selectedTab != .all
selectButton.setImage(UIImage(systemName: viewModel.isSelectionMode ? "checkmark.circle.fill" : "circle"), for: .normal)
selectButton.tintColor = viewModel.isSelectionMode ? AppColor.primary : AppColor.textTertiary
deleteSelectedButton.isHidden = !(viewModel.isSelectionMode && !viewModel.selectedMaterialIds.isEmpty)
deleteSelectedButton.setTitle("删除选中(\(viewModel.selectedMaterialIds.count))", for: .normal)
setDeleteSelectedButtonVisible(viewModel.isSelectionMode && !viewModel.selectedMaterialIds.isEmpty)
var snapshot = NSDiffableDataSourceSnapshot<Int, TravelAlbumMaterial>()
snapshot.appendSections([0])
snapshot.appendItems(viewModel.materials)
if !snapshot.itemIdentifiers.isEmpty {
snapshot.reconfigureItems(snapshot.itemIdentifiers)
}
dataSource.apply(snapshot, animatingDifferences: true)
if viewModel.isLoading && viewModel.album == nil {
@ -231,6 +240,29 @@ final class TravelAlbumDetailViewController: BaseViewController {
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 {
UICollectionViewCompositionalLayout { _, environment in
let spacing: CGFloat = 8

View File

@ -42,7 +42,7 @@ final class TravelAlbumEntryViewController: BaseViewController {
tableView.backgroundColor = .white
tableView.separatorStyle = .none
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 132
tableView.estimatedRowHeight = 148
tableView.delegate = self
tableView.register(TravelAlbumTaskCell.self, forCellReuseIdentifier: TravelAlbumTaskCell.reuseIdentifier)
@ -305,10 +305,14 @@ private final class TravelAlbumTaskCell: UITableViewCell {
nameLabel.font = .systemFont(ofSize: 16, weight: .bold)
nameLabel.textColor = AppColor.textPrimary
nameLabel.numberOfLines = 1
timeLabel.font = .systemFont(ofSize: 12)
timeLabel.textColor = AppColor.textTertiary
timeLabel.numberOfLines = 1
phoneLabel.font = .systemFont(ofSize: 12)
phoneLabel.textColor = AppColor.textTertiary
phoneLabel.numberOfLines = 1
phoneLabel.setContentCompressionResistancePriority(.required, for: .vertical)
shareButton.setImage(UIImage(systemName: "square.and.arrow.up"), for: .normal)
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))
}
coverView.snp.makeConstraints { make in
make.leading.top.bottom.equalToSuperview().inset(10)
make.size.equalTo(86)
make.leading.top.bottom.equalToSuperview().inset(12)
make.size.equalTo(112)
}
iconView.snp.makeConstraints { make in
make.center.equalToSuperview()
@ -360,16 +364,18 @@ private final class TravelAlbumTaskCell: UITableViewCell {
}
timeLabel.snp.makeConstraints { make in
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
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
make.top.equalTo(phoneLabel.snp.bottom).offset(9)
make.trailing.equalToSuperview().offset(-10)
make.bottom.equalToSuperview().offset(-10)
make.bottom.equalToSuperview().offset(-12)
make.height.equalTo(34)
make.width.greaterThanOrEqualTo(104)
}