feat: 美化图片预览工具栏
This commit is contained in:
@@ -129,9 +129,9 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
|
|||||||
forCellWithReuseIdentifier: TravelAlbumPreviewImageCell.reuseIdentifier
|
forCellWithReuseIdentifier: TravelAlbumPreviewImageCell.reuseIdentifier
|
||||||
)
|
)
|
||||||
|
|
||||||
topChrome.backgroundColor = .black
|
topChrome.backgroundColor = UIColor.black.withAlphaComponent(0.82)
|
||||||
topChrome.accessibilityIdentifier = "travelAlbum.previewTopChrome"
|
topChrome.accessibilityIdentifier = "travelAlbum.previewTopChrome"
|
||||||
bottomChrome.backgroundColor = .black
|
bottomChrome.backgroundColor = UIColor.black.withAlphaComponent(0.82)
|
||||||
bottomChrome.accessibilityIdentifier = "travelAlbum.previewBottomChrome"
|
bottomChrome.accessibilityIdentifier = "travelAlbum.previewBottomChrome"
|
||||||
divider.backgroundColor = UIColor.white.withAlphaComponent(0.12)
|
divider.backgroundColor = UIColor.white.withAlphaComponent(0.12)
|
||||||
|
|
||||||
@@ -179,6 +179,15 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
|
|||||||
actionStack.axis = .horizontal
|
actionStack.axis = .horizontal
|
||||||
actionStack.distribution = .fillEqually
|
actionStack.distribution = .fillEqually
|
||||||
actionStack.alignment = .fill
|
actionStack.alignment = .fill
|
||||||
|
actionStack.spacing = 10
|
||||||
|
actionStack.isLayoutMarginsRelativeArrangement = true
|
||||||
|
actionStack.directionalLayoutMargins = NSDirectionalEdgeInsets(
|
||||||
|
top: 9,
|
||||||
|
leading: 0,
|
||||||
|
bottom: 9,
|
||||||
|
trailing: 0
|
||||||
|
)
|
||||||
|
actionStack.accessibilityIdentifier = "travelAlbum.previewActionStack"
|
||||||
configureHighResolutionButton()
|
configureHighResolutionButton()
|
||||||
configureActions()
|
configureActions()
|
||||||
|
|
||||||
@@ -251,7 +260,7 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
actionStack.snp.makeConstraints { make in
|
actionStack.snp.makeConstraints { make in
|
||||||
make.top.equalTo(variantControls.snp.bottom)
|
make.top.equalTo(variantControls.snp.bottom)
|
||||||
make.leading.trailing.equalToSuperview().inset(8)
|
make.leading.trailing.equalToSuperview().inset(16)
|
||||||
make.height.equalTo(70)
|
make.height.equalTo(70)
|
||||||
make.bottom.equalTo(view.safeAreaLayoutGuide)
|
make.bottom.equalTo(view.safeAreaLayoutGuide)
|
||||||
}
|
}
|
||||||
@@ -275,19 +284,30 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func configureActions() {
|
private func configureActions() {
|
||||||
let aiButton = makeActionButton(title: "AI修图", systemName: "tag", color: .white)
|
let aiButton = makeActionButton(
|
||||||
|
title: "AI修图",
|
||||||
|
systemName: "wand.and.stars",
|
||||||
|
foregroundColor: .white,
|
||||||
|
backgroundColor: UIColor(hex: 0x1677FF),
|
||||||
|
strokeColor: UIColor(hex: 0x4096FF)
|
||||||
|
)
|
||||||
|
aiButton.accessibilityIdentifier = "travelAlbum.previewAIRetouchButton"
|
||||||
let deleteConfiguration = makeActionButton(
|
let deleteConfiguration = makeActionButton(
|
||||||
title: "删除",
|
title: "删除",
|
||||||
systemName: "trash",
|
systemName: "trash",
|
||||||
color: .white
|
foregroundColor: UIColor(hex: 0xFF6B6B),
|
||||||
|
backgroundColor: UIColor(hex: 0x211719),
|
||||||
|
strokeColor: UIColor(hex: 0x4A292D)
|
||||||
).configuration
|
).configuration
|
||||||
deleteButton.configuration = deleteConfiguration
|
deleteButton.configuration = deleteConfiguration
|
||||||
deleteButton.accessibilityLabel = "删除"
|
deleteButton.accessibilityLabel = "删除"
|
||||||
deleteButton.accessibilityIdentifier = "travelAlbum.previewDeleteButton"
|
deleteButton.accessibilityIdentifier = "travelAlbum.previewDeleteButton"
|
||||||
refreshButton.configuration = makeActionButton(
|
refreshButton.configuration = makeActionButton(
|
||||||
title: "刷新",
|
title: "刷新",
|
||||||
systemName: "arrow.counterclockwise.circle",
|
systemName: "arrow.clockwise",
|
||||||
color: .white
|
foregroundColor: UIColor.white.withAlphaComponent(0.92),
|
||||||
|
backgroundColor: UIColor(hex: 0x1C1C1E),
|
||||||
|
strokeColor: UIColor.white.withAlphaComponent(0.1)
|
||||||
).configuration
|
).configuration
|
||||||
refreshButton.accessibilityLabel = "刷新"
|
refreshButton.accessibilityLabel = "刷新"
|
||||||
refreshButton.accessibilityIdentifier = "travelAlbum.previewRefreshButton"
|
refreshButton.accessibilityIdentifier = "travelAlbum.previewRefreshButton"
|
||||||
@@ -297,21 +317,31 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
|
|||||||
[aiButton, deleteButton, refreshButton].forEach(actionStack.addArrangedSubview)
|
[aiButton, deleteButton, refreshButton].forEach(actionStack.addArrangedSubview)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeActionButton(title: String, systemName: String, color: UIColor) -> UIButton {
|
private func makeActionButton(
|
||||||
var configuration = UIButton.Configuration.plain()
|
title: String,
|
||||||
|
systemName: String,
|
||||||
|
foregroundColor: UIColor,
|
||||||
|
backgroundColor: UIColor,
|
||||||
|
strokeColor: UIColor
|
||||||
|
) -> UIButton {
|
||||||
|
var configuration = UIButton.Configuration.filled()
|
||||||
configuration.title = title
|
configuration.title = title
|
||||||
configuration.image = UIImage(systemName: systemName)
|
configuration.image = UIImage(systemName: systemName)
|
||||||
configuration.imagePlacement = .top
|
configuration.imagePlacement = .leading
|
||||||
configuration.imagePadding = 8
|
configuration.imagePadding = 7
|
||||||
configuration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(
|
configuration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(
|
||||||
pointSize: 25,
|
pointSize: 18,
|
||||||
weight: .regular
|
weight: .semibold
|
||||||
)
|
)
|
||||||
configuration.baseForegroundColor = color
|
configuration.baseForegroundColor = foregroundColor
|
||||||
configuration.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 6, bottom: 8, trailing: 6)
|
configuration.baseBackgroundColor = backgroundColor
|
||||||
|
configuration.background.cornerRadius = 14
|
||||||
|
configuration.background.strokeColor = strokeColor
|
||||||
|
configuration.background.strokeWidth = 1
|
||||||
|
configuration.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
|
||||||
configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attributes in
|
configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attributes in
|
||||||
var attributes = attributes
|
var attributes = attributes
|
||||||
attributes.font = .systemFont(ofSize: 14, weight: .regular)
|
attributes.font = .systemFont(ofSize: 14, weight: .semibold)
|
||||||
return attributes
|
return attributes
|
||||||
}
|
}
|
||||||
let button = UIButton(configuration: configuration)
|
let button = UIButton(configuration: configuration)
|
||||||
@@ -792,7 +822,7 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
|
|||||||
refreshButton.accessibilityValue = isRefreshingProject ? "刷新中" : nil
|
refreshButton.accessibilityValue = isRefreshingProject ? "刷新中" : nil
|
||||||
var configuration = refreshButton.configuration
|
var configuration = refreshButton.configuration
|
||||||
configuration?.showsActivityIndicator = isRefreshingProject
|
configuration?.showsActivityIndicator = isRefreshingProject
|
||||||
configuration?.image = isRefreshingProject ? nil : UIImage(systemName: "arrow.counterclockwise.circle")
|
configuration?.image = isRefreshingProject ? nil : UIImage(systemName: "arrow.clockwise")
|
||||||
configuration?.title = isRefreshingProject ? "刷新中" : "刷新"
|
configuration?.title = isRefreshingProject ? "刷新中" : "刷新"
|
||||||
refreshButton.configuration = configuration
|
refreshButton.configuration = configuration
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,15 +278,46 @@ final class TravelAlbumDetailViewControllerTests: XCTestCase {
|
|||||||
$0.accessibilityIdentifier == "travelAlbum.previewBackButton"
|
$0.accessibilityIdentifier == "travelAlbum.previewBackButton"
|
||||||
} as? UIButton
|
} as? UIButton
|
||||||
)
|
)
|
||||||
|
let actionStack = try XCTUnwrap(
|
||||||
|
controller.view.findSubview {
|
||||||
|
$0.accessibilityIdentifier == "travelAlbum.previewActionStack"
|
||||||
|
} as? UIStackView
|
||||||
|
)
|
||||||
|
let aiRetouchButton = try XCTUnwrap(
|
||||||
|
controller.view.findSubview {
|
||||||
|
$0.accessibilityIdentifier == "travelAlbum.previewAIRetouchButton"
|
||||||
|
} as? UIButton
|
||||||
|
)
|
||||||
|
let deleteButton = try XCTUnwrap(
|
||||||
|
controller.view.findSubview {
|
||||||
|
$0.accessibilityIdentifier == "travelAlbum.previewDeleteButton"
|
||||||
|
} as? UIButton
|
||||||
|
)
|
||||||
|
let refreshButton = try XCTUnwrap(
|
||||||
|
controller.view.findSubview {
|
||||||
|
$0.accessibilityIdentifier == "travelAlbum.previewRefreshButton"
|
||||||
|
} as? UIButton
|
||||||
|
)
|
||||||
|
|
||||||
XCTAssertFalse(controller.prefersStatusBarHidden)
|
XCTAssertFalse(controller.prefersStatusBarHidden)
|
||||||
XCTAssertEqual(topChrome.backgroundColor, .black)
|
XCTAssertEqual(topChrome.backgroundColor, UIColor.black.withAlphaComponent(0.82))
|
||||||
XCTAssertEqual(bottomChrome.backgroundColor, .black)
|
XCTAssertEqual(bottomChrome.backgroundColor, UIColor.black.withAlphaComponent(0.82))
|
||||||
XCTAssertEqual(highResolutionButton.configuration?.title, "查看高清图")
|
XCTAssertEqual(highResolutionButton.configuration?.title, "查看高清图")
|
||||||
XCTAssertEqual(segmentedControl.numberOfSegments, 3)
|
XCTAssertEqual(segmentedControl.numberOfSegments, 3)
|
||||||
XCTAssertEqual(segmentedControl.selectedSegmentIndex, 0)
|
XCTAssertEqual(segmentedControl.selectedSegmentIndex, 0)
|
||||||
XCTAssertEqual(backButton.bounds.size, CGSize(width: 44, height: 44))
|
XCTAssertEqual(backButton.bounds.size, CGSize(width: 44, height: 44))
|
||||||
XCTAssertNil(backButton.configuration?.baseBackgroundColor)
|
XCTAssertNil(backButton.configuration?.baseBackgroundColor)
|
||||||
|
XCTAssertEqual(actionStack.spacing, 10)
|
||||||
|
XCTAssertTrue(actionStack.isLayoutMarginsRelativeArrangement)
|
||||||
|
XCTAssertEqual(actionStack.directionalLayoutMargins.top, 9)
|
||||||
|
XCTAssertEqual(actionStack.arrangedSubviews, [aiRetouchButton, deleteButton, refreshButton])
|
||||||
|
XCTAssertEqual(aiRetouchButton.bounds.height, 52, accuracy: 0.5)
|
||||||
|
XCTAssertEqual(deleteButton.bounds.height, 52, accuracy: 0.5)
|
||||||
|
XCTAssertEqual(refreshButton.bounds.height, 52, accuracy: 0.5)
|
||||||
|
XCTAssertEqual(aiRetouchButton.configuration?.baseBackgroundColor?.travelAlbumTestHexRGB, 0x1677FF)
|
||||||
|
XCTAssertEqual(deleteButton.configuration?.baseForegroundColor?.travelAlbumTestHexRGB, 0xFF6B6B)
|
||||||
|
XCTAssertEqual(refreshButton.configuration?.baseBackgroundColor?.travelAlbumTestHexRGB, 0x1C1C1E)
|
||||||
|
XCTAssertEqual(aiRetouchButton.configuration?.imagePlacement, .leading)
|
||||||
XCTAssertEqual(collectionView.frame, controller.view.bounds)
|
XCTAssertEqual(collectionView.frame, controller.view.bounds)
|
||||||
XCTAssertLessThan(collectionView.frame.minY, topChrome.frame.maxY)
|
XCTAssertLessThan(collectionView.frame.minY, topChrome.frame.maxY)
|
||||||
XCTAssertGreaterThan(collectionView.frame.maxY, bottomChrome.frame.minY)
|
XCTAssertGreaterThan(collectionView.frame.maxY, bottomChrome.frame.minY)
|
||||||
|
|||||||
Reference in New Issue
Block a user